summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoel Sherrill <joel.sherrill@OARcorp.com>2011-04-08 17:36:40 +0000
committerJoel Sherrill <joel.sherrill@OARcorp.com>2011-04-08 17:36:40 +0000
commit124da02af7a348eed58d7e3580d5176421171070 (patch)
tree8f2b8978157de21be5434e9ec5b4b5f87c46ef21
parent2011-04-08 Joel Sherrill <joel.sherrill@oarcorp.com> (diff)
downloadrtems-addon-packages-124da02af7a348eed58d7e3580d5176421171070.tar.bz2
2011-04-08 Joel Sherrill <joel.sherrill@oarcorp.com>
* bit: Update to libtecl-1.6.1 * libtecla-1.6.1/CHANGES, libtecla-1.6.1/INSTALL, libtecla-1.6.1/LICENSE.TERMS, libtecla-1.6.1/Makefile, libtecla-1.6.1/Makefile.in, libtecla-1.6.1/Makefile.rules, libtecla-1.6.1/Makefile.stub, libtecla-1.6.1/PORTING, libtecla-1.6.1/README, libtecla-1.6.1/RELEASE.NOTES, libtecla-1.6.1/chrqueue.c, libtecla-1.6.1/chrqueue.h, libtecla-1.6.1/config.guess, libtecla-1.6.1/config.sub, libtecla-1.6.1/configure, libtecla-1.6.1/configure.in, libtecla-1.6.1/cplfile.c, libtecla-1.6.1/cplfile.h, libtecla-1.6.1/cplmatch.c, libtecla-1.6.1/cplmatch.h, libtecla-1.6.1/demo.c, libtecla-1.6.1/demo2.c, libtecla-1.6.1/demo3.c, libtecla-1.6.1/direader.c, libtecla-1.6.1/direader.h, libtecla-1.6.1/enhance.c, libtecla-1.6.1/errmsg.c, libtecla-1.6.1/errmsg.h, libtecla-1.6.1/expand.c, libtecla-1.6.1/expand.h, libtecla-1.6.1/freelist.c, libtecla-1.6.1/freelist.h, libtecla-1.6.1/getline.c, libtecla-1.6.1/getline.h, libtecla-1.6.1/hash.c, libtecla-1.6.1/hash.h, libtecla-1.6.1/history.c, libtecla-1.6.1/history.h, libtecla-1.6.1/homedir.c, libtecla-1.6.1/homedir.h, libtecla-1.6.1/install-sh, libtecla-1.6.1/ioutil.c, libtecla-1.6.1/ioutil.h, libtecla-1.6.1/keytab.c, libtecla-1.6.1/keytab.h, libtecla-1.6.1/libtecla.h, libtecla-1.6.1/libtecla.map, libtecla-1.6.1/pathutil.c, libtecla-1.6.1/pathutil.h, libtecla-1.6.1/pcache.c, libtecla-1.6.1/stringrp.c, libtecla-1.6.1/stringrp.h, libtecla-1.6.1/strngmem.c, libtecla-1.6.1/strngmem.h, libtecla-1.6.1/update_html, libtecla-1.6.1/update_version, libtecla-1.6.1/version.c, libtecla-1.6.1/html/changes.html, libtecla-1.6.1/html/cpl_complete_word.html, libtecla-1.6.1/html/ef_expand_file.html, libtecla-1.6.1/html/enhance.html, libtecla-1.6.1/html/gl_get_line.html, libtecla-1.6.1/html/gl_io_mode.html, libtecla-1.6.1/html/index.html, libtecla-1.6.1/html/libtecla.html, libtecla-1.6.1/html/pca_lookup_file.html, libtecla-1.6.1/html/release.html, libtecla-1.6.1/html/tecla.html, libtecla-1.6.1/man/file/teclarc.in, libtecla-1.6.1/man/func/cfc_file_start.in, libtecla-1.6.1/man/func/cfc_literal_escapes.in, libtecla-1.6.1/man/func/cfc_set_check_fn.in, libtecla-1.6.1/man/func/cpl_add_completion.in, libtecla-1.6.1/man/func/cpl_complete_word.in, libtecla-1.6.1/man/func/cpl_file_completions.in, libtecla-1.6.1/man/func/cpl_last_error.in, libtecla-1.6.1/man/func/cpl_list_completions.in, libtecla-1.6.1/man/func/cpl_recall_matches.in, libtecla-1.6.1/man/func/cpl_record_error.in, libtecla-1.6.1/man/func/del_CplFileConf.in, libtecla-1.6.1/man/func/del_ExpandFile.in, libtecla-1.6.1/man/func/del_GetLine.in, libtecla-1.6.1/man/func/del_PathCache.in, libtecla-1.6.1/man/func/del_PcaPathConf.in, libtecla-1.6.1/man/func/del_WordCompletion.in, libtecla-1.6.1/man/func/ef_expand_file.in, libtecla-1.6.1/man/func/ef_last_error.in, libtecla-1.6.1/man/func/ef_list_expansions.in, libtecla-1.6.1/man/func/gl_abandon_line.in, libtecla-1.6.1/man/func/gl_bind_keyseq.in, libtecla-1.6.1/man/func/gl_catch_blocked.in, libtecla-1.6.1/man/func/gl_change_terminal.in, libtecla-1.6.1/man/func/gl_clear_history.in, libtecla-1.6.1/man/func/gl_completion_action.in, libtecla-1.6.1/man/func/gl_configure_getline.in, libtecla-1.6.1/man/func/gl_customize_completion.in, libtecla-1.6.1/man/func/gl_display_text.in, libtecla-1.6.1/man/func/gl_echo_mode.in, libtecla-1.6.1/man/func/gl_erase_terminal.in, libtecla-1.6.1/man/func/gl_error_message.in, libtecla-1.6.1/man/func/gl_get_line.in, libtecla-1.6.1/man/func/gl_group_history.in, libtecla-1.6.1/man/func/gl_handle_signal.in, libtecla-1.6.1/man/func/gl_ignore_signal.in, libtecla-1.6.1/man/func/gl_inactivity_timeout.in, libtecla-1.6.1/man/func/gl_io_mode.in, libtecla-1.6.1/man/func/gl_last_signal.in, libtecla-1.6.1/man/func/gl_limit_history.in, libtecla-1.6.1/man/func/gl_list_signals.in, libtecla-1.6.1/man/func/gl_load_history.in, libtecla-1.6.1/man/func/gl_lookup_history.in, libtecla-1.6.1/man/func/gl_normal_io.in, libtecla-1.6.1/man/func/gl_pending_io.in, libtecla-1.6.1/man/func/gl_prompt_style.in, libtecla-1.6.1/man/func/gl_query_char.in, libtecla-1.6.1/man/func/gl_range_of_history.in, libtecla-1.6.1/man/func/gl_raw_io.in, libtecla-1.6.1/man/func/gl_read_char.in, libtecla-1.6.1/man/func/gl_register_action.in, libtecla-1.6.1/man/func/gl_resize_history.in, libtecla-1.6.1/man/func/gl_return_status.in, libtecla-1.6.1/man/func/gl_save_history.in, libtecla-1.6.1/man/func/gl_set_term_size.in, libtecla-1.6.1/man/func/gl_show_history.in, libtecla-1.6.1/man/func/gl_size_of_history.in, libtecla-1.6.1/man/func/gl_state_of_history.in, libtecla-1.6.1/man/func/gl_terminal_size.in, libtecla-1.6.1/man/func/gl_toggle_history.in, libtecla-1.6.1/man/func/gl_trap_signal.in, libtecla-1.6.1/man/func/gl_tty_signals.in, libtecla-1.6.1/man/func/gl_watch_fd.in, libtecla-1.6.1/man/func/libtecla_version.in, libtecla-1.6.1/man/func/new_CplFileConf.in, libtecla-1.6.1/man/func/new_ExpandFile.in, libtecla-1.6.1/man/func/new_GetLine.in, libtecla-1.6.1/man/func/new_PathCache.in, libtecla-1.6.1/man/func/new_PcaPathConf.in, libtecla-1.6.1/man/func/new_WordCompletion.in, libtecla-1.6.1/man/func/pca_last_error.in, libtecla-1.6.1/man/func/pca_lookup_file.in, libtecla-1.6.1/man/func/pca_path_completions.in, libtecla-1.6.1/man/func/pca_scan_path.in, libtecla-1.6.1/man/func/pca_set_check_fn.in, libtecla-1.6.1/man/func/ppc_file_start.in, libtecla-1.6.1/man/func/ppc_literal_escapes.in, libtecla-1.6.1/man/libr/libtecla.in, libtecla-1.6.1/man/misc/tecla.in, libtecla-1.6.1/man/prog/enhance.in: New files. * libtecla-1.4.1/CHANGES, libtecla-1.4.1/INSTALL, libtecla-1.4.1/LICENSE.TERMS, libtecla-1.4.1/Makefile, libtecla-1.4.1/Makefile.in, libtecla-1.4.1/Makefile.rules, libtecla-1.4.1/Makefile.stub, libtecla-1.4.1/PORTING, libtecla-1.4.1/README, libtecla-1.4.1/RELEASE.NOTES, libtecla-1.4.1/config.guess, libtecla-1.4.1/config.sub, libtecla-1.4.1/configure, libtecla-1.4.1/configure.in, libtecla-1.4.1/cplfile.c, libtecla-1.4.1/cplfile.h, libtecla-1.4.1/cplmatch.c, libtecla-1.4.1/demo.c, libtecla-1.4.1/demo2.c, libtecla-1.4.1/direader.c, libtecla-1.4.1/direader.h, libtecla-1.4.1/enhance.c, libtecla-1.4.1/expand.c, libtecla-1.4.1/freelist.c, libtecla-1.4.1/freelist.h, libtecla-1.4.1/getline.c, libtecla-1.4.1/getline.h, libtecla-1.4.1/hash.c, libtecla-1.4.1/hash.h, libtecla-1.4.1/history.c, libtecla-1.4.1/history.h, libtecla-1.4.1/homedir.c, libtecla-1.4.1/homedir.h, libtecla-1.4.1/install-sh, libtecla-1.4.1/keytab.c, libtecla-1.4.1/keytab.h, libtecla-1.4.1/libtecla.h, libtecla-1.4.1/libtecla.map, libtecla-1.4.1/pathutil.c, libtecla-1.4.1/pathutil.h, libtecla-1.4.1/pcache.c, libtecla-1.4.1/stringrp.c, libtecla-1.4.1/stringrp.h, libtecla-1.4.1/strngmem.c, libtecla-1.4.1/strngmem.h, libtecla-1.4.1/update_html, libtecla-1.4.1/update_version, libtecla-1.4.1/version.c, libtecla-1.4.1/html/changes.html, libtecla-1.4.1/html/cpl_complete_word.html, libtecla-1.4.1/html/ef_expand_file.html, libtecla-1.4.1/html/enhance.html, libtecla-1.4.1/html/gl_get_line.html, libtecla-1.4.1/html/index.html, libtecla-1.4.1/html/libtecla.html, libtecla-1.4.1/html/pca_lookup_file.html, libtecla-1.4.1/html/release.html, libtecla-1.4.1/man3/cfc_file_start.3, libtecla-1.4.1/man3/cfc_literal_escapes.3, libtecla-1.4.1/man3/cfc_set_check_fn.3, libtecla-1.4.1/man3/cpl_add_completion.3, libtecla-1.4.1/man3/cpl_complete_word.3, libtecla-1.4.1/man3/cpl_file_completions.3, libtecla-1.4.1/man3/cpl_last_error.3, libtecla-1.4.1/man3/cpl_list_completions.3, libtecla-1.4.1/man3/cpl_record_error.3, libtecla-1.4.1/man3/del_CplFileConf.3, libtecla-1.4.1/man3/del_ExpandFile.3, libtecla-1.4.1/man3/del_GetLine.3, libtecla-1.4.1/man3/del_PathCache.3, libtecla-1.4.1/man3/del_PcaPathConf.3, libtecla-1.4.1/man3/del_WordCompletion.3, libtecla-1.4.1/man3/ef_expand_file.3, libtecla-1.4.1/man3/ef_last_error.3, libtecla-1.4.1/man3/ef_list_expansions.3, libtecla-1.4.1/man3/enhance.3, libtecla-1.4.1/man3/gl_change_terminal.3, libtecla-1.4.1/man3/gl_clear_history.3, libtecla-1.4.1/man3/gl_configure_getline.3, libtecla-1.4.1/man3/gl_customize_completion.3, libtecla-1.4.1/man3/gl_echo_mode.3, libtecla-1.4.1/man3/gl_get_line.3, libtecla-1.4.1/man3/gl_group_history.3, libtecla-1.4.1/man3/gl_ignore_signal.3, libtecla-1.4.1/man3/gl_last_signal.3, libtecla-1.4.1/man3/gl_limit_history.3, libtecla-1.4.1/man3/gl_load_history.3, libtecla-1.4.1/man3/gl_lookup_history.3, libtecla-1.4.1/man3/gl_prompt_style.3, libtecla-1.4.1/man3/gl_range_of_history.3, libtecla-1.4.1/man3/gl_resize_history.3, libtecla-1.4.1/man3/gl_save_history.3, libtecla-1.4.1/man3/gl_show_history.3, libtecla-1.4.1/man3/gl_size_of_history.3, libtecla-1.4.1/man3/gl_state_of_history.3, libtecla-1.4.1/man3/gl_terminal_size.3, libtecla-1.4.1/man3/gl_toggle_history.3, libtecla-1.4.1/man3/gl_trap_signal.3, libtecla-1.4.1/man3/gl_watch_fd.3, libtecla-1.4.1/man3/libtecla.3, libtecla-1.4.1/man3/libtecla_version.3, libtecla-1.4.1/man3/new_CplFileConf.3, libtecla-1.4.1/man3/new_ExpandFile.3, libtecla-1.4.1/man3/new_GetLine.3, libtecla-1.4.1/man3/new_PathCache.3, libtecla-1.4.1/man3/new_PcaPathConf.3, libtecla-1.4.1/man3/new_WordCompletion.3, libtecla-1.4.1/man3/pca_last_error.3, libtecla-1.4.1/man3/pca_lookup_file.3, libtecla-1.4.1/man3/pca_path_completions.3, libtecla-1.4.1/man3/pca_scan_path.3, libtecla-1.4.1/man3/pca_set_check_fn.3, libtecla-1.4.1/man3/ppc_file_start.3, libtecla-1.4.1/man3/ppc_literal_escapes.3: Removed.
-rw-r--r--ChangeLog209
-rwxr-xr-xbit2
-rw-r--r--libtecla-1.4.1/Makefile3
-rw-r--r--libtecla-1.4.1/Makefile.stub3
-rwxr-xr-xlibtecla-1.4.1/configure1939
-rw-r--r--libtecla-1.4.1/history.c2003
-rw-r--r--libtecla-1.4.1/html/cpl_complete_word.html423
-rw-r--r--libtecla-1.4.1/html/ef_expand_file.html267
-rw-r--r--libtecla-1.4.1/html/enhance.html111
-rw-r--r--libtecla-1.4.1/html/gl_get_line.html2295
-rw-r--r--libtecla-1.4.1/html/libtecla.html163
-rw-r--r--libtecla-1.4.1/html/pca_lookup_file.html371
-rw-r--r--libtecla-1.4.1/man3/cfc_file_start.31
-rw-r--r--libtecla-1.4.1/man3/cfc_literal_escapes.31
-rw-r--r--libtecla-1.4.1/man3/cfc_set_check_fn.31
-rw-r--r--libtecla-1.4.1/man3/cpl_add_completion.31
-rw-r--r--libtecla-1.4.1/man3/cpl_file_completions.31
-rw-r--r--libtecla-1.4.1/man3/cpl_last_error.31
-rw-r--r--libtecla-1.4.1/man3/cpl_list_completions.31
-rw-r--r--libtecla-1.4.1/man3/cpl_record_error.31
-rw-r--r--libtecla-1.4.1/man3/del_CplFileConf.31
-rw-r--r--libtecla-1.4.1/man3/del_ExpandFile.31
-rw-r--r--libtecla-1.4.1/man3/del_GetLine.31
-rw-r--r--libtecla-1.4.1/man3/del_PathCache.31
-rw-r--r--libtecla-1.4.1/man3/del_PcaPathConf.31
-rw-r--r--libtecla-1.4.1/man3/del_WordCompletion.31
-rw-r--r--libtecla-1.4.1/man3/ef_last_error.31
-rw-r--r--libtecla-1.4.1/man3/ef_list_expansions.31
-rw-r--r--libtecla-1.4.1/man3/gl_change_terminal.31
-rw-r--r--libtecla-1.4.1/man3/gl_clear_history.31
-rw-r--r--libtecla-1.4.1/man3/gl_configure_getline.31
-rw-r--r--libtecla-1.4.1/man3/gl_customize_completion.31
-rw-r--r--libtecla-1.4.1/man3/gl_echo_mode.31
-rw-r--r--libtecla-1.4.1/man3/gl_get_line.32329
-rw-r--r--libtecla-1.4.1/man3/gl_group_history.31
-rw-r--r--libtecla-1.4.1/man3/gl_ignore_signal.31
-rw-r--r--libtecla-1.4.1/man3/gl_last_signal.31
-rw-r--r--libtecla-1.4.1/man3/gl_limit_history.31
-rw-r--r--libtecla-1.4.1/man3/gl_load_history.31
-rw-r--r--libtecla-1.4.1/man3/gl_lookup_history.31
-rw-r--r--libtecla-1.4.1/man3/gl_prompt_style.31
-rw-r--r--libtecla-1.4.1/man3/gl_range_of_history.31
-rw-r--r--libtecla-1.4.1/man3/gl_resize_history.31
-rw-r--r--libtecla-1.4.1/man3/gl_save_history.31
-rw-r--r--libtecla-1.4.1/man3/gl_show_history.31
-rw-r--r--libtecla-1.4.1/man3/gl_size_of_history.31
-rw-r--r--libtecla-1.4.1/man3/gl_state_of_history.31
-rw-r--r--libtecla-1.4.1/man3/gl_terminal_size.31
-rw-r--r--libtecla-1.4.1/man3/gl_toggle_history.31
-rw-r--r--libtecla-1.4.1/man3/gl_trap_signal.31
-rw-r--r--libtecla-1.4.1/man3/gl_watch_fd.31
-rw-r--r--libtecla-1.4.1/man3/libtecla_version.31
-rw-r--r--libtecla-1.4.1/man3/new_CplFileConf.31
-rw-r--r--libtecla-1.4.1/man3/new_ExpandFile.31
-rw-r--r--libtecla-1.4.1/man3/new_GetLine.31
-rw-r--r--libtecla-1.4.1/man3/new_PathCache.31
-rw-r--r--libtecla-1.4.1/man3/new_PcaPathConf.31
-rw-r--r--libtecla-1.4.1/man3/new_WordCompletion.31
-rw-r--r--libtecla-1.4.1/man3/pca_last_error.31
-rw-r--r--libtecla-1.4.1/man3/pca_path_completions.31
-rw-r--r--libtecla-1.4.1/man3/pca_scan_path.31
-rw-r--r--libtecla-1.4.1/man3/pca_set_check_fn.31
-rw-r--r--libtecla-1.4.1/man3/ppc_file_start.31
-rw-r--r--libtecla-1.4.1/man3/ppc_literal_escapes.31
-rwxr-xr-xlibtecla-1.4.1/update_html35
-rw-r--r--libtecla-1.6.1/CHANGES (renamed from libtecla-1.4.1/CHANGES)1266
-rw-r--r--libtecla-1.6.1/INSTALL (renamed from libtecla-1.4.1/INSTALL)85
-rw-r--r--libtecla-1.6.1/LICENSE.TERMS (renamed from libtecla-1.4.1/LICENSE.TERMS)2
-rw-r--r--libtecla-1.6.1/Makefile12
-rw-r--r--libtecla-1.6.1/Makefile.in (renamed from libtecla-1.4.1/Makefile.in)67
-rw-r--r--libtecla-1.6.1/Makefile.rules (renamed from libtecla-1.4.1/Makefile.rules)57
-rw-r--r--libtecla-1.6.1/Makefile.stub12
-rw-r--r--libtecla-1.6.1/PORTING (renamed from libtecla-1.4.1/PORTING)0
-rw-r--r--libtecla-1.6.1/README (renamed from libtecla-1.4.1/README)4
-rw-r--r--libtecla-1.6.1/RELEASE.NOTES (renamed from libtecla-1.4.1/RELEASE.NOTES)230
-rw-r--r--libtecla-1.6.1/chrqueue.c432
-rw-r--r--libtecla-1.6.1/chrqueue.h106
-rw-r--r--libtecla-1.6.1/config.guess (renamed from libtecla-1.4.1/config.guess)1069
-rw-r--r--libtecla-1.6.1/config.sub (renamed from libtecla-1.4.1/config.sub)532
-rwxr-xr-xlibtecla-1.6.1/configure5208
-rw-r--r--libtecla-1.6.1/configure.in (renamed from libtecla-1.4.1/configure.in)238
-rw-r--r--libtecla-1.6.1/cplfile.c (renamed from libtecla-1.4.1/cplfile.c)118
-rw-r--r--libtecla-1.6.1/cplfile.h (renamed from libtecla-1.4.1/cplfile.h)2
-rw-r--r--libtecla-1.6.1/cplmatch.c (renamed from libtecla-1.4.1/cplmatch.c)409
-rw-r--r--libtecla-1.6.1/cplmatch.h47
-rw-r--r--libtecla-1.6.1/demo.c (renamed from libtecla-1.4.1/demo.c)61
-rw-r--r--libtecla-1.6.1/demo2.c (renamed from libtecla-1.4.1/demo2.c)75
-rw-r--r--libtecla-1.6.1/demo3.c738
-rw-r--r--libtecla-1.6.1/direader.c (renamed from libtecla-1.4.1/direader.c)66
-rw-r--r--libtecla-1.6.1/direader.h (renamed from libtecla-1.4.1/direader.h)2
-rw-r--r--libtecla-1.6.1/enhance.c (renamed from libtecla-1.4.1/enhance.c)6
-rw-r--r--libtecla-1.6.1/errmsg.c167
-rw-r--r--libtecla-1.6.1/errmsg.h85
-rw-r--r--libtecla-1.6.1/expand.c (renamed from libtecla-1.4.1/expand.c)343
-rw-r--r--libtecla-1.6.1/expand.h48
-rw-r--r--libtecla-1.6.1/freelist.c (renamed from libtecla-1.4.1/freelist.c)49
-rw-r--r--libtecla-1.6.1/freelist.h (renamed from libtecla-1.4.1/freelist.h)15
-rw-r--r--libtecla-1.6.1/getline.c (renamed from libtecla-1.4.1/getline.c)6682
-rw-r--r--libtecla-1.6.1/getline.h (renamed from libtecla-1.4.1/getline.h)2
-rw-r--r--libtecla-1.6.1/hash.c (renamed from libtecla-1.4.1/hash.c)57
-rw-r--r--libtecla-1.6.1/hash.h (renamed from libtecla-1.4.1/hash.h)4
-rw-r--r--libtecla-1.6.1/history.c2842
-rw-r--r--libtecla-1.6.1/history.h (renamed from libtecla-1.4.1/history.h)18
-rw-r--r--libtecla-1.6.1/homedir.c (renamed from libtecla-1.4.1/homedir.c)153
-rw-r--r--libtecla-1.6.1/homedir.h (renamed from libtecla-1.4.1/homedir.h)4
-rw-r--r--libtecla-1.6.1/html/changes.html (renamed from libtecla-1.4.1/html/changes.html)1300
-rw-r--r--libtecla-1.6.1/html/cpl_complete_word.html382
-rw-r--r--libtecla-1.6.1/html/ef_expand_file.html213
-rw-r--r--libtecla-1.6.1/html/enhance.html75
-rw-r--r--libtecla-1.6.1/html/gl_get_line.html1996
-rw-r--r--libtecla-1.6.1/html/gl_io_mode.html509
-rw-r--r--libtecla-1.6.1/html/index.html (renamed from libtecla-1.4.1/html/index.html)38
-rw-r--r--libtecla-1.6.1/html/libtecla.html138
-rw-r--r--libtecla-1.6.1/html/pca_lookup_file.html312
-rw-r--r--libtecla-1.6.1/html/release.html (renamed from libtecla-1.4.1/html/release.html)236
-rw-r--r--libtecla-1.6.1/html/tecla.html1120
-rwxr-xr-xlibtecla-1.6.1/install-sh (renamed from libtecla-1.4.1/install-sh)0
-rw-r--r--libtecla-1.6.1/ioutil.c330
-rw-r--r--libtecla-1.6.1/ioutil.h73
-rw-r--r--libtecla-1.6.1/keytab.c (renamed from libtecla-1.4.1/keytab.c)351
-rw-r--r--libtecla-1.6.1/keytab.h (renamed from libtecla-1.4.1/keytab.h)87
-rw-r--r--libtecla-1.6.1/libtecla.h (renamed from libtecla-1.4.1/libtecla.h)662
-rw-r--r--libtecla-1.6.1/libtecla.map (renamed from libtecla-1.4.1/libtecla.map)31
-rw-r--r--libtecla-1.6.1/man/file/teclarc.in1
-rw-r--r--libtecla-1.6.1/man/func/cfc_file_start.in1
-rw-r--r--libtecla-1.6.1/man/func/cfc_literal_escapes.in1
-rw-r--r--libtecla-1.6.1/man/func/cfc_set_check_fn.in1
-rw-r--r--libtecla-1.6.1/man/func/cpl_add_completion.in1
-rw-r--r--libtecla-1.6.1/man/func/cpl_complete_word.in (renamed from libtecla-1.4.1/man3/cpl_complete_word.3)62
-rw-r--r--libtecla-1.6.1/man/func/cpl_file_completions.in1
-rw-r--r--libtecla-1.6.1/man/func/cpl_last_error.in1
-rw-r--r--libtecla-1.6.1/man/func/cpl_list_completions.in1
-rw-r--r--libtecla-1.6.1/man/func/cpl_recall_matches.in1
-rw-r--r--libtecla-1.6.1/man/func/cpl_record_error.in1
-rw-r--r--libtecla-1.6.1/man/func/del_CplFileConf.in1
-rw-r--r--libtecla-1.6.1/man/func/del_ExpandFile.in1
-rw-r--r--libtecla-1.6.1/man/func/del_GetLine.in1
-rw-r--r--libtecla-1.6.1/man/func/del_PathCache.in1
-rw-r--r--libtecla-1.6.1/man/func/del_PcaPathConf.in1
-rw-r--r--libtecla-1.6.1/man/func/del_WordCompletion.in1
-rw-r--r--libtecla-1.6.1/man/func/ef_expand_file.in (renamed from libtecla-1.4.1/man3/ef_expand_file.3)13
-rw-r--r--libtecla-1.6.1/man/func/ef_last_error.in1
-rw-r--r--libtecla-1.6.1/man/func/ef_list_expansions.in1
-rw-r--r--libtecla-1.6.1/man/func/gl_abandon_line.in1
-rw-r--r--libtecla-1.6.1/man/func/gl_bind_keyseq.in1
-rw-r--r--libtecla-1.6.1/man/func/gl_catch_blocked.in1
-rw-r--r--libtecla-1.6.1/man/func/gl_change_terminal.in1
-rw-r--r--libtecla-1.6.1/man/func/gl_clear_history.in1
-rw-r--r--libtecla-1.6.1/man/func/gl_completion_action.in1
-rw-r--r--libtecla-1.6.1/man/func/gl_configure_getline.in1
-rw-r--r--libtecla-1.6.1/man/func/gl_customize_completion.in1
-rw-r--r--libtecla-1.6.1/man/func/gl_display_text.in1
-rw-r--r--libtecla-1.6.1/man/func/gl_echo_mode.in1
-rw-r--r--libtecla-1.6.1/man/func/gl_erase_terminal.in1
-rw-r--r--libtecla-1.6.1/man/func/gl_error_message.in1
-rw-r--r--libtecla-1.6.1/man/func/gl_get_line.in2236
-rw-r--r--libtecla-1.6.1/man/func/gl_group_history.in1
-rw-r--r--libtecla-1.6.1/man/func/gl_handle_signal.in1
-rw-r--r--libtecla-1.6.1/man/func/gl_ignore_signal.in1
-rw-r--r--libtecla-1.6.1/man/func/gl_inactivity_timeout.in1
-rw-r--r--libtecla-1.6.1/man/func/gl_io_mode.in571
-rw-r--r--libtecla-1.6.1/man/func/gl_last_signal.in1
-rw-r--r--libtecla-1.6.1/man/func/gl_limit_history.in1
-rw-r--r--libtecla-1.6.1/man/func/gl_list_signals.in1
-rw-r--r--libtecla-1.6.1/man/func/gl_load_history.in1
-rw-r--r--libtecla-1.6.1/man/func/gl_lookup_history.in1
-rw-r--r--libtecla-1.6.1/man/func/gl_normal_io.in1
-rw-r--r--libtecla-1.6.1/man/func/gl_pending_io.in1
-rw-r--r--libtecla-1.6.1/man/func/gl_prompt_style.in1
-rw-r--r--libtecla-1.6.1/man/func/gl_query_char.in1
-rw-r--r--libtecla-1.6.1/man/func/gl_range_of_history.in1
-rw-r--r--libtecla-1.6.1/man/func/gl_raw_io.in1
-rw-r--r--libtecla-1.6.1/man/func/gl_read_char.in1
-rw-r--r--libtecla-1.6.1/man/func/gl_register_action.in1
-rw-r--r--libtecla-1.6.1/man/func/gl_resize_history.in1
-rw-r--r--libtecla-1.6.1/man/func/gl_return_status.in1
-rw-r--r--libtecla-1.6.1/man/func/gl_save_history.in1
-rw-r--r--libtecla-1.6.1/man/func/gl_set_term_size.in1
-rw-r--r--libtecla-1.6.1/man/func/gl_show_history.in1
-rw-r--r--libtecla-1.6.1/man/func/gl_size_of_history.in1
-rw-r--r--libtecla-1.6.1/man/func/gl_state_of_history.in1
-rw-r--r--libtecla-1.6.1/man/func/gl_terminal_size.in1
-rw-r--r--libtecla-1.6.1/man/func/gl_toggle_history.in1
-rw-r--r--libtecla-1.6.1/man/func/gl_trap_signal.in1
-rw-r--r--libtecla-1.6.1/man/func/gl_tty_signals.in1
-rw-r--r--libtecla-1.6.1/man/func/gl_watch_fd.in1
-rw-r--r--libtecla-1.6.1/man/func/libtecla_version.in1
-rw-r--r--libtecla-1.6.1/man/func/new_CplFileConf.in1
-rw-r--r--libtecla-1.6.1/man/func/new_ExpandFile.in1
-rw-r--r--libtecla-1.6.1/man/func/new_GetLine.in1
-rw-r--r--libtecla-1.6.1/man/func/new_PathCache.in1
-rw-r--r--libtecla-1.6.1/man/func/new_PcaPathConf.in1
-rw-r--r--libtecla-1.6.1/man/func/new_WordCompletion.in1
-rw-r--r--libtecla-1.6.1/man/func/pca_last_error.in1
-rw-r--r--libtecla-1.6.1/man/func/pca_lookup_file.in (renamed from libtecla-1.4.1/man3/pca_lookup_file.3)16
-rw-r--r--libtecla-1.6.1/man/func/pca_path_completions.in1
-rw-r--r--libtecla-1.6.1/man/func/pca_scan_path.in1
-rw-r--r--libtecla-1.6.1/man/func/pca_set_check_fn.in1
-rw-r--r--libtecla-1.6.1/man/func/ppc_file_start.in1
-rw-r--r--libtecla-1.6.1/man/func/ppc_literal_escapes.in1
-rw-r--r--libtecla-1.6.1/man/libr/libtecla.in (renamed from libtecla-1.4.1/man3/libtecla.3)32
-rw-r--r--libtecla-1.6.1/man/misc/tecla.in1201
-rw-r--r--libtecla-1.6.1/man/prog/enhance.in (renamed from libtecla-1.4.1/man3/enhance.3)9
-rw-r--r--libtecla-1.6.1/pathutil.c (renamed from libtecla-1.4.1/pathutil.c)33
-rw-r--r--libtecla-1.6.1/pathutil.h (renamed from libtecla-1.4.1/pathutil.h)2
-rw-r--r--libtecla-1.6.1/pcache.c (renamed from libtecla-1.4.1/pcache.c)98
-rw-r--r--libtecla-1.6.1/stringrp.c (renamed from libtecla-1.4.1/stringrp.c)15
-rw-r--r--libtecla-1.6.1/stringrp.h (renamed from libtecla-1.4.1/stringrp.h)2
-rw-r--r--libtecla-1.6.1/strngmem.c (renamed from libtecla-1.4.1/strngmem.c)28
-rw-r--r--libtecla-1.6.1/strngmem.h (renamed from libtecla-1.4.1/strngmem.h)6
-rwxr-xr-xlibtecla-1.6.1/update_html37
-rwxr-xr-xlibtecla-1.6.1/update_version (renamed from libtecla-1.4.1/update_version)0
-rw-r--r--libtecla-1.6.1/version.c (renamed from libtecla-1.4.1/version.c)0
213 files changed, 31418 insertions, 12385 deletions
diff --git a/ChangeLog b/ChangeLog
index b88cd6a..8516227 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,214 @@
2011-04-08 Joel Sherrill <joel.sherrill@oarcorp.com>
+ * bit: Update to libtecl-1.6.1
+ * libtecla-1.6.1/CHANGES, libtecla-1.6.1/INSTALL,
+ libtecla-1.6.1/LICENSE.TERMS, libtecla-1.6.1/Makefile,
+ libtecla-1.6.1/Makefile.in, libtecla-1.6.1/Makefile.rules,
+ libtecla-1.6.1/Makefile.stub, libtecla-1.6.1/PORTING,
+ libtecla-1.6.1/README, libtecla-1.6.1/RELEASE.NOTES,
+ libtecla-1.6.1/chrqueue.c, libtecla-1.6.1/chrqueue.h,
+ libtecla-1.6.1/config.guess, libtecla-1.6.1/config.sub,
+ libtecla-1.6.1/configure, libtecla-1.6.1/configure.in,
+ libtecla-1.6.1/cplfile.c, libtecla-1.6.1/cplfile.h,
+ libtecla-1.6.1/cplmatch.c, libtecla-1.6.1/cplmatch.h,
+ libtecla-1.6.1/demo.c, libtecla-1.6.1/demo2.c,
+ libtecla-1.6.1/demo3.c, libtecla-1.6.1/direader.c,
+ libtecla-1.6.1/direader.h, libtecla-1.6.1/enhance.c,
+ libtecla-1.6.1/errmsg.c, libtecla-1.6.1/errmsg.h,
+ libtecla-1.6.1/expand.c, libtecla-1.6.1/expand.h,
+ libtecla-1.6.1/freelist.c, libtecla-1.6.1/freelist.h,
+ libtecla-1.6.1/getline.c, libtecla-1.6.1/getline.h,
+ libtecla-1.6.1/hash.c, libtecla-1.6.1/hash.h,
+ libtecla-1.6.1/history.c, libtecla-1.6.1/history.h,
+ libtecla-1.6.1/homedir.c, libtecla-1.6.1/homedir.h,
+ libtecla-1.6.1/install-sh, libtecla-1.6.1/ioutil.c,
+ libtecla-1.6.1/ioutil.h, libtecla-1.6.1/keytab.c,
+ libtecla-1.6.1/keytab.h, libtecla-1.6.1/libtecla.h,
+ libtecla-1.6.1/libtecla.map, libtecla-1.6.1/pathutil.c,
+ libtecla-1.6.1/pathutil.h, libtecla-1.6.1/pcache.c,
+ libtecla-1.6.1/stringrp.c, libtecla-1.6.1/stringrp.h,
+ libtecla-1.6.1/strngmem.c, libtecla-1.6.1/strngmem.h,
+ libtecla-1.6.1/update_html, libtecla-1.6.1/update_version,
+ libtecla-1.6.1/version.c, libtecla-1.6.1/html/changes.html,
+ libtecla-1.6.1/html/cpl_complete_word.html,
+ libtecla-1.6.1/html/ef_expand_file.html,
+ libtecla-1.6.1/html/enhance.html,
+ libtecla-1.6.1/html/gl_get_line.html,
+ libtecla-1.6.1/html/gl_io_mode.html, libtecla-1.6.1/html/index.html,
+ libtecla-1.6.1/html/libtecla.html,
+ libtecla-1.6.1/html/pca_lookup_file.html,
+ libtecla-1.6.1/html/release.html, libtecla-1.6.1/html/tecla.html,
+ libtecla-1.6.1/man/file/teclarc.in,
+ libtecla-1.6.1/man/func/cfc_file_start.in,
+ libtecla-1.6.1/man/func/cfc_literal_escapes.in,
+ libtecla-1.6.1/man/func/cfc_set_check_fn.in,
+ libtecla-1.6.1/man/func/cpl_add_completion.in,
+ libtecla-1.6.1/man/func/cpl_complete_word.in,
+ libtecla-1.6.1/man/func/cpl_file_completions.in,
+ libtecla-1.6.1/man/func/cpl_last_error.in,
+ libtecla-1.6.1/man/func/cpl_list_completions.in,
+ libtecla-1.6.1/man/func/cpl_recall_matches.in,
+ libtecla-1.6.1/man/func/cpl_record_error.in,
+ libtecla-1.6.1/man/func/del_CplFileConf.in,
+ libtecla-1.6.1/man/func/del_ExpandFile.in,
+ libtecla-1.6.1/man/func/del_GetLine.in,
+ libtecla-1.6.1/man/func/del_PathCache.in,
+ libtecla-1.6.1/man/func/del_PcaPathConf.in,
+ libtecla-1.6.1/man/func/del_WordCompletion.in,
+ libtecla-1.6.1/man/func/ef_expand_file.in,
+ libtecla-1.6.1/man/func/ef_last_error.in,
+ libtecla-1.6.1/man/func/ef_list_expansions.in,
+ libtecla-1.6.1/man/func/gl_abandon_line.in,
+ libtecla-1.6.1/man/func/gl_bind_keyseq.in,
+ libtecla-1.6.1/man/func/gl_catch_blocked.in,
+ libtecla-1.6.1/man/func/gl_change_terminal.in,
+ libtecla-1.6.1/man/func/gl_clear_history.in,
+ libtecla-1.6.1/man/func/gl_completion_action.in,
+ libtecla-1.6.1/man/func/gl_configure_getline.in,
+ libtecla-1.6.1/man/func/gl_customize_completion.in,
+ libtecla-1.6.1/man/func/gl_display_text.in,
+ libtecla-1.6.1/man/func/gl_echo_mode.in,
+ libtecla-1.6.1/man/func/gl_erase_terminal.in,
+ libtecla-1.6.1/man/func/gl_error_message.in,
+ libtecla-1.6.1/man/func/gl_get_line.in,
+ libtecla-1.6.1/man/func/gl_group_history.in,
+ libtecla-1.6.1/man/func/gl_handle_signal.in,
+ libtecla-1.6.1/man/func/gl_ignore_signal.in,
+ libtecla-1.6.1/man/func/gl_inactivity_timeout.in,
+ libtecla-1.6.1/man/func/gl_io_mode.in,
+ libtecla-1.6.1/man/func/gl_last_signal.in,
+ libtecla-1.6.1/man/func/gl_limit_history.in,
+ libtecla-1.6.1/man/func/gl_list_signals.in,
+ libtecla-1.6.1/man/func/gl_load_history.in,
+ libtecla-1.6.1/man/func/gl_lookup_history.in,
+ libtecla-1.6.1/man/func/gl_normal_io.in,
+ libtecla-1.6.1/man/func/gl_pending_io.in,
+ libtecla-1.6.1/man/func/gl_prompt_style.in,
+ libtecla-1.6.1/man/func/gl_query_char.in,
+ libtecla-1.6.1/man/func/gl_range_of_history.in,
+ libtecla-1.6.1/man/func/gl_raw_io.in,
+ libtecla-1.6.1/man/func/gl_read_char.in,
+ libtecla-1.6.1/man/func/gl_register_action.in,
+ libtecla-1.6.1/man/func/gl_resize_history.in,
+ libtecla-1.6.1/man/func/gl_return_status.in,
+ libtecla-1.6.1/man/func/gl_save_history.in,
+ libtecla-1.6.1/man/func/gl_set_term_size.in,
+ libtecla-1.6.1/man/func/gl_show_history.in,
+ libtecla-1.6.1/man/func/gl_size_of_history.in,
+ libtecla-1.6.1/man/func/gl_state_of_history.in,
+ libtecla-1.6.1/man/func/gl_terminal_size.in,
+ libtecla-1.6.1/man/func/gl_toggle_history.in,
+ libtecla-1.6.1/man/func/gl_trap_signal.in,
+ libtecla-1.6.1/man/func/gl_tty_signals.in,
+ libtecla-1.6.1/man/func/gl_watch_fd.in,
+ libtecla-1.6.1/man/func/libtecla_version.in,
+ libtecla-1.6.1/man/func/new_CplFileConf.in,
+ libtecla-1.6.1/man/func/new_ExpandFile.in,
+ libtecla-1.6.1/man/func/new_GetLine.in,
+ libtecla-1.6.1/man/func/new_PathCache.in,
+ libtecla-1.6.1/man/func/new_PcaPathConf.in,
+ libtecla-1.6.1/man/func/new_WordCompletion.in,
+ libtecla-1.6.1/man/func/pca_last_error.in,
+ libtecla-1.6.1/man/func/pca_lookup_file.in,
+ libtecla-1.6.1/man/func/pca_path_completions.in,
+ libtecla-1.6.1/man/func/pca_scan_path.in,
+ libtecla-1.6.1/man/func/pca_set_check_fn.in,
+ libtecla-1.6.1/man/func/ppc_file_start.in,
+ libtecla-1.6.1/man/func/ppc_literal_escapes.in,
+ libtecla-1.6.1/man/libr/libtecla.in,
+ libtecla-1.6.1/man/misc/tecla.in, libtecla-1.6.1/man/prog/enhance.in:
+ New files.
+ * libtecla-1.4.1/CHANGES, libtecla-1.4.1/INSTALL,
+ libtecla-1.4.1/LICENSE.TERMS, libtecla-1.4.1/Makefile,
+ libtecla-1.4.1/Makefile.in, libtecla-1.4.1/Makefile.rules,
+ libtecla-1.4.1/Makefile.stub, libtecla-1.4.1/PORTING,
+ libtecla-1.4.1/README, libtecla-1.4.1/RELEASE.NOTES,
+ libtecla-1.4.1/config.guess, libtecla-1.4.1/config.sub,
+ libtecla-1.4.1/configure, libtecla-1.4.1/configure.in,
+ libtecla-1.4.1/cplfile.c, libtecla-1.4.1/cplfile.h,
+ libtecla-1.4.1/cplmatch.c, libtecla-1.4.1/demo.c,
+ libtecla-1.4.1/demo2.c, libtecla-1.4.1/direader.c,
+ libtecla-1.4.1/direader.h, libtecla-1.4.1/enhance.c,
+ libtecla-1.4.1/expand.c, libtecla-1.4.1/freelist.c,
+ libtecla-1.4.1/freelist.h, libtecla-1.4.1/getline.c,
+ libtecla-1.4.1/getline.h, libtecla-1.4.1/hash.c,
+ libtecla-1.4.1/hash.h, libtecla-1.4.1/history.c,
+ libtecla-1.4.1/history.h, libtecla-1.4.1/homedir.c,
+ libtecla-1.4.1/homedir.h, libtecla-1.4.1/install-sh,
+ libtecla-1.4.1/keytab.c, libtecla-1.4.1/keytab.h,
+ libtecla-1.4.1/libtecla.h, libtecla-1.4.1/libtecla.map,
+ libtecla-1.4.1/pathutil.c, libtecla-1.4.1/pathutil.h,
+ libtecla-1.4.1/pcache.c, libtecla-1.4.1/stringrp.c,
+ libtecla-1.4.1/stringrp.h, libtecla-1.4.1/strngmem.c,
+ libtecla-1.4.1/strngmem.h, libtecla-1.4.1/update_html,
+ libtecla-1.4.1/update_version, libtecla-1.4.1/version.c,
+ libtecla-1.4.1/html/changes.html,
+ libtecla-1.4.1/html/cpl_complete_word.html,
+ libtecla-1.4.1/html/ef_expand_file.html,
+ libtecla-1.4.1/html/enhance.html,
+ libtecla-1.4.1/html/gl_get_line.html, libtecla-1.4.1/html/index.html,
+ libtecla-1.4.1/html/libtecla.html,
+ libtecla-1.4.1/html/pca_lookup_file.html,
+ libtecla-1.4.1/html/release.html,
+ libtecla-1.4.1/man3/cfc_file_start.3,
+ libtecla-1.4.1/man3/cfc_literal_escapes.3,
+ libtecla-1.4.1/man3/cfc_set_check_fn.3,
+ libtecla-1.4.1/man3/cpl_add_completion.3,
+ libtecla-1.4.1/man3/cpl_complete_word.3,
+ libtecla-1.4.1/man3/cpl_file_completions.3,
+ libtecla-1.4.1/man3/cpl_last_error.3,
+ libtecla-1.4.1/man3/cpl_list_completions.3,
+ libtecla-1.4.1/man3/cpl_record_error.3,
+ libtecla-1.4.1/man3/del_CplFileConf.3,
+ libtecla-1.4.1/man3/del_ExpandFile.3,
+ libtecla-1.4.1/man3/del_GetLine.3,
+ libtecla-1.4.1/man3/del_PathCache.3,
+ libtecla-1.4.1/man3/del_PcaPathConf.3,
+ libtecla-1.4.1/man3/del_WordCompletion.3,
+ libtecla-1.4.1/man3/ef_expand_file.3,
+ libtecla-1.4.1/man3/ef_last_error.3,
+ libtecla-1.4.1/man3/ef_list_expansions.3,
+ libtecla-1.4.1/man3/enhance.3,
+ libtecla-1.4.1/man3/gl_change_terminal.3,
+ libtecla-1.4.1/man3/gl_clear_history.3,
+ libtecla-1.4.1/man3/gl_configure_getline.3,
+ libtecla-1.4.1/man3/gl_customize_completion.3,
+ libtecla-1.4.1/man3/gl_echo_mode.3,
+ libtecla-1.4.1/man3/gl_get_line.3,
+ libtecla-1.4.1/man3/gl_group_history.3,
+ libtecla-1.4.1/man3/gl_ignore_signal.3,
+ libtecla-1.4.1/man3/gl_last_signal.3,
+ libtecla-1.4.1/man3/gl_limit_history.3,
+ libtecla-1.4.1/man3/gl_load_history.3,
+ libtecla-1.4.1/man3/gl_lookup_history.3,
+ libtecla-1.4.1/man3/gl_prompt_style.3,
+ libtecla-1.4.1/man3/gl_range_of_history.3,
+ libtecla-1.4.1/man3/gl_resize_history.3,
+ libtecla-1.4.1/man3/gl_save_history.3,
+ libtecla-1.4.1/man3/gl_show_history.3,
+ libtecla-1.4.1/man3/gl_size_of_history.3,
+ libtecla-1.4.1/man3/gl_state_of_history.3,
+ libtecla-1.4.1/man3/gl_terminal_size.3,
+ libtecla-1.4.1/man3/gl_toggle_history.3,
+ libtecla-1.4.1/man3/gl_trap_signal.3,
+ libtecla-1.4.1/man3/gl_watch_fd.3, libtecla-1.4.1/man3/libtecla.3,
+ libtecla-1.4.1/man3/libtecla_version.3,
+ libtecla-1.4.1/man3/new_CplFileConf.3,
+ libtecla-1.4.1/man3/new_ExpandFile.3,
+ libtecla-1.4.1/man3/new_GetLine.3,
+ libtecla-1.4.1/man3/new_PathCache.3,
+ libtecla-1.4.1/man3/new_PcaPathConf.3,
+ libtecla-1.4.1/man3/new_WordCompletion.3,
+ libtecla-1.4.1/man3/pca_last_error.3,
+ libtecla-1.4.1/man3/pca_lookup_file.3,
+ libtecla-1.4.1/man3/pca_path_completions.3,
+ libtecla-1.4.1/man3/pca_scan_path.3,
+ libtecla-1.4.1/man3/pca_set_check_fn.3,
+ libtecla-1.4.1/man3/ppc_file_start.3,
+ libtecla-1.4.1/man3/ppc_literal_escapes.3: Removed.
+
+2011-04-08 Joel Sherrill <joel.sherrill@oarcorp.com>
+
* RTEMS_Makefiles/Makefile.gsl: New file.
2011-04-08 Joel Sherrill <joel.sherrill@oarcorp.com>
diff --git a/bit b/bit
index b5b17aa..2fbdd9c 100755
--- a/bit
+++ b/bit
@@ -9,7 +9,7 @@
#
set -ex
-PACKAGES="avl-1.4.0 ncurses-5.9 readline-4.3 libtecla-1.4.1"
+PACKAGES="avl-1.4.0 gsl-1.9 ncurses-5.9 readline-6.2 libtecla-1.6.1"
# make sure it is clean before we start
for p in $PACKAGES
diff --git a/libtecla-1.4.1/Makefile b/libtecla-1.4.1/Makefile
deleted file mode 100644
index 15116b5..0000000
--- a/libtecla-1.4.1/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-default:
- ./configure
- make
diff --git a/libtecla-1.4.1/Makefile.stub b/libtecla-1.4.1/Makefile.stub
deleted file mode 100644
index 15116b5..0000000
--- a/libtecla-1.4.1/Makefile.stub
+++ /dev/null
@@ -1,3 +0,0 @@
-default:
- ./configure
- make
diff --git a/libtecla-1.4.1/configure b/libtecla-1.4.1/configure
deleted file mode 100755
index feaa587..0000000
--- a/libtecla-1.4.1/configure
+++ /dev/null
@@ -1,1939 +0,0 @@
-#! /bin/sh
-
-# Guess values for system-dependent variables and create Makefiles.
-# Generated automatically using autoconf version 2.13
-# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
-#
-# This configure script is free software; the Free Software Foundation
-# gives unlimited permission to copy, distribute and modify it.
-
-# Defaults:
-ac_help=
-ac_default_prefix=/usr/local
-# Any additions from configure.in:
-
-# Initialize some variables set by options.
-# The variables have the same names as the options, with
-# dashes changed to underlines.
-build=NONE
-cache_file=./config.cache
-exec_prefix=NONE
-host=NONE
-no_create=
-nonopt=NONE
-no_recursion=
-prefix=NONE
-program_prefix=NONE
-program_suffix=NONE
-program_transform_name=s,x,x,
-silent=
-site=
-srcdir=
-target=NONE
-verbose=
-x_includes=NONE
-x_libraries=NONE
-bindir='${exec_prefix}/bin'
-sbindir='${exec_prefix}/sbin'
-libexecdir='${exec_prefix}/libexec'
-datadir='${prefix}/share'
-sysconfdir='${prefix}/etc'
-sharedstatedir='${prefix}/com'
-localstatedir='${prefix}/var'
-libdir='${exec_prefix}/lib'
-includedir='${prefix}/include'
-oldincludedir='/usr/include'
-infodir='${prefix}/info'
-mandir='${prefix}/man'
-
-# Initialize some other variables.
-subdirs=
-MFLAGS= MAKEFLAGS=
-SHELL=${CONFIG_SHELL-/bin/sh}
-# Maximum number of lines to put in a shell here document.
-ac_max_here_lines=12
-
-ac_prev=
-for ac_option
-do
-
- # If the previous option needs an argument, assign it.
- if test -n "$ac_prev"; then
- eval "$ac_prev=\$ac_option"
- ac_prev=
- continue
- fi
-
- case "$ac_option" in
- -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
- *) ac_optarg= ;;
- esac
-
- # Accept the important Cygnus configure options, so we can diagnose typos.
-
- case "$ac_option" in
-
- -bindir | --bindir | --bindi | --bind | --bin | --bi)
- ac_prev=bindir ;;
- -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
- bindir="$ac_optarg" ;;
-
- -build | --build | --buil | --bui | --bu)
- ac_prev=build ;;
- -build=* | --build=* | --buil=* | --bui=* | --bu=*)
- build="$ac_optarg" ;;
-
- -cache-file | --cache-file | --cache-fil | --cache-fi \
- | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
- ac_prev=cache_file ;;
- -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
- | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
- cache_file="$ac_optarg" ;;
-
- -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
- ac_prev=datadir ;;
- -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
- | --da=*)
- datadir="$ac_optarg" ;;
-
- -disable-* | --disable-*)
- ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
- # Reject names that are not valid shell variable names.
- if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
- { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
- fi
- ac_feature=`echo $ac_feature| sed 's/-/_/g'`
- eval "enable_${ac_feature}=no" ;;
-
- -enable-* | --enable-*)
- ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
- # Reject names that are not valid shell variable names.
- if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
- { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
- fi
- ac_feature=`echo $ac_feature| sed 's/-/_/g'`
- case "$ac_option" in
- *=*) ;;
- *) ac_optarg=yes ;;
- esac
- eval "enable_${ac_feature}='$ac_optarg'" ;;
-
- -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
- | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
- | --exec | --exe | --ex)
- ac_prev=exec_prefix ;;
- -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
- | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
- | --exec=* | --exe=* | --ex=*)
- exec_prefix="$ac_optarg" ;;
-
- -gas | --gas | --ga | --g)
- # Obsolete; use --with-gas.
- with_gas=yes ;;
-
- -help | --help | --hel | --he)
- # Omit some internal or obsolete options to make the list less imposing.
- # This message is too long to be a string in the A/UX 3.1 sh.
- cat << EOF
-Usage: configure [options] [host]
-Options: [defaults in brackets after descriptions]
-Configuration:
- --cache-file=FILE cache test results in FILE
- --help print this message
- --no-create do not create output files
- --quiet, --silent do not print \`checking...' messages
- --version print the version of autoconf that created configure
-Directory and file names:
- --prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
- --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [same as prefix]
- --bindir=DIR user executables in DIR [EPREFIX/bin]
- --sbindir=DIR system admin executables in DIR [EPREFIX/sbin]
- --libexecdir=DIR program executables in DIR [EPREFIX/libexec]
- --datadir=DIR read-only architecture-independent data in DIR
- [PREFIX/share]
- --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc]
- --sharedstatedir=DIR modifiable architecture-independent data in DIR
- [PREFIX/com]
- --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var]
- --libdir=DIR object code libraries in DIR [EPREFIX/lib]
- --includedir=DIR C header files in DIR [PREFIX/include]
- --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include]
- --infodir=DIR info documentation in DIR [PREFIX/info]
- --mandir=DIR man documentation in DIR [PREFIX/man]
- --srcdir=DIR find the sources in DIR [configure dir or ..]
- --program-prefix=PREFIX prepend PREFIX to installed program names
- --program-suffix=SUFFIX append SUFFIX to installed program names
- --program-transform-name=PROGRAM
- run sed PROGRAM on installed program names
-EOF
- cat << EOF
-Host type:
- --build=BUILD configure for building on BUILD [BUILD=HOST]
- --host=HOST configure for HOST [guessed]
- --target=TARGET configure for TARGET [TARGET=HOST]
-Features and packages:
- --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
- --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
- --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
- --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
- --x-includes=DIR X include files are in DIR
- --x-libraries=DIR X library files are in DIR
-EOF
- if test -n "$ac_help"; then
- echo "--enable and --with options recognized:$ac_help"
- fi
- exit 0 ;;
-
- -host | --host | --hos | --ho)
- ac_prev=host ;;
- -host=* | --host=* | --hos=* | --ho=*)
- host="$ac_optarg" ;;
-
- -includedir | --includedir | --includedi | --included | --include \
- | --includ | --inclu | --incl | --inc)
- ac_prev=includedir ;;
- -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
- | --includ=* | --inclu=* | --incl=* | --inc=*)
- includedir="$ac_optarg" ;;
-
- -infodir | --infodir | --infodi | --infod | --info | --inf)
- ac_prev=infodir ;;
- -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
- infodir="$ac_optarg" ;;
-
- -libdir | --libdir | --libdi | --libd)
- ac_prev=libdir ;;
- -libdir=* | --libdir=* | --libdi=* | --libd=*)
- libdir="$ac_optarg" ;;
-
- -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
- | --libexe | --libex | --libe)
- ac_prev=libexecdir ;;
- -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
- | --libexe=* | --libex=* | --libe=*)
- libexecdir="$ac_optarg" ;;
-
- -localstatedir | --localstatedir | --localstatedi | --localstated \
- | --localstate | --localstat | --localsta | --localst \
- | --locals | --local | --loca | --loc | --lo)
- ac_prev=localstatedir ;;
- -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
- | --localstate=* | --localstat=* | --localsta=* | --localst=* \
- | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
- localstatedir="$ac_optarg" ;;
-
- -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
- ac_prev=mandir ;;
- -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
- mandir="$ac_optarg" ;;
-
- -nfp | --nfp | --nf)
- # Obsolete; use --without-fp.
- with_fp=no ;;
-
- -no-create | --no-create | --no-creat | --no-crea | --no-cre \
- | --no-cr | --no-c)
- no_create=yes ;;
-
- -no-recursion | --no-recursion | --no-recursio | --no-recursi \
- | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
- no_recursion=yes ;;
-
- -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
- | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
- | --oldin | --oldi | --old | --ol | --o)
- ac_prev=oldincludedir ;;
- -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
- | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
- | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
- oldincludedir="$ac_optarg" ;;
-
- -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
- ac_prev=prefix ;;
- -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
- prefix="$ac_optarg" ;;
-
- -program-prefix | --program-prefix | --program-prefi | --program-pref \
- | --program-pre | --program-pr | --program-p)
- ac_prev=program_prefix ;;
- -program-prefix=* | --program-prefix=* | --program-prefi=* \
- | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
- program_prefix="$ac_optarg" ;;
-
- -program-suffix | --program-suffix | --program-suffi | --program-suff \
- | --program-suf | --program-su | --program-s)
- ac_prev=program_suffix ;;
- -program-suffix=* | --program-suffix=* | --program-suffi=* \
- | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
- program_suffix="$ac_optarg" ;;
-
- -program-transform-name | --program-transform-name \
- | --program-transform-nam | --program-transform-na \
- | --program-transform-n | --program-transform- \
- | --program-transform | --program-transfor \
- | --program-transfo | --program-transf \
- | --program-trans | --program-tran \
- | --progr-tra | --program-tr | --program-t)
- ac_prev=program_transform_name ;;
- -program-transform-name=* | --program-transform-name=* \
- | --program-transform-nam=* | --program-transform-na=* \
- | --program-transform-n=* | --program-transform-=* \
- | --program-transform=* | --program-transfor=* \
- | --program-transfo=* | --program-transf=* \
- | --program-trans=* | --program-tran=* \
- | --progr-tra=* | --program-tr=* | --program-t=*)
- program_transform_name="$ac_optarg" ;;
-
- -q | -quiet | --quiet | --quie | --qui | --qu | --q \
- | -silent | --silent | --silen | --sile | --sil)
- silent=yes ;;
-
- -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
- ac_prev=sbindir ;;
- -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
- | --sbi=* | --sb=*)
- sbindir="$ac_optarg" ;;
-
- -sharedstatedir | --sharedstatedir | --sharedstatedi \
- | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
- | --sharedst | --shareds | --shared | --share | --shar \
- | --sha | --sh)
- ac_prev=sharedstatedir ;;
- -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
- | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
- | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
- | --sha=* | --sh=*)
- sharedstatedir="$ac_optarg" ;;
-
- -site | --site | --sit)
- ac_prev=site ;;
- -site=* | --site=* | --sit=*)
- site="$ac_optarg" ;;
-
- -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
- ac_prev=srcdir ;;
- -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
- srcdir="$ac_optarg" ;;
-
- -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
- | --syscon | --sysco | --sysc | --sys | --sy)
- ac_prev=sysconfdir ;;
- -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
- | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
- sysconfdir="$ac_optarg" ;;
-
- -target | --target | --targe | --targ | --tar | --ta | --t)
- ac_prev=target ;;
- -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
- target="$ac_optarg" ;;
-
- -v | -verbose | --verbose | --verbos | --verbo | --verb)
- verbose=yes ;;
-
- -version | --version | --versio | --versi | --vers)
- echo "configure generated by autoconf version 2.13"
- exit 0 ;;
-
- -with-* | --with-*)
- ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
- # Reject names that are not valid shell variable names.
- if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
- { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
- fi
- ac_package=`echo $ac_package| sed 's/-/_/g'`
- case "$ac_option" in
- *=*) ;;
- *) ac_optarg=yes ;;
- esac
- eval "with_${ac_package}='$ac_optarg'" ;;
-
- -without-* | --without-*)
- ac_package=`echo $ac_option|sed -e 's/-*without-//'`
- # Reject names that are not valid shell variable names.
- if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
- { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
- fi
- ac_package=`echo $ac_package| sed 's/-/_/g'`
- eval "with_${ac_package}=no" ;;
-
- --x)
- # Obsolete; use --with-x.
- with_x=yes ;;
-
- -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
- | --x-incl | --x-inc | --x-in | --x-i)
- ac_prev=x_includes ;;
- -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
- | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
- x_includes="$ac_optarg" ;;
-
- -x-libraries | --x-libraries | --x-librarie | --x-librari \
- | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
- ac_prev=x_libraries ;;
- -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
- | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
- x_libraries="$ac_optarg" ;;
-
- -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
- ;;
-
- *)
- if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
- echo "configure: warning: $ac_option: invalid host type" 1>&2
- fi
- if test "x$nonopt" != xNONE; then
- { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
- fi
- nonopt="$ac_option"
- ;;
-
- esac
-done
-
-if test -n "$ac_prev"; then
- { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
-fi
-
-trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
-
-# File descriptor usage:
-# 0 standard input
-# 1 file creation
-# 2 errors and warnings
-# 3 some systems may open it to /dev/tty
-# 4 used on the Kubota Titan
-# 6 checking for... messages and results
-# 5 compiler messages saved in config.log
-if test "$silent" = yes; then
- exec 6>/dev/null
-else
- exec 6>&1
-fi
-exec 5>./config.log
-
-echo "\
-This file contains any messages produced by compilers while
-running configure, to aid debugging if configure makes a mistake.
-" 1>&5
-
-# Strip out --no-create and --no-recursion so they do not pile up.
-# Also quote any args containing shell metacharacters.
-ac_configure_args=
-for ac_arg
-do
- case "$ac_arg" in
- -no-create | --no-create | --no-creat | --no-crea | --no-cre \
- | --no-cr | --no-c) ;;
- -no-recursion | --no-recursion | --no-recursio | --no-recursi \
- | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
- *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
- ac_configure_args="$ac_configure_args '$ac_arg'" ;;
- *) ac_configure_args="$ac_configure_args $ac_arg" ;;
- esac
-done
-
-# NLS nuisances.
-# Only set these to C if already set. These must not be set unconditionally
-# because not all systems understand e.g. LANG=C (notably SCO).
-# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
-# Non-C LC_CTYPE values break the ctype check.
-if test "${LANG+set}" = set; then LANG=C; export LANG; fi
-if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
-if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
-if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi
-
-# confdefs.h avoids OS command line length limits that DEFS can exceed.
-rm -rf conftest* confdefs.h
-# AIX cpp loses on an empty file, so make sure it contains at least a newline.
-echo > confdefs.h
-
-# A filename unique to this package, relative to the directory that
-# configure is in, which we can look for to find out if srcdir is correct.
-ac_unique_file=getline.c
-
-# Find the source files, if location was not specified.
-if test -z "$srcdir"; then
- ac_srcdir_defaulted=yes
- # Try the directory containing this script, then its parent.
- ac_prog=$0
- ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
- test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
- srcdir=$ac_confdir
- if test ! -r $srcdir/$ac_unique_file; then
- srcdir=..
- fi
-else
- ac_srcdir_defaulted=no
-fi
-if test ! -r $srcdir/$ac_unique_file; then
- if test "$ac_srcdir_defaulted" = yes; then
- { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
- else
- { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
- fi
-fi
-srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
-
-# Prefer explicitly selected file to automatically selected ones.
-if test -z "$CONFIG_SITE"; then
- if test "x$prefix" != xNONE; then
- CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
- else
- CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
- fi
-fi
-for ac_site_file in $CONFIG_SITE; do
- if test -r "$ac_site_file"; then
- echo "loading site script $ac_site_file"
- . "$ac_site_file"
- fi
-done
-
-if test -r "$cache_file"; then
- echo "loading cache $cache_file"
- . $cache_file
-else
- echo "creating cache $cache_file"
- > $cache_file
-fi
-
-ac_ext=c
-# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
-ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
-cross_compiling=$ac_cv_prog_cc_cross
-
-ac_exeext=
-ac_objext=o
-if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
- # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
- if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
- ac_n= ac_c='
-' ac_t=' '
- else
- ac_n=-n ac_c= ac_t=
- fi
-else
- ac_n= ac_c='\c' ac_t=
-fi
-
-
-
-
-
-MAJOR_VER="1"
-
-
-
-MINOR_VER="4"
-
-
-
-MICRO_VER="1"
-
-
-CFLAGS="$CFLAGS"
-# Extract the first word of "gcc", so it can be a program name with args.
-set dummy gcc; ac_word=$2
-echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:543: checking for $ac_word" >&5
-if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- if test -n "$CC"; then
- ac_cv_prog_CC="$CC" # Let the user override the test.
-else
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
- ac_dummy="$PATH"
- for ac_dir in $ac_dummy; do
- test -z "$ac_dir" && ac_dir=.
- if test -f $ac_dir/$ac_word; then
- ac_cv_prog_CC="gcc"
- break
- fi
- done
- IFS="$ac_save_ifs"
-fi
-fi
-CC="$ac_cv_prog_CC"
-if test -n "$CC"; then
- echo "$ac_t""$CC" 1>&6
-else
- echo "$ac_t""no" 1>&6
-fi
-
-if test -z "$CC"; then
- # Extract the first word of "cc", so it can be a program name with args.
-set dummy cc; ac_word=$2
-echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:573: checking for $ac_word" >&5
-if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- if test -n "$CC"; then
- ac_cv_prog_CC="$CC" # Let the user override the test.
-else
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
- ac_prog_rejected=no
- ac_dummy="$PATH"
- for ac_dir in $ac_dummy; do
- test -z "$ac_dir" && ac_dir=.
- if test -f $ac_dir/$ac_word; then
- if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
- ac_prog_rejected=yes
- continue
- fi
- ac_cv_prog_CC="cc"
- break
- fi
- done
- IFS="$ac_save_ifs"
-if test $ac_prog_rejected = yes; then
- # We found a bogon in the path, so make sure we never use it.
- set dummy $ac_cv_prog_CC
- shift
- if test $# -gt 0; then
- # We chose a different compiler from the bogus one.
- # However, it has the same basename, so the bogon will be chosen
- # first if we set CC to just the basename; use the full file name.
- shift
- set dummy "$ac_dir/$ac_word" "$@"
- shift
- ac_cv_prog_CC="$@"
- fi
-fi
-fi
-fi
-CC="$ac_cv_prog_CC"
-if test -n "$CC"; then
- echo "$ac_t""$CC" 1>&6
-else
- echo "$ac_t""no" 1>&6
-fi
-
- if test -z "$CC"; then
- case "`uname -s`" in
- *win32* | *WIN32*)
- # Extract the first word of "cl", so it can be a program name with args.
-set dummy cl; ac_word=$2
-echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:624: checking for $ac_word" >&5
-if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- if test -n "$CC"; then
- ac_cv_prog_CC="$CC" # Let the user override the test.
-else
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
- ac_dummy="$PATH"
- for ac_dir in $ac_dummy; do
- test -z "$ac_dir" && ac_dir=.
- if test -f $ac_dir/$ac_word; then
- ac_cv_prog_CC="cl"
- break
- fi
- done
- IFS="$ac_save_ifs"
-fi
-fi
-CC="$ac_cv_prog_CC"
-if test -n "$CC"; then
- echo "$ac_t""$CC" 1>&6
-else
- echo "$ac_t""no" 1>&6
-fi
- ;;
- esac
- fi
- test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
-fi
-
-echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
-echo "configure:656: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
-
-ac_ext=c
-# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
-ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
-cross_compiling=$ac_cv_prog_cc_cross
-
-cat > conftest.$ac_ext << EOF
-
-#line 667 "configure"
-#include "confdefs.h"
-
-main(){return(0);}
-EOF
-if { (eval echo configure:672: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- ac_cv_prog_cc_works=yes
- # If we can't run a trivial program, we are probably using a cross compiler.
- if (./conftest; exit) 2>/dev/null; then
- ac_cv_prog_cc_cross=no
- else
- ac_cv_prog_cc_cross=yes
- fi
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- ac_cv_prog_cc_works=no
-fi
-rm -fr conftest*
-ac_ext=c
-# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
-ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
-cross_compiling=$ac_cv_prog_cc_cross
-
-echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
-if test $ac_cv_prog_cc_works = no; then
- { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
-fi
-echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
-echo "configure:698: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
-echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
-cross_compiling=$ac_cv_prog_cc_cross
-
-echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
-echo "configure:703: checking whether we are using GNU C" >&5
-if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftest.c <<EOF
-#ifdef __GNUC__
- yes;
-#endif
-EOF
-if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:712: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
- ac_cv_prog_gcc=yes
-else
- ac_cv_prog_gcc=no
-fi
-fi
-
-echo "$ac_t""$ac_cv_prog_gcc" 1>&6
-
-if test $ac_cv_prog_gcc = yes; then
- GCC=yes
-else
- GCC=
-fi
-
-ac_test_CFLAGS="${CFLAGS+set}"
-ac_save_CFLAGS="$CFLAGS"
-CFLAGS=
-echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
-echo "configure:731: checking whether ${CC-cc} accepts -g" >&5
-if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- echo 'void f(){}' > conftest.c
-if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
- ac_cv_prog_cc_g=yes
-else
- ac_cv_prog_cc_g=no
-fi
-rm -f conftest*
-
-fi
-
-echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
-if test "$ac_test_CFLAGS" = set; then
- CFLAGS="$ac_save_CFLAGS"
-elif test $ac_cv_prog_cc_g = yes; then
- if test "$GCC" = yes; then
- CFLAGS="-g -O2"
- else
- CFLAGS="-g"
- fi
-else
- if test "$GCC" = yes; then
- CFLAGS="-O2"
- else
- CFLAGS=
- fi
-fi
-
-
-
-echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
-echo "configure:765: checking whether ${MAKE-make} sets \${MAKE}" >&5
-set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftestmake <<\EOF
-all:
- @echo 'ac_maketemp="${MAKE}"'
-EOF
-# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
-eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
-if test -n "$ac_maketemp"; then
- eval ac_cv_prog_make_${ac_make}_set=yes
-else
- eval ac_cv_prog_make_${ac_make}_set=no
-fi
-rm -f conftestmake
-fi
-if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- SET_MAKE=
-else
- echo "$ac_t""no" 1>&6
- SET_MAKE="MAKE=${MAKE-make}"
-fi
-
-
-
-echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6
-echo "configure:794: checking whether ln -s works" >&5
-if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- rm -f conftestdata
-if ln -s X conftestdata 2>/dev/null
-then
- rm -f conftestdata
- ac_cv_prog_LN_S="ln -s"
-else
- ac_cv_prog_LN_S=ln
-fi
-fi
-LN_S="$ac_cv_prog_LN_S"
-if test "$ac_cv_prog_LN_S" = "ln -s"; then
- echo "$ac_t""yes" 1>&6
-else
- echo "$ac_t""no" 1>&6
-fi
-
-
-
-for ac_prog in gawk mawk nawk awk
-do
-# Extract the first word of "$ac_prog", so it can be a program name with args.
-set dummy $ac_prog; ac_word=$2
-echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:821: checking for $ac_word" >&5
-if eval "test \"`echo '$''{'ac_cv_prog_AWK'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- if test -n "$AWK"; then
- ac_cv_prog_AWK="$AWK" # Let the user override the test.
-else
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
- ac_dummy="$PATH"
- for ac_dir in $ac_dummy; do
- test -z "$ac_dir" && ac_dir=.
- if test -f $ac_dir/$ac_word; then
- ac_cv_prog_AWK="$ac_prog"
- break
- fi
- done
- IFS="$ac_save_ifs"
-fi
-fi
-AWK="$ac_cv_prog_AWK"
-if test -n "$AWK"; then
- echo "$ac_t""$AWK" 1>&6
-else
- echo "$ac_t""no" 1>&6
-fi
-
-test -n "$AWK" && break
-done
-
-
-
-# Extract the first word of "ranlib", so it can be a program name with args.
-set dummy ranlib; ac_word=$2
-echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:855: checking for $ac_word" >&5
-if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- if test -n "$RANLIB"; then
- ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
-else
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
- ac_dummy="$PATH"
- for ac_dir in $ac_dummy; do
- test -z "$ac_dir" && ac_dir=.
- if test -f $ac_dir/$ac_word; then
- ac_cv_prog_RANLIB="ranlib"
- break
- fi
- done
- IFS="$ac_save_ifs"
- test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":"
-fi
-fi
-RANLIB="$ac_cv_prog_RANLIB"
-if test -n "$RANLIB"; then
- echo "$ac_t""$RANLIB" 1>&6
-else
- echo "$ac_t""no" 1>&6
-fi
-
-
-
-ac_aux_dir=
-for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
- if test -f $ac_dir/install-sh; then
- ac_aux_dir=$ac_dir
- ac_install_sh="$ac_aux_dir/install-sh -c"
- break
- elif test -f $ac_dir/install.sh; then
- ac_aux_dir=$ac_dir
- ac_install_sh="$ac_aux_dir/install.sh -c"
- break
- fi
-done
-if test -z "$ac_aux_dir"; then
- { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
-fi
-ac_config_guess=$ac_aux_dir/config.guess
-ac_config_sub=$ac_aux_dir/config.sub
-ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
-
-
-# Do some error checking and defaulting for the host and target type.
-# The inputs are:
-# configure --host=HOST --target=TARGET --build=BUILD NONOPT
-#
-# The rules are:
-# 1. You are not allowed to specify --host, --target, and nonopt at the
-# same time.
-# 2. Host defaults to nonopt.
-# 3. If nonopt is not specified, then host defaults to the current host,
-# as determined by config.guess.
-# 4. Target and build default to nonopt.
-# 5. If nonopt is not specified, then target and build default to host.
-
-# The aliases save the names the user supplied, while $host etc.
-# will get canonicalized.
-case $host---$target---$nonopt in
-NONE---*---* | *---NONE---* | *---*---NONE) ;;
-*) { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } ;;
-esac
-
-
-# Make sure we can run config.sub.
-if ${CONFIG_SHELL-/bin/sh} $ac_config_sub sun4 >/dev/null 2>&1; then :
-else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; }
-fi
-
-echo $ac_n "checking host system type""... $ac_c" 1>&6
-echo "configure:931: checking host system type" >&5
-
-host_alias=$host
-case "$host_alias" in
-NONE)
- case $nonopt in
- NONE)
- if host_alias=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`; then :
- else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; }
- fi ;;
- *) host_alias=$nonopt ;;
- esac ;;
-esac
-
-host=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $host_alias`
-host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
-host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
-host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
-echo "$ac_t""$host" 1>&6
-
-echo $ac_n "checking target system type""... $ac_c" 1>&6
-echo "configure:952: checking target system type" >&5
-
-target_alias=$target
-case "$target_alias" in
-NONE)
- case $nonopt in
- NONE) target_alias=$host_alias ;;
- *) target_alias=$nonopt ;;
- esac ;;
-esac
-
-target=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $target_alias`
-target_cpu=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
-target_vendor=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
-target_os=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
-echo "$ac_t""$target" 1>&6
-
-echo $ac_n "checking build system type""... $ac_c" 1>&6
-echo "configure:970: checking build system type" >&5
-
-build_alias=$build
-case "$build_alias" in
-NONE)
- case $nonopt in
- NONE) build_alias=$host_alias ;;
- *) build_alias=$nonopt ;;
- esac ;;
-esac
-
-build=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $build_alias`
-build_cpu=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
-build_vendor=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
-build_os=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
-echo "$ac_t""$build" 1>&6
-
-test "$host_alias" != "$target_alias" &&
- test "$program_prefix$program_suffix$program_transform_name" = \
- NONENONEs,x,x, &&
- program_prefix=${target_alias}-
-
-
-
-case $target in
-*-sun-solaris2.[0-6]|*-sun-solaris2.[0-6].*)
- LIBS="$LIBS -L/usr/ccs/lib"
- ;;
-esac
-
-
-echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
-echo "configure:1002: checking how to run the C preprocessor" >&5
-# On Suns, sometimes $CPP names a directory.
-if test -n "$CPP" && test -d "$CPP"; then
- CPP=
-fi
-if test -z "$CPP"; then
-if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- # This must be in double quotes, not single quotes, because CPP may get
- # substituted into the Makefile and "${CC-cc}" will confuse make.
- CPP="${CC-cc} -E"
- # On the NeXT, cc -E runs the code through the compiler's parser,
- # not just through cpp.
- cat > conftest.$ac_ext <<EOF
-#line 1017 "configure"
-#include "confdefs.h"
-#include <assert.h>
-Syntax Error
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1023: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
- :
-else
- echo "$ac_err" >&5
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- CPP="${CC-cc} -E -traditional-cpp"
- cat > conftest.$ac_ext <<EOF
-#line 1034 "configure"
-#include "confdefs.h"
-#include <assert.h>
-Syntax Error
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1040: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
- :
-else
- echo "$ac_err" >&5
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- CPP="${CC-cc} -nologo -E"
- cat > conftest.$ac_ext <<EOF
-#line 1051 "configure"
-#include "confdefs.h"
-#include <assert.h>
-Syntax Error
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1057: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
- :
-else
- echo "$ac_err" >&5
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- CPP=/lib/cpp
-fi
-rm -f conftest*
-fi
-rm -f conftest*
-fi
-rm -f conftest*
- ac_cv_prog_CPP="$CPP"
-fi
- CPP="$ac_cv_prog_CPP"
-else
- ac_cv_prog_CPP="$CPP"
-fi
-echo "$ac_t""$CPP" 1>&6
-
-echo $ac_n "checking for tigetstr in -lcurses""... $ac_c" 1>&6
-echo "configure:1082: checking for tigetstr in -lcurses" >&5
-ac_lib_var=`echo curses'_'tigetstr | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- ac_save_LIBS="$LIBS"
-LIBS="-lcurses $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 1090 "configure"
-#include "confdefs.h"
-/* Override any gcc2 internal prototype to avoid an error. */
-/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char tigetstr();
-
-int main() {
-tigetstr()
-; return 0; }
-EOF
-if { (eval echo configure:1101: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=yes"
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
- echo "$ac_t""yes" 1>&6
-
- cat >> confdefs.h <<\EOF
-#define USE_TERMINFO 1
-EOF
-
- LIBS="$LIBS -lcurses"
-
-else
- echo "$ac_t""no" 1>&6
-echo $ac_n "checking for tigetstr in -lncurses""... $ac_c" 1>&6
-echo "configure:1126: checking for tigetstr in -lncurses" >&5
-ac_lib_var=`echo ncurses'_'tigetstr | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- ac_save_LIBS="$LIBS"
-LIBS="-lncurses $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 1134 "configure"
-#include "confdefs.h"
-/* Override any gcc2 internal prototype to avoid an error. */
-/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char tigetstr();
-
-int main() {
-tigetstr()
-; return 0; }
-EOF
-if { (eval echo configure:1145: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=yes"
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
- echo "$ac_t""yes" 1>&6
-
- cat >> confdefs.h <<\EOF
-#define USE_TERMINFO 1
-EOF
-
- LIBS="$LIBS -lncurses"
-
-else
- echo "$ac_t""no" 1>&6
-echo $ac_n "checking for tgetstr in -lcurses""... $ac_c" 1>&6
-echo "configure:1170: checking for tgetstr in -lcurses" >&5
-ac_lib_var=`echo curses'_'tgetstr | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- ac_save_LIBS="$LIBS"
-LIBS="-lcurses $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 1178 "configure"
-#include "confdefs.h"
-/* Override any gcc2 internal prototype to avoid an error. */
-/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char tgetstr();
-
-int main() {
-tgetstr()
-; return 0; }
-EOF
-if { (eval echo configure:1189: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=yes"
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
- echo "$ac_t""yes" 1>&6
-
- cat >> confdefs.h <<\EOF
-#define USE_TERMCAP 1
-EOF
-
- LIBS="$LIBS -lcurses"
- ac_safe=`echo "termcap.h" | sed 'y%./+-%__p_%'`
-echo $ac_n "checking for termcap.h""... $ac_c" 1>&6
-echo "configure:1212: checking for termcap.h" >&5
-if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftest.$ac_ext <<EOF
-#line 1217 "configure"
-#include "confdefs.h"
-#include <termcap.h>
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1222: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
- rm -rf conftest*
- eval "ac_cv_header_$ac_safe=yes"
-else
- echo "$ac_err" >&5
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_header_$ac_safe=no"
-fi
-rm -f conftest*
-fi
-if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- cat >> confdefs.h <<\EOF
-#define HAVE_TERMCAP_H 1
-EOF
-
-else
- echo "$ac_t""no" 1>&6
-fi
-
-
-else
- echo "$ac_t""no" 1>&6
-fi
-
-fi
-
-fi
-
-
-
-ac_safe=`echo "term.h" | sed 'y%./+-%__p_%'`
-echo $ac_n "checking for term.h""... $ac_c" 1>&6
-echo "configure:1259: checking for term.h" >&5
-if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftest.$ac_ext <<EOF
-#line 1264 "configure"
-#include "confdefs.h"
-#include <term.h>
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1269: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
- rm -rf conftest*
- eval "ac_cv_header_$ac_safe=yes"
-else
- echo "$ac_err" >&5
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_header_$ac_safe=no"
-fi
-rm -f conftest*
-fi
-if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- cat >> confdefs.h <<\EOF
-#define HAVE_TERM_H 1
-EOF
-
-else
- echo "$ac_t""no" 1>&6
-
- ac_safe=`echo "ncurses/term.h" | sed 'y%./+-%__p_%'`
-echo $ac_n "checking for ncurses/term.h""... $ac_c" 1>&6
-echo "configure:1294: checking for ncurses/term.h" >&5
-if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftest.$ac_ext <<EOF
-#line 1299 "configure"
-#include "confdefs.h"
-#include <ncurses/term.h>
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1304: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
- rm -rf conftest*
- eval "ac_cv_header_$ac_safe=yes"
-else
- echo "$ac_err" >&5
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_header_$ac_safe=no"
-fi
-rm -f conftest*
-fi
-if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- cat >> confdefs.h <<\EOF
-#define HAVE_NCURSES_TERM_H 1
-EOF
-
-else
- echo "$ac_t""no" 1>&6
-fi
-
-
-fi
-
-
-
-ac_safe=`echo "curses.h" | sed 'y%./+-%__p_%'`
-echo $ac_n "checking for curses.h""... $ac_c" 1>&6
-echo "configure:1335: checking for curses.h" >&5
-if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftest.$ac_ext <<EOF
-#line 1340 "configure"
-#include "confdefs.h"
-#include <curses.h>
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1345: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
- rm -rf conftest*
- eval "ac_cv_header_$ac_safe=yes"
-else
- echo "$ac_err" >&5
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_header_$ac_safe=no"
-fi
-rm -f conftest*
-fi
-if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- cat >> confdefs.h <<\EOF
-#define HAVE_CURSES_H 1
-EOF
-
-else
- echo "$ac_t""no" 1>&6
-
- ac_safe=`echo "ncurses/curses.h" | sed 'y%./+-%__p_%'`
-echo $ac_n "checking for ncurses/curses.h""... $ac_c" 1>&6
-echo "configure:1370: checking for ncurses/curses.h" >&5
-if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftest.$ac_ext <<EOF
-#line 1375 "configure"
-#include "confdefs.h"
-#include <ncurses/curses.h>
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1380: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
- rm -rf conftest*
- eval "ac_cv_header_$ac_safe=yes"
-else
- echo "$ac_err" >&5
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_header_$ac_safe=no"
-fi
-rm -f conftest*
-fi
-if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- cat >> confdefs.h <<\EOF
-#define HAVE_NCURSES_CURSES_H 1
-EOF
-
-else
- echo "$ac_t""no" 1>&6
-fi
-
-
-fi
-
-
-
-
-TARGETS="normal reentrant"
-
-
-echo $ac_n "checking for reentrant functions""... $ac_c" 1>&6
-echo "configure:1414: checking for reentrant functions" >&5
-if eval "test \"`echo '$''{'tecla_cv_reentrant'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
-
- KEPT_CFLAGS="$CFLAGS"
- CFLAGS="$CFLAGS -D_POSIX_C_SOURCE=199506L"
- cat > conftest.$ac_ext <<EOF
-#line 1422 "configure"
-#include "confdefs.h"
-
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <dirent.h>
-#include <pwd.h>
-
-int main() {
-
- (void) readdir_r(NULL, NULL, NULL);
- (void) getpwuid_r(geteuid(), NULL, NULL, 0, NULL);
- (void) getpwnam_r(NULL, NULL, NULL, 0, NULL);
-
-; return 0; }
-EOF
-if { (eval echo configure:1439: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- tecla_cv_reentrant=yes
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- tecla_cv_reentrant=no
-fi
-rm -f conftest*
- CFLAGS="$KEPT_CFLAGS"
-
-fi
-
-echo "$ac_t""$tecla_cv_reentrant" 1>&6
-
-
-if test $tecla_cv_reentrant = no; then
- TARGETS="normal"
-fi
-
-
-echo $ac_n "checking for select system call""... $ac_c" 1>&6
-echo "configure:1462: checking for select system call" >&5
-if eval "test \"`echo '$''{'tecla_cv_select'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
-
- cat > conftest.$ac_ext <<EOF
-#line 1468 "configure"
-#include "confdefs.h"
-
-#ifdef HAVE_SELECT_H
-#include <select.h>
-#endif
-#include <sys/time.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-int main() {
-
- fd_set fds;
- int nready;
- FD_ZERO(&fds);
- FD_SET(1, &fds);
- nready = select(2, &fds, &fds, &fds, NULL);
-
-; return 0; }
-EOF
-if { (eval echo configure:1488: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- tecla_cv_select=yes
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- tecla_cv_select=no
-fi
-rm -f conftest*
-
-fi
-
-echo "$ac_t""$tecla_cv_select" 1>&6
-
-
-if test $tecla_cv_select = yes; then
- cat >> confdefs.h <<\EOF
-#define HAVE_SELECT 1
-EOF
-
-fi
-
-
-echo $ac_n "checking for SysV pseudo-terminals""... $ac_c" 1>&6
-echo "configure:1513: checking for SysV pseudo-terminals" >&5
-if eval "test \"`echo '$''{'tecla_cv_sysv_pty'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
-
- cat > conftest.$ac_ext <<EOF
-#line 1519 "configure"
-#include "confdefs.h"
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <stropts.h>
-
-int main() {
-
- char *name = ptsname(0);
- int i1 = grantpt(0);
- int i2 = unlockpt(0);
- int i3 = ioctl(0, I_PUSH, "ptem");
- return 0;
-
-; return 0; }
-EOF
-if { (eval echo configure:1536: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- tecla_cv_sysv_pty=yes
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- tecla_cv_sysv_pty=no
-fi
-rm -f conftest*
-
-fi
-
-echo "$ac_t""$tecla_cv_sysv_pty" 1>&6
-
-
-if test $tecla_cv_sysv_pty = yes; then
- cat >> confdefs.h <<\EOF
-#define HAVE_SYSV_PTY 1
-EOF
-
-fi
-
-
-
-SHARED_EXT=""
-
-
-
-SHARED_ALT=""
-
-
-
-SHARED_CFLAGS=""
-
-
-
-LINK_SHARED=""
-
-
-case $target in
-*solaris*)
- cat >> confdefs.h <<\EOF
-#define __EXTENSIONS__ 1
-EOF
-
- SHARED_EXT=".so.${MAJOR_VER}"
- SHARED_ALT=".so"
- LINK_SHARED='ld -G -M $$(srcdir)/libtecla.map -o $$@ -h $$(@F) -z defs -i $$(LIB_OBJECTS) $$(LIBS) -lc'
- SHARED_CFLAGS="-Kpic"
- case $CC in
- */cc|cc) SHARED_CFLAGS="$SHARED_CFLAGS -xstrconst" ;;
- gcc) CFLAGS="-I/usr/include $CFLAGS" ;;
- esac
- case $target in
- *sparc*) SHARED_CFLAGS="$SHARED_CFLAGS -xregs=no%appl"
- esac
- ;;
-*linux*)
- SHARED_EXT=".so.${MAJOR_VER}.${MINOR_VER}.${MICRO_VER}"
- SHARED_ALT=".so .so.${MAJOR_VER}"
-
-
- echo $ac_n "checking for --version-script in GNU ld""... $ac_c" 1>&6
-echo "configure:1600: checking for --version-script in GNU ld" >&5
-if eval "test \"`echo '$''{'tecla_cv_gnu_ld_script'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
-
- if (echo 'void dummy(void) {return;}' > dummy.c; $CC -c -fpic dummy.c; \
- ld -o dummy.so dummy.o -shared --version-script=$srcdir/libtecla.map) 1>&2 2>/dev/null; then
- tecla_cv_gnu_ld_script=yes
- else
- tecla_cv_gnu_ld_script=no
- fi
- rm -f dummy.c dummy.o dummy.so
-
-fi
-
-echo "$ac_t""$tecla_cv_gnu_ld_script" 1>&6
- if test $tecla_cv_gnu_ld_script = yes; then
- VERSION_OPT='--version-script=$$(srcdir)/libtecla.map'
- else
- VERSION_OPT=''
- fi
-
- LINK_SHARED='ld -o $$@ -soname libtecla$$(SUFFIX).so.'${MAJOR_VER}' -shared '$VERSION_OPT' $$(LIB_OBJECTS) $$(LIBS) -lc'
- SHARED_CFLAGS="-fpic"
- ;;
-*hpux*)
- SHARED_EXT=".${MAJOR_VER}"
- SHARED_ALT=".sl"
- LINK_SHARED='ld -b +h $$(@F) +k +vshlibunsats -o $$@ -c libtecla.map.opt $$(LIB_OBJECTS) $$(LIBS) -lc'
- SHARED_CFLAGS="+z"
- ;;
-*dec-osf*)
- cat >> confdefs.h <<\EOF
-#define _OSF_SOURCE 1
-EOF
-
- ;;
-esac
-
-
-if test "$GCC"_ = "yes"_ && test "$LINK_SHARED"_ != "_" ; then
- SHARED_CFLAGS="-fpic"
- case $target_os in
- sparc*solaris*) SHARED_CFLAGS="$SHARED_CFLAGS -mno-app-regs"
- esac
- LINK_SHARED="$LINK_SHARED `gcc -print-libgcc-file-name`"
-fi
-
-
-
-
-
-if test "$LINK_SHARED"_ != "_"; then
- TARGET_LIBS="static shared"
-else
- TARGET_LIBS="static"
- LINK_SHARED="@:"
-fi
-
-
-trap '' 1 2 15
-cat > confcache <<\EOF
-# This file is a shell script that caches the results of configure
-# tests run on this system so they can be shared between configure
-# scripts and configure runs. It is not useful on other systems.
-# If it contains results you don't want to keep, you may remove or edit it.
-#
-# By default, configure uses ./config.cache as the cache file,
-# creating it if it does not exist already. You can give configure
-# the --cache-file=FILE option to use a different cache file; that is
-# what configure does when it calls configure scripts in
-# subdirectories, so they share the cache.
-# Giving --cache-file=/dev/null disables caching, for debugging configure.
-# config.status only pays attention to the cache file if you give it the
-# --recheck option to rerun configure.
-#
-EOF
-# The following way of writing the cache mishandles newlines in values,
-# but we know of no workaround that is simple, portable, and efficient.
-# So, don't put newlines in cache variables' values.
-# Ultrix sh set writes to stderr and can't be redirected directly,
-# and sets the high bit in the cache file unless we assign to the vars.
-(set) 2>&1 |
- case `(ac_space=' '; set | grep ac_space) 2>&1` in
- *ac_space=\ *)
- # `set' does not quote correctly, so add quotes (double-quote substitution
- # turns \\\\ into \\, and sed turns \\ into \).
- sed -n \
- -e "s/'/'\\\\''/g" \
- -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
- ;;
- *)
- # `set' quotes correctly as required by POSIX, so do not add quotes.
- sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
- ;;
- esac >> confcache
-if cmp -s $cache_file confcache; then
- :
-else
- if test -w $cache_file; then
- echo "updating cache $cache_file"
- cat confcache > $cache_file
- else
- echo "not updating unwritable cache $cache_file"
- fi
-fi
-rm -f confcache
-
-trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
-
-test "x$prefix" = xNONE && prefix=$ac_default_prefix
-# Let make expand exec_prefix.
-test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
-
-# Any assignment to VPATH causes Sun make to only execute
-# the first set of double-colon rules, so remove it if not needed.
-# If there is a colon in the path, we need to keep it.
-if test "x$srcdir" = x.; then
- ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d'
-fi
-
-trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
-
-# Transform confdefs.h into DEFS.
-# Protect against shell expansion while executing Makefile rules.
-# Protect against Makefile macro expansion.
-cat > conftest.defs <<\EOF
-s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%-D\1=\2%g
-s%[ `~#$^&*(){}\\|;'"<>?]%\\&%g
-s%\[%\\&%g
-s%\]%\\&%g
-s%\$%$$%g
-EOF
-DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' '`
-rm -f conftest.defs
-
-
-# Without the "./", some shells look in PATH for config.status.
-: ${CONFIG_STATUS=./config.status}
-
-echo creating $CONFIG_STATUS
-rm -f $CONFIG_STATUS
-cat > $CONFIG_STATUS <<EOF
-#! /bin/sh
-# Generated automatically by configure.
-# Run this file to recreate the current configuration.
-# This directory was configured as follows,
-# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
-#
-# $0 $ac_configure_args
-#
-# Compiler output produced by configure, useful for debugging
-# configure, is in ./config.log if it exists.
-
-ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
-for ac_option
-do
- case "\$ac_option" in
- -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
- echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
- exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
- -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
- echo "$CONFIG_STATUS generated by autoconf version 2.13"
- exit 0 ;;
- -help | --help | --hel | --he | --h)
- echo "\$ac_cs_usage"; exit 0 ;;
- *) echo "\$ac_cs_usage"; exit 1 ;;
- esac
-done
-
-ac_given_srcdir=$srcdir
-
-trap 'rm -fr `echo "Makefile" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
-EOF
-cat >> $CONFIG_STATUS <<EOF
-
-# Protect against being on the right side of a sed subst in config.status.
-sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
- s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
-$ac_vpsub
-$extrasub
-s%@SHELL@%$SHELL%g
-s%@CFLAGS@%$CFLAGS%g
-s%@CPPFLAGS@%$CPPFLAGS%g
-s%@CXXFLAGS@%$CXXFLAGS%g
-s%@FFLAGS@%$FFLAGS%g
-s%@DEFS@%$DEFS%g
-s%@LDFLAGS@%$LDFLAGS%g
-s%@LIBS@%$LIBS%g
-s%@exec_prefix@%$exec_prefix%g
-s%@prefix@%$prefix%g
-s%@program_transform_name@%$program_transform_name%g
-s%@bindir@%$bindir%g
-s%@sbindir@%$sbindir%g
-s%@libexecdir@%$libexecdir%g
-s%@datadir@%$datadir%g
-s%@sysconfdir@%$sysconfdir%g
-s%@sharedstatedir@%$sharedstatedir%g
-s%@localstatedir@%$localstatedir%g
-s%@libdir@%$libdir%g
-s%@includedir@%$includedir%g
-s%@oldincludedir@%$oldincludedir%g
-s%@infodir@%$infodir%g
-s%@mandir@%$mandir%g
-s%@MAJOR_VER@%$MAJOR_VER%g
-s%@MINOR_VER@%$MINOR_VER%g
-s%@MICRO_VER@%$MICRO_VER%g
-s%@CC@%$CC%g
-s%@SET_MAKE@%$SET_MAKE%g
-s%@LN_S@%$LN_S%g
-s%@AWK@%$AWK%g
-s%@RANLIB@%$RANLIB%g
-s%@host@%$host%g
-s%@host_alias@%$host_alias%g
-s%@host_cpu@%$host_cpu%g
-s%@host_vendor@%$host_vendor%g
-s%@host_os@%$host_os%g
-s%@target@%$target%g
-s%@target_alias@%$target_alias%g
-s%@target_cpu@%$target_cpu%g
-s%@target_vendor@%$target_vendor%g
-s%@target_os@%$target_os%g
-s%@build@%$build%g
-s%@build_alias@%$build_alias%g
-s%@build_cpu@%$build_cpu%g
-s%@build_vendor@%$build_vendor%g
-s%@build_os@%$build_os%g
-s%@CPP@%$CPP%g
-s%@TARGETS@%$TARGETS%g
-s%@SHARED_EXT@%$SHARED_EXT%g
-s%@SHARED_ALT@%$SHARED_ALT%g
-s%@SHARED_CFLAGS@%$SHARED_CFLAGS%g
-s%@LINK_SHARED@%$LINK_SHARED%g
-s%@TARGET_LIBS@%$TARGET_LIBS%g
-
-CEOF
-EOF
-
-cat >> $CONFIG_STATUS <<\EOF
-
-# Split the substitutions into bite-sized pieces for seds with
-# small command number limits, like on Digital OSF/1 and HP-UX.
-ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
-ac_file=1 # Number of current file.
-ac_beg=1 # First line for current file.
-ac_end=$ac_max_sed_cmds # Line after last line for current file.
-ac_more_lines=:
-ac_sed_cmds=""
-while $ac_more_lines; do
- if test $ac_beg -gt 1; then
- sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
- else
- sed "${ac_end}q" conftest.subs > conftest.s$ac_file
- fi
- if test ! -s conftest.s$ac_file; then
- ac_more_lines=false
- rm -f conftest.s$ac_file
- else
- if test -z "$ac_sed_cmds"; then
- ac_sed_cmds="sed -f conftest.s$ac_file"
- else
- ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
- fi
- ac_file=`expr $ac_file + 1`
- ac_beg=$ac_end
- ac_end=`expr $ac_end + $ac_max_sed_cmds`
- fi
-done
-if test -z "$ac_sed_cmds"; then
- ac_sed_cmds=cat
-fi
-EOF
-
-cat >> $CONFIG_STATUS <<EOF
-
-CONFIG_FILES=\${CONFIG_FILES-"Makefile"}
-EOF
-cat >> $CONFIG_STATUS <<\EOF
-for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
- # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
- case "$ac_file" in
- *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
- ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
- *) ac_file_in="${ac_file}.in" ;;
- esac
-
- # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
-
- # Remove last slash and all that follows it. Not all systems have dirname.
- ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
- if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
- # The file is in a subdirectory.
- test ! -d "$ac_dir" && mkdir "$ac_dir"
- ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
- # A "../" for each directory in $ac_dir_suffix.
- ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
- else
- ac_dir_suffix= ac_dots=
- fi
-
- case "$ac_given_srcdir" in
- .) srcdir=.
- if test -z "$ac_dots"; then top_srcdir=.
- else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
- /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
- *) # Relative path.
- srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
- top_srcdir="$ac_dots$ac_given_srcdir" ;;
- esac
-
-
- echo creating "$ac_file"
- rm -f "$ac_file"
- configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
- case "$ac_file" in
- *Makefile*) ac_comsub="1i\\
-# $configure_input" ;;
- *) ac_comsub= ;;
- esac
-
- ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
- sed -e "$ac_comsub
-s%@configure_input@%$configure_input%g
-s%@srcdir@%$srcdir%g
-s%@top_srcdir@%$top_srcdir%g
-" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
-fi; done
-rm -f conftest.s*
-
-EOF
-cat >> $CONFIG_STATUS <<EOF
-
-EOF
-cat >> $CONFIG_STATUS <<\EOF
-
-exit 0
-EOF
-chmod +x $CONFIG_STATUS
-rm -fr confdefs* $ac_clean_files
-test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
-
diff --git a/libtecla-1.4.1/history.c b/libtecla-1.4.1/history.c
deleted file mode 100644
index 5a8d94f..0000000
--- a/libtecla-1.4.1/history.c
+++ /dev/null
@@ -1,2003 +0,0 @@
-/*
- * Copyright (c) 2000, 2001 by Martin C. Shepherd.
- *
- * All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, and/or sell copies of the Software, and to permit persons
- * to whom the Software is furnished to do so, provided that the above
- * copyright notice(s) and this permission notice appear in all copies of
- * the Software and that both the above copyright notice(s) and this
- * permission notice appear in supporting documentation.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
- * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
- * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
- * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
- * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * Except as contained in this notice, the name of a copyright holder
- * shall not be used in advertising or otherwise to promote the sale, use
- * or other dealings in this Software without prior written authorization
- * of the copyright holder.
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
-#include <time.h>
-#include <errno.h>
-
-#include "history.h"
-#include "freelist.h"
-
-/*
- * GlLineNode's record the location and length of historical lines in
- * a buffer array.
- */
-typedef struct GlLineNode GlLineNode;
-struct GlLineNode {
- long id; /* The unique identifier of this history line */
- time_t timestamp; /* The time at which the line was archived */
- unsigned group; /* The identifier of the history group to which the */
- /* the line belongs. */
- GlLineNode *next; /* The next youngest line in the list */
- GlLineNode *prev; /* The next oldest line in the list */
- int start; /* The start index of the line in the buffer */
- int nchar; /* The total length of the line, including the '\0' */
-};
-
-/*
- * The number of GlLineNode elements per freelist block.
- */
-#define LINE_NODE_BLK 100
-
-/*
- * Lines are organised in the buffer from oldest to newest. The
- * positions of the lines are recorded in a doubly linked list
- * of GlLineNode objects.
- */
-typedef struct {
- FreeList *node_mem; /* A freelist of GlLineNode objects */
- GlLineNode *head; /* The head of the list of lines */
- GlLineNode *tail; /* The tail of the list of lines */
-} GlLineList;
-
-/*
- * All elements of the history mechanism are recorded in an object of
- * the following type.
- */
-struct GlHistory {
- char *buffer; /* A circular buffer used to record historical input */
- /* lines. */
- size_t buflen; /* The length of the buffer array */
- GlLineList list; /* A list of the start of lines in buffer[] */
- GlLineNode *recall; /* The last line recalled, or NULL if no recall */
- /* session is currently active. */
- GlLineNode *id_node;/* The node at which the last ID search terminated */
- const char *prefix; /* A pointer to the line containing the prefix that */
- /* is being searched for. */
- int prefix_len; /* The length of the prefix */
- unsigned long seq; /* The next ID to assign to a line node */
- unsigned group; /* The identifier of the current history group */
- int nline; /* The number of lines currently in the history list */
- int max_lines; /* Either -1 or a ceiling on the number of lines */
- int enable; /* If false, ignore history additions and lookups */
-};
-
-static char *_glh_restore_line(GlHistory *glh, char *line, size_t dim);
-static int _glh_cant_load_history(GlHistory *glh, const char *filename,
- int lineno, const char *message, FILE *fp);
-static int _glh_write_timestamp(FILE *fp, time_t timestamp);
-static int _glh_decode_timestamp(char *string, char **endp, time_t *t);
-static void _glh_discard_node(GlHistory *glh, GlLineNode *node);
-static GlLineNode *_glh_find_id(GlHistory *glh, GlhLineID id);
-
-/*.......................................................................
- * Create a line history maintenance object.
- *
- * Input:
- * buflen size_t The number of bytes to allocate to the circular
- * buffer that is used to record all of the
- * most recent lines of user input that will fit.
- * If buflen==0, no buffer will be allocated.
- * Output:
- * return GlHistory * The new object, or NULL on error.
- */
-GlHistory *_new_GlHistory(size_t buflen)
-{
- GlHistory *glh; /* The object to be returned */
-/*
- * Allocate the container.
- */
- glh = (GlHistory *) malloc(sizeof(GlHistory));
- if(!glh) {
- fprintf(stderr, "_new_GlHistory: Insufficient memory.\n");
- return NULL;
- };
-/*
- * Before attempting any operation that might fail, initialize the
- * container at least up to the point at which it can safely be passed
- * to _del_GlHistory().
- */
- glh->buffer = NULL;
- glh->buflen = buflen;
- glh->list.node_mem = NULL;
- glh->list.head = NULL;
- glh->list.tail = NULL;
- glh->recall = NULL;
- glh->id_node = NULL;
- glh->prefix = NULL;
- glh->prefix_len = 0;
- glh->seq = 0;
- glh->group = 0;
- glh->nline = 0;
- glh->max_lines = -1;
- glh->enable = 1;
-/*
- * Allocate the buffer, if required.
- */
- if(buflen > 0) {
- glh->buffer = (char *) malloc(sizeof(char) * buflen);
- if(!glh->buffer) {
- fprintf(stderr, "_new_GlHistory: Insufficient memory.\n");
- return _del_GlHistory(glh);
- };
- };
-/*
- * Allocate the GlLineNode freelist.
- */
- glh->list.node_mem = _new_FreeList("_new_GlHistory", sizeof(GlLineNode),
- LINE_NODE_BLK);
- if(!glh->list.node_mem)
- return _del_GlHistory(glh);
- return glh;
-}
-
-/*.......................................................................
- * Delete a GlHistory object.
- *
- * Input:
- * glh GlHistory * The object to be deleted.
- * Output:
- * return GlHistory * The deleted object (always NULL).
- */
-GlHistory *_del_GlHistory(GlHistory *glh)
-{
- if(glh) {
-/*
- * Delete the buffer.
- */
- if(glh->buffer) {
- free(glh->buffer);
- glh->buffer = NULL;
- };
-/*
- * Delete the freelist of GlLineNode's.
- */
- glh->list.node_mem = _del_FreeList("_del_GlHistory", glh->list.node_mem, 1);
-/*
- * The contents of the list were deleted by deleting the freelist.
- */
- glh->list.head = NULL;
- glh->list.tail = NULL;
-/*
- * Delete the container.
- */
- free(glh);
- };
- return NULL;
-}
-
-/*.......................................................................
- * Add a new line to the end of the history buffer, wrapping round to the
- * start of the buffer if needed.
- *
- * Input:
- * glh GlHistory * The input-line history maintenance object.
- * line char * The line to be archived.
- * force int Unless this flag is non-zero, empty lines and
- * lines which match the previous line in the history
- * buffer, aren't archived. This flag requests that
- * the line be archived regardless.
- * Output:
- * return int 0 - OK.
- * 1 - Error.
- */
-int _glh_add_history(GlHistory *glh, const char *line, int force)
-{
- GlLineList *list; /* The line location list */
- int nchar; /* The number of characters needed to record the line */
- GlLineNode *node; /* The new line location list node */
- int empty; /* True if the string is empty */
- const char *nlptr;/* A pointer to a newline character in line[] */
- int i;
-/*
- * Check the arguments.
- */
- if(!glh || !line)
- return 1;
-/*
- * Is history enabled?
- */
- if(!glh->enable || !glh->buffer || glh->max_lines == 0)
- return 0;
-/*
- * Get the line location list.
- */
- list = &glh->list;
-/*
- * Cancel any ongoing search.
- */
- if(_glh_cancel_search(glh))
- return 1;
-/*
- * See how much buffer space will be needed to record the line?
- *
- * If the string contains a terminating newline character, arrange to
- * have the archived line NUL terminated at this point.
- */
- nlptr = strchr(line, '\n');
- if(nlptr)
- nchar = (nlptr - line) + 1;
- else
- nchar = strlen(line) + 1;
-/*
- * If the line is too big to fit in the buffer, truncate it.
- */
- if(nchar > glh->buflen)
- nchar = glh->buflen;
-/*
- * Is the line empty?
- */
- empty = 1;
- for(i=0; i<nchar-1 && empty; i++)
- empty = isspace((int)(unsigned char) line[i]);
-/*
- * If the line is empty, don't add it to the buffer unless explicitly
- * told to.
- */
- if(empty && !force)
- return 0;
-/*
- * If the new line is the same as the most recently added line,
- * don't add it again, unless explicitly told to.
- */
- if(!force &&
- list->tail && strlen(glh->buffer + list->tail->start) == nchar-1 &&
- strncmp(line, glh->buffer + list->tail->start, nchar-1)==0)
- return 0;
-/*
- * Allocate the list node that will record the line location.
- */
- node = (GlLineNode *) _new_FreeListNode(list->node_mem);
- if(!node)
- return 1;
-/*
- * Is the buffer empty?
- */
- if(!list->head) {
-/*
- * Place the line at the beginning of the buffer.
- */
- strncpy(glh->buffer, line, nchar);
- glh->buffer[nchar-1] = '\0';
-/*
- * Record the location of the line.
- */
- node->start = 0;
-/*
- * The buffer has one or more lines in it.
- */
- } else {
-/*
- * Place the start of the new line just after the most recently
- * added line.
- */
- int start = list->tail->start + list->tail->nchar;
-/*
- * If there is insufficient room between the end of the most
- * recently added line and the end of the buffer, we place the
- * line at the beginning of the buffer. To make as much space
- * as possible for this line, we first delete any old lines
- * at the end of the buffer, then shift the remaining contents
- * of the buffer to the end of the buffer.
- */
- if(start + nchar >= glh->buflen) {
- GlLineNode *last; /* The last line in the buffer */
- GlLineNode *ln; /* A member of the list of line locations */
- int shift; /* The shift needed to move the contents of the */
- /* buffer to its end. */
-/*
- * Delete any old lines between the most recent line and the end of the
- * buffer.
- */
- while(list->head && list->head->start > list->tail->start)
- _glh_discard_node(glh, list->head);
-/*
- * Find the line that is nearest the end of the buffer.
- */
- last = NULL;
- for(ln=list->head; ln; ln=ln->next) {
- if(!last || ln->start > last->start)
- last = ln;
- };
-/*
- * How big a shift is needed to move the existing contents of the
- * buffer to the end of the buffer?
- */
- shift = last ? (glh->buflen - (last->start + last->nchar)) : 0;
-/*
- * Is any shift needed?
- */
- if(shift > 0) {
-/*
- * Move the buffer contents to the end of the buffer.
- */
- memmove(glh->buffer + shift, glh->buffer, glh->buflen - shift);
-/*
- * Update the listed locations to reflect the shift.
- */
- for(ln=list->head; ln; ln=ln->next)
- ln->start += shift;
- };
-/*
- * The new line should now be located at the start of the buffer.
- */
- start = 0;
- };
-/*
- * Make space for the new line at the beginning of the buffer by
- * deleting the oldest lines. This just involves removing them
- * from the list of used locations. Also enforce the current
- * maximum number of lines.
- */
- while(list->head &&
- ((list->head->start >= start && list->head->start - start < nchar) ||
- (glh->max_lines >= 0 && glh->nline>=glh->max_lines))) {
- _glh_discard_node(glh, list->head);
- };
-/*
- * Copy the new line into the buffer.
- */
- memcpy(glh->buffer + start, line, nchar);
- glh->buffer[start + nchar - 1] = '\0';
-/*
- * Record its location.
- */
- node->start = start;
- };
-/*
- * Append the line location node to the end of the list.
- */
- node->id = glh->seq++;
- node->timestamp = time(NULL);
- node->group = glh->group;
- node->nchar = nchar;
- node->next = NULL;
- node->prev = list->tail;
- if(list->tail)
- list->tail->next = node;
- else
- list->head = node;
- list->tail = node;
- glh->nline++;
- return 0;
-}
-
-/*.......................................................................
- * Recall the next oldest line that has the search prefix last recorded
- * by _glh_search_prefix().
- *
- * Input:
- * glh GlHistory * The input-line history maintenance object.
- * line char * The input line buffer. On input this should contain
- * the current input line, and on output, if anything
- * was found, its contents will have been replaced
- * with the matching line.
- * dim size_t The allocated dimensions of the line buffer.
- * Output:
- * return char * A pointer to line[0], or NULL if not found.
- */
-char *_glh_find_backwards(GlHistory *glh, char *line, size_t dim)
-{
- GlLineNode *node; /* The line location node being checked */
- int first; /* True if this is the start of a new search */
-/*
- * Check the arguments.
- */
- if(!glh || !line) {
- fprintf(stderr, "_glh_find_backwards: NULL argument(s).\n");
- return NULL;
- };
-/*
- * Is history enabled?
- */
- if(!glh->enable || !glh->buffer || glh->max_lines == 0)
- return NULL;
-/*
- * Check the line dimensions.
- */
- if(dim < strlen(line) + 1) {
- fprintf(stderr,
- "_glh_find_backwards: 'dim' inconsistent with strlen(line) contents.\n");
- return NULL;
- };
-/*
- * Is this the start of a new search?
- */
- first = glh->recall==NULL;
-/*
- * If this is the first search backwards, save the current line
- * for potential recall later, and mark it as the last line
- * recalled.
- */
- if(first) {
- if(_glh_add_history(glh, line, 1))
- return NULL;
- glh->recall = glh->list.tail;
- };
-/*
- * If there is no search prefix, the prefix last set by glh_search_prefix()
- * doesn't exist in the history buffer.
- */
- if(!glh->prefix)
- return NULL;
-/*
- * From where should we start the search?
- */
- if(glh->recall)
- node = glh->recall->prev;
- else
- node = glh->list.tail;
-/*
- * Search backwards through the list for the first match with the
- * prefix string.
- */
- for( ; node &&
- (node->group != glh->group ||
- strncmp(glh->buffer + node->start, glh->prefix, glh->prefix_len) != 0);
- node = node->prev)
- ;
-/*
- * Was a matching line found?
- */
- if(node) {
-/*
- * Recall the found node as the starting point for subsequent
- * searches.
- */
- glh->recall = node;
-/*
- * Copy the matching line into the provided line buffer.
- */
- strncpy(line, glh->buffer + node->start, dim);
- line[dim-1] = '\0';
- return line;
- };
-/*
- * No match was found.
- */
- return NULL;
-}
-
-/*.......................................................................
- * Recall the next newest line that has the search prefix last recorded
- * by _glh_search_prefix().
- *
- * Input:
- * glh GlHistory * The input-line history maintenance object.
- * line char * The input line buffer. On input this should contain
- * the current input line, and on output, if anything
- * was found, its contents will have been replaced
- * with the matching line.
- * dim size_t The allocated dimensions of the line buffer.
- * Output:
- * return char * The line requested, or NULL if no matching line
- * was found.
- */
-char *_glh_find_forwards(GlHistory *glh, char *line, size_t dim)
-{
- GlLineNode *node; /* The line location node being checked */
-/*
- * Check the arguments.
- */
- if(!glh || !line) {
- fprintf(stderr, "_glh_find_forwards: NULL argument(s).\n");
- return NULL;
- };
-/*
- * Is history enabled?
- */
- if(!glh->enable || !glh->buffer || glh->max_lines == 0)
- return NULL;
-/*
- * Check the line dimensions.
- */
- if(dim < strlen(line) + 1) {
- fprintf(stderr,
- "_glh_find_forwards: 'dim' inconsistent with strlen(line) contents.\n");
- return NULL;
- };
-/*
- * From where should we start the search?
- */
- if(glh->recall)
- node = glh->recall->next;
- else
- return NULL;
-/*
- * If there is no search prefix, the prefix last set by glh_search_prefix()
- * doesn't exist in the history buffer.
- */
- if(!glh->prefix)
- return NULL;
-/*
- * Search forwards through the list for the first match with the
- * prefix string.
- */
- for( ; node &&
- (node->group != glh->group ||
- strncmp(glh->buffer + node->start, glh->prefix, glh->prefix_len) != 0);
- node = node->next)
- ;
-/*
- * Was a matching line found?
- */
- if(node) {
-/*
- * Did we hit the line that was originally being edited when the
- * current history traversal started?
- */
- if(node == glh->list.tail)
- return _glh_restore_line(glh, line, dim);
-/*
- * Copy the matching line into the provided line buffer.
- */
- strncpy(line, glh->buffer + node->start, dim);
- line[dim-1] = '\0';
-/*
- * Record the starting point of the next search.
- */
- glh->recall = node;
-/*
- * Return the matching line to the user.
- */
- return line;
- };
-/*
- * No match was found.
- */
- return NULL;
-}
-
-/*.......................................................................
- * If a search is in progress, cancel it.
- *
- * This involves discarding the line that was temporarily saved by
- * _glh_find_backwards() when the search was originally started,
- * and reseting the search iteration pointer to NULL.
- *
- * Input:
- * glh GlHistory * The input-line history maintenance object.
- * Output:
- * return int 0 - OK.
- * 1 - Error.
- */
-int _glh_cancel_search(GlHistory *glh)
-{
-/*
- * Check the arguments.
- */
- if(!glh) {
- fprintf(stderr, "_glh_cancel_search: NULL argument(s).\n");
- return 1;
- };
-/*
- * If there wasn't a search in progress, do nothing.
- */
- if(!glh->recall)
- return 0;
-/*
- * Delete the node of the preserved line.
- */
- _glh_discard_node(glh, glh->list.tail);
-/*
- * Reset the search pointers.
- */
- glh->recall = NULL;
- glh->prefix = "";
- glh->prefix_len = 0;
- return 0;
-}
-
-/*.......................................................................
- * Set the prefix of subsequent history searches.
- *
- * Input:
- * glh GlHistory * The input-line history maintenance object.
- * line char * The command line who's prefix is to be used.
- * prefix_len int The length of the prefix.
- * Output:
- * return int 0 - OK.
- * 1 - Error.
- */
-int _glh_search_prefix(GlHistory *glh, const char *line, int prefix_len)
-{
- GlLineNode *node; /* The line location node being checked */
-/*
- * Check the arguments.
- */
- if(!glh) {
- fprintf(stderr, "_glh_search_prefix: NULL argument(s).\n");
- return 1;
- };
-/*
- * Is history enabled?
- */
- if(!glh->enable || !glh->buffer || glh->max_lines == 0)
- return 0;
-/*
- * Record a zero length search prefix?
- */
- if(prefix_len <= 0) {
- glh->prefix_len = 0;
- glh->prefix = "";
- return 0;
- };
-/*
- * Record the length of the new search prefix.
- */
- glh->prefix_len = prefix_len;
-/*
- * If any history line starts with the specified prefix, record a
- * pointer to it for comparison in subsequent searches. If the prefix
- * doesn't match any of the lines, then simply record NULL to indicate
- * that there is no point in searching. Note that _glh_add_history()
- * clears this pointer by calling _glh_cancel_search(), so there is
- * no danger of it being used after the buffer has been modified.
- */
- for(node = glh->list.tail ; node &&
- (node->group != glh->group ||
- strncmp(glh->buffer + node->start, line, prefix_len) != 0);
- node = node->prev)
- ;
-/*
- * If a matching line was found record it for use as the search
- * prefix.
- */
- glh->prefix = node ? glh->buffer + node->start : NULL;
- return 0;
-}
-
-/*.......................................................................
- * Recall the oldest recorded line.
- *
- * Input:
- * glh GlHistory * The input-line history maintenance object.
- * line char * The input line buffer. On input this should contain
- * the current input line, and on output, its contents
- * will have been replaced with the oldest line.
- * dim size_t The allocated dimensions of the line buffer.
- * Output:
- * return char * A pointer to line[0], or NULL if not found.
- */
-char *_glh_oldest_line(GlHistory *glh, char *line, size_t dim)
-{
- GlLineNode *node; /* The line location node being checked */
- int first; /* True if this is the start of a new search */
-/*
- * Check the arguments.
- */
- if(!glh || !line) {
- fprintf(stderr, "_glh_oldest_line: NULL argument(s).\n");
- return NULL;
- };
-/*
- * Is history enabled?
- */
- if(!glh->enable || !glh->buffer || glh->max_lines == 0)
- return NULL;
-/*
- * Check the line dimensions.
- */
- if(dim < strlen(line) + 1) {
- fprintf(stderr,
- "_glh_oldest_line: 'dim' inconsistent with strlen(line) contents.\n");
- return NULL;
- };
-/*
- * Is this the start of a new search?
- */
- first = glh->recall==NULL;
-/*
- * If this is the first search backwards, save the current line
- * for potential recall later, and mark it as the last line
- * recalled.
- */
- if(first) {
- if(_glh_add_history(glh, line, 1))
- return NULL;
- glh->recall = glh->list.tail;
- };
-/*
- * Locate the oldest line that belongs to the current group.
- */
- for(node=glh->list.head; node && node->group != glh->group;
- node = node->next)
- ;
-/*
- * No line found?
- */
- if(!node)
- return NULL;
-/*
- * Record the above node as the starting point for subsequent
- * searches.
- */
- glh->recall = node;
-/*
- * Copy the recalled line into the provided line buffer.
- */
- strncpy(line, glh->buffer + node->start, dim);
- line[dim-1] = '\0';
- return line;
-}
-
-/*.......................................................................
- * Recall the line that was being entered when the search started.
- *
- * Input:
- * glh GlHistory * The input-line history maintenance object.
- * line char * The input line buffer. On input this should contain
- * the current input line, and on output, its contents
- * will have been replaced with the line that was
- * being entered when the search was started.
- * dim size_t The allocated dimensions of the line buffer.
- * Output:
- * return char * A pointer to line[0], or NULL if not found.
- */
-char *_glh_current_line(GlHistory *glh, char *line, size_t dim)
-{
-/*
- * Check the arguments.
- */
- if(!glh || !line) {
- fprintf(stderr, "_glh_current_line: NULL argument(s).\n");
- return NULL;
- };
-/*
- * Is history enabled?
- */
- if(!glh->enable || !glh->buffer || glh->max_lines == 0)
- return NULL;
-/*
- * Check the line dimensions.
- */
- if(dim < strlen(line) + 1) {
- fprintf(stderr,
- "_glh_current_line: 'dim' inconsistent with strlen(line) contents.\n");
- return NULL;
- };
-/*
- * Restore the original line.
- */
- return _glh_restore_line(glh, line, dim);
-}
-
-/*.......................................................................
- * Remove the line that was originally being edited when the history
- * traversal was started, from its saved position in the history list,
- * and place it in the provided line buffer.
- *
- * Input:
- * glh GlHistory * The input-line history maintenance object.
- * line char * The input line buffer. On input this should contain
- * the current input line, and on output, its contents
- * will have been replaced with the saved line.
- * dim size_t The allocated dimensions of the line buffer.
- * Output:
- * return char * A pointer to line[0], or NULL if not found.
- */
-static char *_glh_restore_line(GlHistory *glh, char *line, size_t dim)
-{
- GlLineNode *tail; /* The tail node to be discarded */
-/*
- * If there wasn't a search in progress, do nothing.
- */
- if(!glh->recall)
- return NULL;
-/*
- * Get the list node that is to be removed.
- */
- tail = glh->list.tail;
-/*
- * If a pointer to the saved line is being used to record the
- * current search prefix, reestablish the search prefix, to
- * have it recorded by another history line if possible.
- */
- if(glh->prefix == glh->buffer + tail->start)
- (void) _glh_search_prefix(glh, glh->buffer + tail->start, glh->prefix_len);
-/*
- * Copy the recalled line into the input-line buffer.
- */
- strncpy(line, glh->buffer + tail->start, dim);
- line[dim-1] = '\0';
-/*
- * Discard the line-location node.
- */
- _glh_discard_node(glh, tail);
-/*
- * Mark the search as ended.
- */
- glh->recall = NULL;
- return line;
-}
-
-/*.......................................................................
- * Query the id of a history line offset by a given number of lines from
- * the one that is currently being recalled. If a recall session isn't
- * in progress, or the offset points outside the history list, 0 is
- * returned.
- *
- * Input:
- * glh GlHistory * The input-line history maintenance object.
- * offset int The line offset (0 for the current line, < 0
- * for an older line, > 0 for a newer line.
- * Output:
- * return GlhLineID The identifier of the line that is currently
- * being recalled, or 0 if no recall session is
- * currently in progress.
- */
-GlhLineID _glh_line_id(GlHistory *glh, int offset)
-{
- GlLineNode *node; /* The line location node being checked */
-/*
- * Is history enabled?
- */
- if(!glh->enable || !glh->buffer || glh->max_lines == 0)
- return 0;
-/*
- * Search forward 'offset' lines to find the required line.
- */
- if(offset >= 0) {
- for(node=glh->recall; node && offset != 0; node=node->next) {
- if(node->group == glh->group)
- offset--;
- };
- } else {
- for(node=glh->recall; node && offset != 0; node=node->prev) {
- if(node->group == glh->group)
- offset++;
- };
- };
- return node ? node->id : 0;
-}
-
-/*.......................................................................
- * Recall a line by its history buffer ID. If the line is no longer
- * in the buffer, or the id is zero, NULL is returned.
- *
- * Input:
- * glh GlHistory * The input-line history maintenance object.
- * id GlhLineID The ID of the line to be returned.
- * line char * The input line buffer. On input this should contain
- * the current input line, and on output, its contents
- * will have been replaced with the saved line.
- * dim size_t The allocated dimensions of the line buffer.
- * Output:
- * return char * A pointer to line[0], or NULL if not found.
- */
-char *_glh_recall_line(GlHistory *glh, GlhLineID id, char *line, size_t dim)
-{
- GlLineNode *node; /* The line location node being checked */
-/*
- * Is history enabled?
- */
- if(!glh->enable || !glh->buffer || glh->max_lines == 0)
- return NULL;
-/*
- * If we are starting a new recall session, save the current line
- * for potential recall later.
- */
- if(!glh->recall && _glh_add_history(glh, line, 1))
- return NULL;
-/*
- * Search for the specified line.
- */
- node = _glh_find_id(glh, id);
-/*
- * Not found?
- */
- if(!node || node->group != glh->group)
- return NULL;
-/*
- * Record the node of the matching line as the starting point
- * for subsequent searches.
- */
- glh->recall = node;
-/*
- * Copy the recalled line into the provided line buffer.
- */
- strncpy(line, glh->buffer + node->start, dim);
- line[dim-1] = '\0';
- return line;
-}
-
-/*.......................................................................
- * Save the current history in a specified file.
- *
- * Input:
- * glh GlHistory * The input-line history maintenance object.
- * filename const char * The name of the new file to record the
- * history in.
- * comment const char * Extra information such as timestamps will
- * be recorded on a line started with this
- * string, the idea being that the file can
- * double as a command file. Specify "" if
- * you don't care.
- * max_lines int The maximum number of lines to save, or -1
- * to save all of the lines in the history
- * list.
- * Output:
- * return int 0 - OK.
- * 1 - Error.
- */
-int _glh_save_history(GlHistory *glh, const char *filename, const char *comment,
- int max_lines)
-{
- FILE *fp; /* The output file */
- GlLineNode *node; /* The line being saved */
- GlLineNode *head; /* The head of the list of lines to be saved */
-/*
- * Check the arguments.
- */
- if(!glh || !filename || !comment) {
- fprintf(stderr, "_glh_save_history: NULL argument(s).\n");
- return 1;
- };
-/*
- * Attempt to open the specified file.
- */
- fp = fopen(filename, "w");
- if(!fp) {
- fprintf(stderr, "_glh_save_history: Can't open %s (%s).\n",
- filename, strerror(errno));
- return 1;
- };
-/*
- * If a ceiling on the number of lines to save was specified, count
- * that number of lines backwards, to find the first line to be saved.
- */
- head = NULL;
- if(max_lines >= 0) {
- for(head=glh->list.tail; head && --max_lines > 0; head=head->prev)
- ;
- };
- if(!head)
- head = glh->list.head;
-/*
- * Write the contents of the history buffer to the history file, writing
- * associated data such as timestamps, to a line starting with the
- * specified comment string.
- */
- for(node=head; node; node=node->next) {
-/*
- * Write peripheral information associated with the line, as a comment.
- */
- if(fprintf(fp, "%s ", comment) < 0 ||
- _glh_write_timestamp(fp, node->timestamp) ||
- fprintf(fp, " %u\n", node->group) < 0) {
- fprintf(stderr, "Error writing %s (%s).\n", filename, strerror(errno));
- (void) fclose(fp);
- return 1;
- };
-/*
- * Write the history line.
- */
- if(fprintf(fp, "%s\n", glh->buffer + node->start) < 0) {
- fprintf(stderr, "Error writing %s (%s).\n", filename, strerror(errno));
- (void) fclose(fp);
- return 1;
- };
- };
-/*
- * Close the history file.
- */
- if(fclose(fp) == EOF) {
- fprintf(stderr, "Error writing %s (%s).\n", filename, strerror(errno));
- return 1;
- };
- return 0;
-}
-
-/*.......................................................................
- * Restore previous history lines from a given file.
- *
- * Input:
- * glh GlHistory * The input-line history maintenance object.
- * filename const char * The name of the file to read from.
- * comment const char * The same comment string that was passed to
- * _glh_save_history() when this file was
- * written.
- * line char * A buffer into which lines can be read.
- * dim size_t The allocated dimension of line[].
- * Output:
- * return int 0 - OK.
- * 1 - Error.
- */
-int _glh_load_history(GlHistory *glh, const char *filename, const char *comment,
- char *line, size_t dim)
-{
- FILE *fp; /* The output file */
- size_t comment_len; /* The length of the comment string */
- time_t timestamp; /* The timestamp of the history line */
- unsigned group; /* The identifier of the history group to which */
- /* the line belongs. */
- int lineno; /* The line number being read */
-/*
- * Check the arguments.
- */
- if(!glh || !filename || !comment || !line) {
- fprintf(stderr, "_glh_load_history: NULL argument(s).\n");
- return 1;
- };
-/*
- * Measure the length of the comment string.
- */
- comment_len = strlen(comment);
-/*
- * Clear the history list.
- */
- _glh_clear_history(glh, 1);
-/*
- * Attempt to open the specified file. Don't treat it as an error
- * if the file doesn't exist.
- */
- fp = fopen(filename, "r");
- if(!fp)
- return 0;
-/*
- * Attempt to read each line and preceding peripheral info, and add these
- * to the history list.
- */
- for(lineno=1; fgets(line, dim, fp) != NULL; lineno++) {
- char *lptr; /* A pointer into the input line */
-/*
- * Check that the line starts with the comment string.
- */
- if(strncmp(line, comment, comment_len) != 0) {
- return _glh_cant_load_history(glh, filename, lineno,
- "Corrupt history parameter line", fp);
- };
-/*
- * Skip spaces and tabs after the comment.
- */
- for(lptr=line+comment_len; *lptr && (*lptr==' ' || *lptr=='\t'); lptr++)
- ;
-/*
- * The next word must be a timestamp.
- */
- if(_glh_decode_timestamp(lptr, &lptr, &timestamp)) {
- return _glh_cant_load_history(glh, filename, lineno,
- "Corrupt timestamp", fp);
- };
-/*
- * Skip spaces and tabs.
- */
- while(*lptr==' ' || *lptr=='\t')
- lptr++;
-/*
- * The next word must be an unsigned integer group number.
- */
- group = (int) strtoul(lptr, &lptr, 10);
- if(*lptr != ' ' && *lptr != '\n') {
- return _glh_cant_load_history(glh, filename, lineno,
- "Corrupt group id", fp);
- };
-/*
- * Skip spaces and tabs.
- */
- while(*lptr==' ' || *lptr=='\t')
- lptr++;
-/*
- * There shouldn't be anything left on the line.
- */
- if(*lptr != '\n') {
- return _glh_cant_load_history(glh, filename, lineno,
- "Corrupt parameter line", fp);
- };
-/*
- * Now read the history line itself.
- */
- lineno++;
- if(fgets(line, dim, fp) == NULL)
- return _glh_cant_load_history(glh, filename, lineno, "Read error", fp);
-/*
- * Append the line to the history buffer.
- */
- if(_glh_add_history(glh, line, 1)) {
- return _glh_cant_load_history(glh, filename, lineno,
- "Insufficient memory to record line", fp);
- };
-/*
- * Record the group and timestamp information along with the line.
- */
- if(glh->list.tail) {
- glh->list.tail->timestamp = timestamp;
- glh->list.tail->group = group;
- };
- };
-/*
- * Close the file.
- */
- (void) fclose(fp);
- return 0;
-}
-
-/*.......................................................................
- * This is a private error return function of _glh_load_history().
- */
-static int _glh_cant_load_history(GlHistory *glh, const char *filename,
- int lineno, const char *message, FILE *fp)
-{
- fprintf(stderr, "%s:%d: %s.\n", filename, lineno, message);
- (void) fclose(fp);
- return 1;
-}
-
-/*.......................................................................
- * Switch history groups.
- *
- * Input:
- * glh GlHistory * The input-line history maintenance object.
- * group unsigned The new group identifier. This will be recorded
- * with subsequent history lines, and subsequent
- * history searches will only return lines with
- * this group identifier. This allows multiple
- * separate history lists to exist within
- * a single GlHistory object. Note that the
- * default group identifier is 0.
- * Output:
- * return int 0 - OK.
- * 1 - Error.
- */
-int _glh_set_group(GlHistory *glh, unsigned group)
-{
-/*
- * Check the arguments.
- */
- if(!glh) {
- fprintf(stderr, "_glh_set_group: NULL argument(s).\n");
- return 1;
- };
-/*
- * Is the group being changed?
- */
- if(group != glh->group) {
-/*
- * Cancel any ongoing search.
- */
- if(_glh_cancel_search(glh))
- return 1;
-/*
- * Record the new group.
- */
- glh->group = group;
- };
- return 0;
-}
-
-/*.......................................................................
- * Query the current history group.
- *
- * Input:
- * glh GlHistory * The input-line history maintenance object.
- * Output:
- * return unsigned The group identifier.
- */
-int _glh_get_group(GlHistory *glh)
-{
- return glh ? glh->group : 0;
-}
-
-/*.......................................................................
- * Write a timestamp to a given stdio stream, in the format
- * yyyymmddhhmmss
- *
- * Input:
- * fp FILE * The stream to write to.
- * timestamp time_t The timestamp to be written.
- * Output:
- * return int 0 - OK.
- * 1 - Error.
- */
-static int _glh_write_timestamp(FILE *fp, time_t timestamp)
-{
- struct tm *t; /* THe broken-down calendar time */
-/*
- * Get the calendar components corresponding to the given timestamp.
- */
- if(timestamp < 0 || (t = localtime(&timestamp)) == NULL) {
- if(fprintf(fp, "?") < 0)
- return 1;
- return 0;
- };
-/*
- * Write the calendar time as yyyymmddhhmmss.
- */
- if(fprintf(fp, "%04d%02d%02d%02d%02d%02d", t->tm_year + 1900, t->tm_mon + 1,
- t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec) < 0)
- return 1;
- return 0;
-}
-
-/*.......................................................................
- * Read a timestamp from a string.
- *
- * Input:
- * string char * The string to read from.
- * Input/Output:
- * endp char ** On output *endp will point to the next unprocessed
- * character in string[].
- * timestamp time_t * The timestamp will be assigned to *t.
- * Output:
- * return int 0 - OK.
- * 1 - Error.
- */
-static int _glh_decode_timestamp(char *string, char **endp, time_t *timestamp)
-{
- unsigned year,month,day,hour,min,sec; /* Calendar time components */
- struct tm t;
-/*
- * There are 14 characters in the date format yyyymmddhhmmss.
- */
- enum {TSLEN=14};
- char timestr[TSLEN+1]; /* The timestamp part of the string */
-/*
- * If the time wasn't available at the time that the line was recorded
- * it will have been written as "?". Check for this before trying
- * to read the timestamp.
- */
- if(string[0] == '\?') {
- *endp = string+1;
- *timestamp = -1;
- return 0;
- };
-/*
- * The timestamp is expected to be written in the form yyyymmddhhmmss.
- */
- if(strlen(string) < TSLEN) {
- *endp = string;
- return 1;
- };
-/*
- * Copy the timestamp out of the string.
- */
- strncpy(timestr, string, TSLEN);
- timestr[TSLEN] = '\0';
-/*
- * Decode the timestamp.
- */
- if(sscanf(timestr, "%4u%2u%2u%2u%2u%2u", &year, &month, &day, &hour, &min,
- &sec) != 6) {
- *endp = string;
- return 1;
- };
-/*
- * Advance the string pointer over the successfully read timestamp.
- */
- *endp = string + TSLEN;
-/*
- * Copy the read values into a struct tm.
- */
- t.tm_sec = sec;
- t.tm_min = min;
- t.tm_hour = hour;
- t.tm_mday = day;
- t.tm_wday = 0;
- t.tm_yday = 0;
- t.tm_mon = month - 1;
- t.tm_year = year - 1900;
- t.tm_isdst = -1;
-/*
- * Convert the contents of the struct tm to a time_t.
- */
- *timestamp = mktime(&t);
- return 0;
-}
-
-/*.......................................................................
- * Display the contents of the history list.
- *
- * Input:
- * glh GlHistory * The input-line history maintenance object.
- * fp FILE * The stdio stream to write to.
- * fmt const char * A format string. This can contain arbitrary
- * characters, which are written verbatim, plus
- * any of the following format directives:
- * %D - The date, like 2001-11-20
- * %T - The time of day, like 23:59:59
- * %N - The sequential entry number of the
- * line in the history buffer.
- * %G - The history group number of the line.
- * %% - A literal % character.
- * %H - The history line.
- * all_groups int If true, display history lines from all
- * history groups. Otherwise only display
- * those of the current history group.
- * max_lines int If max_lines is < 0, all available lines
- * are displayed. Otherwise only the most
- * recent max_lines lines will be displayed.
- * Output:
- * return int 0 - OK.
- * 1 - Error.
- */
-int _glh_show_history(GlHistory *glh, FILE *fp, const char *fmt,
- int all_groups, int max_lines)
-{
- GlLineNode *node; /* The line being displayed */
- GlLineNode *oldest; /* The oldest line to display */
- enum {TSMAX=32}; /* The maximum length of the date and time string */
- char buffer[TSMAX+1]; /* The buffer in which to write the date and time */
- int idlen; /* The length of displayed ID strings */
- unsigned grpmax; /* The maximum group number in the buffer */
- int grplen; /* The number of characters needed to print grpmax */
-/*
- * Check the arguments.
- */
- if(!glh || !fp || !fmt) {
- fprintf(stderr, "_glh_show_history: NULL argument(s).\n");
- return 1;
- };
-/*
- * Is history enabled?
- */
- if(!glh->enable || !glh->list.head)
- return 0;
-/*
- * Work out the length to display ID numbers, choosing the length of
- * the biggest number in the buffer. Smaller numbers will be padded
- * with leading zeroes if needed.
- */
- sprintf(buffer, "%lu", (unsigned long) glh->list.tail->id);
- idlen = strlen(buffer);
-/*
- * Find the largest group number.
- */
- grpmax = 0;
- for(node=glh->list.head; node; node=node->next) {
- if(node->group > grpmax)
- grpmax = node->group;
- };
-/*
- * Find out how many characters are needed to display the group number.
- */
- sprintf(buffer, "%u", (unsigned) grpmax);
- grplen = strlen(buffer);
-/*
- * Find the node that follows the oldest line to be displayed.
- */
- if(max_lines < 0) {
- oldest = glh->list.head;
- } else if(max_lines==0) {
- return 0;
- } else {
- for(oldest=glh->list.tail; oldest; oldest=oldest->prev) {
- if((all_groups || oldest->group == glh->group) && --max_lines <= 0)
- break;
- };
-/*
- * If the number of lines in the buffer doesn't exceed the specified
- * maximum, start from the oldest line in the buffer.
- */
- if(!oldest)
- oldest = glh->list.head;
- };
-/*
- * List the history lines in increasing time order.
- */
- for(node=oldest; node; node=node->next) {
-/*
- * Only display lines from the current history group, unless
- * told otherwise.
- */
- if(all_groups || node->group == glh->group) {
- const char *fptr; /* A pointer into the format string */
- struct tm *t = NULL; /* The broken time version of the timestamp */
-/*
- * Work out the calendar representation of the node timestamp.
- */
- if(node->timestamp != (time_t) -1)
- t = localtime(&node->timestamp);
-/*
- * Parse the format string.
- */
- fptr = fmt;
- while(*fptr) {
-/*
- * Search for the start of the next format directive or the end of the string.
- */
- const char *start = fptr;
- while(*fptr && *fptr != '%')
- fptr++;
-/*
- * Display any literal characters that precede the located directive.
- */
- if(fptr > start && fprintf(fp, "%.*s", (int) (fptr - start), start) < 0)
- return 1;
-/*
- * Did we hit a new directive before the end of the line?
- */
- if(*fptr) {
-/*
- * Obey the directive. Ignore unknown directives.
- */
- switch(*++fptr) {
- case 'D': /* Display the date */
- if(t && strftime(buffer, TSMAX, "%Y-%m-%d", t) != 0 &&
- fprintf(fp, "%s", buffer) < 0)
- return 1;
- break;
- case 'T': /* Display the time of day */
- if(t && strftime(buffer, TSMAX, "%H:%M:%S", t) != 0 &&
- fprintf(fp, "%s", buffer) < 0)
- return 1;
- break;
- case 'N': /* Display the sequential entry number */
- if(fprintf(fp, "%*lu", idlen, (unsigned long) node->id) < 0)
- return 1;
- break;
- case 'G':
- if(fprintf(fp, "%*u", grplen, (unsigned) node->group) < 0)
- return 1;
- break;
- case 'H': /* Display the history line */
- if(fprintf(fp, "%s", glh->buffer + node->start) < 0)
- return 1;
- break;
- case '%': /* A literal % symbol */
- if(fputc('%', fp) == EOF)
- return 1;
- break;
- };
-/*
- * Skip the directive.
- */
- if(*fptr)
- fptr++;
- };
- };
- };
- };
- return 0;
-}
-
-/*.......................................................................
- * Change the size of the history buffer.
- *
- * Input:
- * glh GlHistory * The input-line history maintenance object.
- * bufsize size_t The number of bytes in the history buffer, or 0
- * to delete the buffer completely.
- * Output:
- * return int 0 - OK.
- * 1 - Insufficient memory (the previous buffer
- * will have been retained). No error message
- * will be displayed.
- */
-int _glh_resize_history(GlHistory *glh, size_t bufsize)
-{
- GlLineNode *node; /* A line location node in the list of lines */
- GlLineNode *prev; /* The line location node preceding 'node' */
-/*
- * Check the arguments.
- */
- if(!glh)
- return bufsize > 0;
-/*
- * If the new size doesn't differ from the existing size, do nothing.
- */
- if(glh->buflen == bufsize)
- return 0;
-/*
- * Cancel any ongoing search.
- */
- (void) _glh_cancel_search(glh);
-/*
- * Create a wholly new buffer?
- */
- if(glh->buflen == 0) {
- glh->buffer = (char *) malloc(bufsize);
- if(!glh->buffer)
- return 1;
- glh->buflen = bufsize;
-/*
- * Delete an existing buffer?
- */
- } else if(bufsize == 0) {
- _glh_clear_history(glh, 1);
- free(glh->buffer);
- glh->buffer = NULL;
- glh->buflen = 0;
-/*
- * To get here, we must be shrinking or expanding from one
- * finite size to another.
- */
- } else {
-/*
- * If we are shrinking the size of the buffer, then we first need
- * to discard the oldest lines that won't fit in the new buffer.
- */
- if(bufsize < glh->buflen) {
- size_t nbytes = 0; /* The number of bytes used in the new buffer */
- GlLineNode *oldest; /* The oldest node to be kept */
-/*
- * Searching backwards from the youngest line, find the oldest
- * line for which there will be sufficient room in the new buffer.
- */
- for(oldest = glh->list.tail;
- oldest && (nbytes += oldest->nchar) <= bufsize;
- oldest = oldest->prev)
- ;
-/*
- * We will have gone one node too far, unless we reached the oldest line
- * without exceeding the target length.
- */
- if(oldest) {
- nbytes -= oldest->nchar;
- oldest = oldest->next;
- };
-/*
- * Discard the nodes that can't be retained.
- */
- while(glh->list.head && glh->list.head != oldest)
- _glh_discard_node(glh, glh->list.head);
-/*
- * If we are increasing the size of the buffer, we need to reallocate
- * the buffer before shifting the lines into their new positions.
- */
- } else {
- char *new_buffer = (char *) realloc(glh->buffer, bufsize);
- if(!new_buffer)
- return 1;
- glh->buffer = new_buffer;
- glh->buflen = bufsize;
- };
-/*
- * If there are any lines to be preserved, copy the block of lines
- * that precedes the end of the existing buffer to what will be
- * the end of the new buffer.
- */
- if(glh->list.head) {
- int shift; /* The number of bytes to shift lines in the buffer */
-/*
- * Get the oldest line to be kept.
- */
- GlLineNode *oldest = glh->list.head;
-/*
- * Count the number of characters that are used in the lines that
- * precede the end of the current buffer (ie. not including those
- * lines that have been wrapped to the start of the buffer).
- */
- int n = 0;
- for(node=oldest,prev=oldest->prev; node && node->start >= oldest->start;
- prev=node, node=node->next)
- n += node->nchar;
-/*
- * Move these bytes to the end of the resized buffer.
- */
- memmove(glh->buffer + bufsize - n, glh->buffer + oldest->start, n);
-/*
- * Adjust the buffer pointers to reflect the new locations of the moved
- * lines.
- */
- shift = bufsize - n - oldest->start;
- for(node=prev; node && node->start >= oldest->start; node=node->prev)
- node->start += shift;
- };
-/*
- * Shrink the buffer?
- */
- if(bufsize < glh->buflen) {
- char *new_buffer = (char *) realloc(glh->buffer, bufsize);
- if(new_buffer)
- glh->buffer = new_buffer;
- glh->buflen = bufsize; /* Mark it as shrunk, regardless of success */
- };
- };
- return 0;
-}
-
-/*.......................................................................
- * Set an upper limit to the number of lines that can be recorded in the
- * history list, or remove a previously specified limit.
- *
- * Input:
- * glh GlHistory * The input-line history maintenance object.
- * max_lines int The maximum number of lines to allow, or -1 to
- * cancel a previous limit and allow as many lines
- * as will fit in the current history buffer size.
- */
-void _glh_limit_history(GlHistory *glh, int max_lines)
-{
- if(!glh)
- return;
-/*
- * Apply a new limit?
- */
- if(max_lines >= 0 && max_lines != glh->max_lines) {
-/*
- * Count successively older lines until we reach the start of the
- * list, or until we have seen max_lines lines (at which point 'node'
- * will be line number max_lines+1).
- */
- int nline = 0;
- GlLineNode *node;
- for(node=glh->list.tail; node && ++nline <= max_lines; node=node->prev)
- ;
-/*
- * Discard any lines that exceed the limit.
- */
- if(node) {
- GlLineNode *oldest = node->next; /* The oldest line to be kept */
-/*
- * Delete nodes from the head of the list until we reach the node that
- * is to be kept.
- */
- while(glh->list.head && glh->list.head != oldest)
- _glh_discard_node(glh, glh->list.head);
- };
- };
-/*
- * Record the new limit.
- */
- glh->max_lines = max_lines;
- return;
-}
-
-/*.......................................................................
- * Discard either all history, or the history associated with the current
- * history group.
- *
- * Input:
- * glh GlHistory * The input-line history maintenance object.
- * all_groups int If true, clear all of the history. If false,
- * clear only the stored lines associated with the
- * currently selected history group.
- */
-void _glh_clear_history(GlHistory *glh, int all_groups)
-{
-/*
- * Check the arguments.
- */
- if(!glh)
- return;
-/*
- * Cancel any ongoing search.
- */
- (void) _glh_cancel_search(glh);
-/*
- * Delete all history lines regardless of group?
- */
- if(all_groups) {
- _rst_FreeList(glh->list.node_mem);
- glh->list.head = glh->list.tail = NULL;
- glh->nline = 0;
- glh->id_node = NULL;
-/*
- * Just delete lines of the current group?
- */
- } else {
- GlLineNode *node; /* The line node being checked */
- GlLineNode *prev; /* The line node that precedes 'node' */
- GlLineNode *next; /* The line node that follows 'node' */
-/*
- * Search out and delete the line nodes of the current group.
- */
- for(node=glh->list.head; node; node=next) {
-/*
- * Keep a record of the following node before we delete the current
- * node.
- */
- next = node->next;
-/*
- * Discard this node?
- */
- if(node->group == glh->group)
- _glh_discard_node(glh, node);
- };
-/*
- * If there are any lines left, and we deleted any lines, there will
- * be gaps in the buffer. These need to be removed.
- */
- if(glh->list.head) {
- int epos; /* The index of the last used element in the buffer */
-/*
- * Find the line nearest the end of the buffer.
- */
- GlLineNode *enode;
- for(node=glh->list.head, prev=NULL;
- node && node->start >= glh->list.head->start;
- prev=node, node = node->next)
- ;
- enode = prev;
-/*
- * Move the end line to abutt the end of the buffer, and remove gaps
- * between the lines that precede it.
- */
- epos = glh->buflen;
- for(node=enode; node; node=node->prev) {
- int shift = epos - (node->start + node->nchar);
- if(shift) {
- memmove(glh->buffer + node->start + shift,
- glh->buffer + node->start, node->nchar);
- node->start += shift;
- };
- epos = node->start;
- };
-/*
- * Move the first line in the buffer to the start of the buffer, and
- * remove gaps between the lines that follow it.
- */
- epos = 0;
- for(node=enode ? enode->next : NULL; node; node=node->next) {
- int shift = epos - node->start;
- if(shift) {
- memmove(glh->buffer + node->start + shift,
- glh->buffer + node->start, node->nchar);
- node->start += shift;
- };
- epos = node->start + node->nchar;
- };
- };
- };
- return;
-}
-
-/*.......................................................................
- * Temporarily enable or disable the history list.
- *
- * Input:
- * glh GlHistory * The input-line history maintenance object.
- * enable int If true, turn on the history mechanism. If
- * false, disable it.
- */
-void _glh_toggle_history(GlHistory *glh, int enable)
-{
- if(glh)
- glh->enable = enable;
-}
-
-/*.......................................................................
- * Remove a given line location node from the history list, and return
- * it to the freelist.
- *
- * Input:
- * glh GlHistory * The input-line history maintenance object.
- * node GlLineNode * The node to be removed. This must be currently
- * in the list who's head is glh->list.head, or
- * be NULL.
- */
-static void _glh_discard_node(GlHistory *glh, GlLineNode *node)
-{
- if(node) {
-/*
- * Make the node that precedes the node being removed point
- * to the one that follows it.
- */
- if(node->prev)
- node->prev->next = node->next;
- else
- glh->list.head = node->next;
-/*
- * Make the node that follows the node being removed point
- * to the one that precedes it.
- */
- if(node->next)
- node->next->prev = node->prev;
- else
- glh->list.tail = node->prev;
-/*
- * If we are deleting the node that is marked as the start point of the
- * last ID search, remove the cached starting point.
- */
- if(node == glh->id_node)
- glh->id_node = NULL;
-/*
- * Return the node to the free list.
- */
- node = (GlLineNode *) _del_FreeListNode(glh->list.node_mem, node);
-/*
- * Decrement the count of the number of lines in the buffer.
- */
- glh->nline--;
- };
-}
-
-/*.......................................................................
- * Lookup the details of a given history line, given its id.
- *
- * Input:
- * glh GlHistory * The input-line history maintenance object.
- * id GlLineID The sequential number of the line.
- * Input/Output:
- * line const char ** A pointer to the history line will be assigned
- * to *line.
- * group unsigned * The group membership of the line will be assigned
- * to *group.
- * timestamp time_t * The timestamp of the line will be assigned to
- * *timestamp.
- * Output:
- * return int 0 - The requested line wasn't found.
- * 1 - The line was found.
- */
-int _glh_lookup_history(GlHistory *glh, GlhLineID id, const char **line,
- unsigned *group, time_t *timestamp)
-{
- GlLineNode *node; /* The located line location node */
-/*
- * Check the arguments.
- */
- if(!glh)
- return 0;
-/*
- * Search for the line that has the specified ID.
- */
- node = _glh_find_id(glh, (GlhLineID) id);
-/*
- * Not found?
- */
- if(!node)
- return 0;
-/*
- * Return the details of the line.
- */
- if(line)
- *line = glh->buffer + node->start;
- if(group)
- *group = node->group;
- if(timestamp)
- *timestamp = node->timestamp;
- return 1;
-}
-
-/*.......................................................................
- * Lookup a node in the history list by its ID.
- *
- * Input:
- * glh GlHistory * The input-line history maintenance object.
- * id GlhLineID The ID of the line to be returned.
- * Output:
- * return GlLIneNode * The located node, or NULL if not found.
- */
-static GlLineNode *_glh_find_id(GlHistory *glh, GlhLineID id)
-{
- GlLineNode *node; /* The node being checked */
-/*
- * Is history enabled?
- */
- if(!glh->enable || !glh->list.head)
- return NULL;
-/*
- * If possible, start at the end point of the last ID search.
- * Otherwise start from the head of the list.
- */
- node = glh->id_node;
- if(!node)
- node = glh->list.head;
-/*
- * Search forwards from 'node'?
- */
- if(node->id < id) {
- while(node && node->id != id)
- node = node->next;
- glh->id_node = node ? node : glh->list.tail;
-/*
- * Search backwards from 'node'?
- */
- } else {
- while(node && node->id != id)
- node = node->prev;
- glh->id_node = node ? node : glh->list.head;
- };
-/*
- * Return the located node (this will be NULL if the ID wasn't found).
- */
- return node;
-}
-
-/*.......................................................................
- * Query the state of the history list. Note that any of the input/output
- * pointers can be specified as NULL.
- *
- * Input:
- * glh GlHistory * The input-line history maintenance object.
- * Input/Output:
- * enabled int * If history is enabled, *enabled will be
- * set to 1. Otherwise it will be assigned 0.
- * group unsigned * The current history group ID will be assigned
- * to *group.
- * max_lines int * The currently requested limit on the number
- * of history lines in the list, or -1 if
- * unlimited.
- */
-void _glh_state_of_history(GlHistory *glh, int *enabled, unsigned *group,
- int *max_lines)
-{
- if(glh) {
- if(enabled)
- *enabled = glh->enable;
- if(group)
- *group = glh->group;
- if(max_lines)
- *max_lines = glh->max_lines;
- };
-}
-
-/*.......................................................................
- * Get the range of lines in the history buffer.
- *
- * Input:
- * glh GlHistory * The input-line history maintenance object.
- * Input/Output:
- * oldest unsigned long * The sequential entry number of the oldest
- * line in the history list will be assigned
- * to *oldest, unless there are no lines, in
- * which case 0 will be assigned.
- * newest unsigned long * The sequential entry number of the newest
- * line in the history list will be assigned
- * to *newest, unless there are no lines, in
- * which case 0 will be assigned.
- * nlines int * The number of lines currently in the history
- * list.
- */
-void _glh_range_of_history(GlHistory *glh, unsigned long *oldest,
- unsigned long *newest, int *nlines)
-{
- if(glh) {
- if(oldest)
- *oldest = glh->list.head ? glh->list.head->id : 0;
- if(newest)
- *newest = glh->list.tail ? glh->list.tail->id : 0;
- if(nlines)
- *nlines = glh->nline;
- };
-}
-
-/*.......................................................................
- * Return the size of the history buffer and the amount of the
- * buffer that is currently in use.
- *
- * Input:
- * glh GlHistory * The input-line history maintenance object.
- * Input/Output:
- * buff_size size_t * The size of the history buffer (bytes).
- * buff_used size_t * The amount of the history buffer that
- * is currently occupied (bytes).
- */
-void _glh_size_of_history(GlHistory *glh, size_t *buff_size, size_t *buff_used)
-{
- if(glh) {
- if(buff_size)
- *buff_size = glh->buflen;
-/*
- * Determine the amount of buffer space that is currently occupied.
- */
- if(buff_used) {
- size_t used = 0;
- GlLineNode *node;
- for(node=glh->list.head; node; node=node->next)
- used += node->nchar;
- *buff_used = used;
- };
- };
-}
diff --git a/libtecla-1.4.1/html/cpl_complete_word.html b/libtecla-1.4.1/html/cpl_complete_word.html
deleted file mode 100644
index 063359d..0000000
--- a/libtecla-1.4.1/html/cpl_complete_word.html
+++ /dev/null
@@ -1,423 +0,0 @@
-<head>
-<title>Manual Page</title>
-</head>
-<body>
-<pre>
-</pre><h2>NAME</h2><pre>
- cpl_complete_word, cfc_file_start, cfc_literal_escapes,
- cfc_set_check_fn, cpl_add_completion, cpl_file_completions,
- cpl_last_error, cpl_list_completions, cpl_record_error,
- del_CplFileConf, del_WordCompletion, new_CplFileConf,
- new_WordCompletion - lookup possible completions for a word
-
-</pre><h2>SYNOPSIS</h2><pre>
- #include &lt;stdio.h&gt;
- #include &lt;libtecla.h&gt;
-
- WordCompletion *new_WordCompletion(void);
-
- WordCompletion *del_WordCompletion(WordCompletion *cpl);
-
- #define CPL_MATCH_FN(fn) int (fn)(WordCompletion *cpl, \
- void *data, \
- const char *line, \
- int word_end)
- typedef CPL_MATCH_FN(CplMatchFn);
-
- CPL_MATCH_FN(cpl_file_completions);
-
- CplMatches *cpl_complete_word(WordCompletion *cpl,
- const char *line,
- int word_end, void *data,
- CplMatchFn *match_fn);
-
- int cpl_list_completions(CplMatches *result, FILE *fp,
- int term_width);
-
- int cpl_add_completion(WordCompletion *cpl,
- const char *line, int word_start,
- int word_end, const char *suffix,
- const char *type_suffix,
- const char *cont_suffix);
-
- void cpl_record_error(WordCompletion *cpl,
- const char *errmsg);
-
- const char *cpl_last_error(WordCompletion *cpl);
-
-
-
-</pre><h2>DESCRIPTION</h2><pre>
- The cpl_complete_word() function is part of the tecla
- library (see the <a href="libtecla.html">libtecla(3)</a> man page). It is usually called
- behind the scenes by <a href="gl_get_line.html">gl_get_line(3)</a>, but can also be called
- separately.
-
- Given an input line containing an incomplete word to be com-
- pleted, it calls a user-provided callback function (or the
- provided file-completion callback function) to look up all
- possible completion suffixes for that word. The callback
- function is expected to look backward in the line, starting
- from the specified cursor position, to find the start of the
- word to be completed, then to look up all possible comple-
- tions of that word and record them, one at a time by calling
- cpl_add_completion().
-
-
- Descriptions of the functions of this module are as follows:
-
- CompleteWord *new_CompleteWord(void)
-
- This function creates the resources used by the
- cpl_complete_word() function. In particular, it maintains
- the memory that is used to return the results of calling
- cpl_complete_word().
-
- CompleteWord *del_CompleteWord(CompleteWord *cpl)
-
- This function deletes the resources that were returned by a
- previous call to new_CompleteWord(). It always returns NULL
- (ie. a deleted object). It does nothing if the cpl argument
- is NULL.
-
- The callback functions which lookup possible completions
- should be defined with the following macro (which is defined
- in libtecla.h).
-
- #define CPL_MATCH_FN(fn) int (fn)(WordCompletion *cpl, \
- void *data, \
- const char *line, \
- int word_end)
-
- Functions of this type are called by cpl_complete_word(),
- and all of the arguments of the callback are those that were
- passed to said function. In particular, the line argument
- contains the input line containing the word to be completed,
- and word_end is the index of the character that follows the
- last character of the incomplete word within this string.
- The callback is expected to look backwards from word_end for
- the start of the incomplete word. What constitutes the start
- of a word clearly depends on the application, so it makes
- sense for the callback to take on this responsibility. For
- example, the builtin filename completion function looks
- backwards until it hits an unescaped space, or the start of
- the line. Having found the start of the word, the callback
- should then lookup all possible completions of this word,
- and record each completion via separate calls to
- cpl_add_completion(). If the callback needs access to an
- application-specific symbol table, it can pass it and any
- other data that it needs, via the data argument. This
- removes any need for globals.
-
- The callback function should return 0 if no errors occur. On
- failure it should return 1, and register a terse description
- of the error by calling cpl_record_error().
-
- void cpl_record_error(WordCompletion *cpl,
- const char *errmsg);
-
- The last error message recorded by calling
- cpl_record_error(), can subsequently be queried by calling
- cpl_last_error(), as described later.
-
- int cpl_add_completion(WordCompletion *cpl,
- const char *line, int word_start,
- int word_end, const char *suffix,
- const char *type_suffix,
- const char *cont_suffix);
-
- The cpl_add_completion() function is called zero or more
- times by the completion callback function to record each
- possible completion in the specified WordCompletion object.
- These completions are subsequently returned by
- cpl_complete_word(), as described later. The cpl, line, and
- word_end arguments should be those that were passed to the
- callback function. The word_start argument should be the
- index within the input line string of the start of the word
- that is being completed. This should equal word_end if a
- zero-length string is being completed. The suffix argument
- is the string that would have to be appended to the incom-
- plete word to complete it. If this needs any quoting (eg.
- the addition of backslashes before special charaters) to be
- valid within the displayed input line, this should be
- included. A copy of the suffix string is allocated inter-
- nally, so there is no need to maintain your copy of the
- string after cpl_add_completion() returns.
-
- Note that in the array of possible completions which the
- cpl_complete_word() function returns, the suffix recorded by
- cpl_add_completion() is listed along with the concatentation
- of this suffix with the word that lies between word_start
- and word_end in the input line.
-
- The type_suffix argument specifies an optional string to be
- appended to the completion if it is displayed as part of a
- list of completions by cpl_list_completions(). The intention
- is that this indicate to the user the type of each comple-
- tion. For example, the file completion function places a
- directory separator after completions that are directories,
- to indicate their nature to the user. Similary, if the com-
- pletion were a function, you could indicate this to the user
- by setting type_suffix to "()". Note that the type_suffix
- string isn't copied, so if the argument isn't a literal
- string between speech marks, be sure that the string remains
- valid for at least as long as the results of
- cpl_complete_word() are needed.
-
- The cont_suffix is a continuation suffix to append to the
- completed word in the input line if this is the only comple-
- tion. This is something that isn't part of the completion
- itself, but that gives the user an indication about how they
- might continue to extend the token. For example, the file-
- completion callback function adds a directory separator if
- the completed word is a directory. If the completed word
- were a function name, you could similarly aid the user by
- arranging for an open parenthesis to be appended.
-
- CplMatches *cpl_complete_word(WordCompletion *cpl,
- const char *line,
- int word_end, void *data,
- CplMatchFn *match_fn);
-
- The cpl_complete_word() is normally called behind the scenes
- by <a href="gl_get_line.html">gl_get_line(3)</a>, but can also be called separately if you
- separately allocate a WordCompletion object. It performs
- word completion, as described at the beginning of this sec-
- tion. Its first argument is a resource object previously
- returned by new_CompleteWord(). The line argument is the
- input line string, containing the word to be completed. The
- word_end argument contains the index of the character in the
- input line, that just follows the last character of the word
- to be completed. When called by gl_get_line(), this is the
- character over which the user pressed TAB. The match_fn
- argument is the function pointer of the callback function
- which will lookup possible completions of the word, as
- described above, and the data argument provides a way for
- the application to pass arbitrary data to the callback func-
- tion.
-
- If no errors occur, the cpl_complete_word() function returns
- a pointer to a CplMatches container, as defined below. This
- container is allocated as part of the cpl object that was
- passed to cpl_complete_word(), and will thus change on each
- call which uses the same cpl argument.
-
- typedef struct {
- char *completion; /* A matching completion */
- /* string */
- char *suffix; /* The part of the */
- /* completion string which */
- /* would have to be */
- /* appended to complete the */
- /* original word. */
- const char *type_suffix; /* A suffix to be added when */
- /* listing completions, to */
- /* indicate the type of the */
- /* completion. */
- } CplMatch;
-
- typedef struct {
- char *suffix; /* The common initial part */
- /* of all of the completion */
- /* suffixes. */
- const char *cont_suffix; /* Optional continuation */
- /* string to be appended to */
- /* the sole completion when */
- /* nmatch==1. */
- CplMatch *matches; /* The array of possible */
- /* completion strings, */
- /* sorted into lexical */
- /* order. */
- int nmatch; /* The number of elements in */
- /* the above matches[] */
- /* array. */
- } CplMatches;
-
- If an error occurs during completion, cpl_complete_word()
- returns NULL. A description of the error can be acquired by
- calling the cpl_last_error() function.
-
- const char *cpl_last_error(WordCompletion *cpl);
-
- The cpl_last_error() function returns a terse description of
- the error which occurred on the last call to
- cpl_complete_word() or cpl_add_completion().
-
- int cpl_list_completions(CplMatches *result, FILE *fp,
- int terminal_width);
-
- When the cpl_complete_word() function returns multiple pos-
- sible completions, the cpl_list_completions() function can
- be called upon to list them, suitably arranged across the
- available width of the terminal. It arranges for the
- displayed columns of completions to all have the same width,
- set by the longest completion. It also appends the
- type_suffix strings that were recorded with each completion,
- thus indicating their types to the user.
-
-
-</pre><h2>THE BUILT-IN FILENAME-COMPLETION CALLBACK</h2><pre>
- By default the <a href="gl_get_line.html">gl_get_line(3)</a> function, passes the following
- completion callback function to cpl_complete_word(). This
- function can also be used separately, either by sending it
- to cpl_complete_word(), or by calling it directly from your
- own completion callback function.
-
- CPL_MATCH_FN(cpl_file_completions);
-
- Certain aspects of the behavior of this callback can be
- changed via its data argument. If you are happy with its
- default behavior you can pass NULL in this argument. Other-
- wise it should be a pointer to a CplFileConf object, previ-
- ously allocated by calling new_CplFileConf().
-
- CplFileConf *new_CplFileConf(void);
-
- CplFileConf objects encapsulate the configuration parameters
- of cpl_file_completions(). These parameters, which start out
- with default values, can be changed by calling the accessor
- functions described below.
-
- By default, the cpl_file_completions() callback function
- searches backwards for the start of the filename being com-
- pleted, looking for the first un-escaped space or the start
- of the input line. If you wish to specify a different loca-
- tion, call cfc_file_start() with the index at which the
- filename starts in the input line. Passing start_index=-1
- re-enables the default behavior.
-
- void cfc_file_start(CplFileConf *cfc, int start_index);
-
- By default, when cpl_file_completions() looks at a filename
- in the input line, each lone backslash in the input line is
- interpreted as being a special character which removes any
- special significance of the character which follows it, such
- as a space which should be taken as part of the filename
- rather than delimiting the start of the filename. These
- backslashes are thus ignored while looking for completions,
- and subsequently added before spaces, tabs and literal
- backslashes in the list of completions. To have unescaped
- backslashes treated as normal characters, call
- cfc_literal_escapes() with a non-zero value in its literal
- argument.
-
- void cfc_literal_escapes(CplFileConf *cfc, int literal);
-
- By default, cpl_file_completions() reports all files who's
- names start with the prefix that is being completed. If you
- only want a selected subset of these files to be reported in
- the list of completions, you can arrange this by providing a
- callback function which takes the full pathname of a file,
- and returns 0 if the file should be ignored, or 1 if the
- file should be included in the list of completions. To
- register such a function for use by cpl_file_completions(),
- call cfc_set_check_fn(), and pass it a pointer to the func-
- tion, together with a pointer to any data that you would
- like passed to this callback whenever it is called. Your
- callback can make its decisions based on any property of the
- file, such as the filename itself, whether the file is read-
- able, writable or executable, or even based on what the file
- contains.
-
- #define CPL_CHECK_FN(fn) int (fn)(void *data, \
- const char *pathname)
- typedef CPL_CHECK_FN(CplCheckFn);
-
- void cfc_set_check_fn(CplFileConf *cfc,
- CplCheckFn *chk_fn, void *chk_data);
-
- The cpl_check_exe() function is a provided callback of the
- above type, for use with cpl_file_completions(). It returns
- non-zero if the filename that it is given represents a nor-
- mal file that the user has execute permission to. You could
- use this to have cpl_file_completions() only list comple-
- tions of executable files.
-
- When you have finished with a CplFileConf variable, you can
- pass it to the del_CplFileConf() destructor function to
- reclaim its memory.
-
- CplFileConf *del_CplFileConf(CplFileConf *cfc);
-
-
-
-</pre><h2>THREAD SAFETY</h2><pre>
- In multi-threaded programs, you should use the libtecla_r.a
- version of the library. This uses POSIX reentrant functions
- where available (hence the _r suffix), and disables features
- that rely on non-reentrant system functions. In the case of
- this module, the only disabled feature is username comple-
- tion in ~username/ expressions, in cpl_file_completions().
-
- Using the libtecla_r.a version of the library, it is safe to
- use the facilities of this module in multiple threads, pro-
- vided that each thread uses a separately allocated WordCom-
- pletion object. In other words, if two threads want to do
- word completion, they should each call new_WordCompletion()
- to allocate their own completion objects.
-
-
-</pre><h2>FILES</h2><pre>
- libtecla.a - The tecla library
- libtecla.h - The tecla header file.
-
-
-</pre><h2>SEE ALSO</h2><pre>
- <a href="libtecla.html">libtecla(3)</a>, <a href="gl_get_line.html">gl_get_line(3)</a>, <a href="ef_expand_file.html">ef_expand_file(3)</a>,
- <a href="pca_lookup_file.html">pca_lookup_file(3)</a>
-
-
-</pre><h2>AUTHOR</h2><pre>
- Martin Shepherd (mcs@astro.caltech.edu)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-</pre>
-</body>
diff --git a/libtecla-1.4.1/html/ef_expand_file.html b/libtecla-1.4.1/html/ef_expand_file.html
deleted file mode 100644
index c1e71c7..0000000
--- a/libtecla-1.4.1/html/ef_expand_file.html
+++ /dev/null
@@ -1,267 +0,0 @@
-<head>
-<title>Manual Page</title>
-</head>
-<body>
-<pre>
-</pre><h2>NAME</h2><pre>
- ef_expand_file, del_ExpandFile, ef_last_error,
- ef_list_expansions, new_ExpandFile - expand filenames con-
- taining ~user/$envvar and wildcard expressions
-
-</pre><h2>SYNOPSIS</h2><pre>
- #include &lt;libtecla.h&gt;
-
- ExpandFile *new_ExpandFile(void);
-
- ExpandFile *del_ExpandFile(ExpandFile *ef);
-
- FileExpansion *ef_expand_file(ExpandFile *ef,
- const char *path,
- int pathlen);
-
- int ef_list_expansions(FileExpansion *result, FILE *fp,
- int term_width);
-
- const char *ef_last_error(ExpandFile *ef);
-
-
-</pre><h2>DESCRIPTION</h2><pre>
- The ef_expand_file() function is part of the tecla library
- (see the <a href="libtecla.html">libtecla(3)</a> man page). It expands a specified
- filename, converting ~user/ and ~/ expressions at the start
- of the filename to the corresponding home directories,
- replacing $envvar with the value of the corresponding
- environment variable, and then, if there are any wildcards,
- matching these against existing filenames. Backslashes in
- the input filename are interpreted as escaping any special
- meanings of the characters that follow them. Only
- backslahes that are themselves preceded by backslashes are
- preserved in the expanded filename.
-
- In the presence of wildcards, the returned list of filenames
- only includes the names of existing files which match the
- wildcards. Otherwise, the original filename is returned
- after expansion of tilde and dollar expressions, and the
- result is not checked against existing files. This mimics
- the file-globbing behavior of the unix tcsh shell.
-
- The supported wildcards and their meanings are:
- * - Match any sequence of zero or more characters.
- ? - Match any single character.
- [chars] - Match any single character that appears in
- 'chars'. If 'chars' contains an expression of
- the form a-b, then any character between a and
- b, including a and b, matches. The '-'
- character looses its special meaning as a
- range specifier when it appears at the start
- of the sequence of characters. The ']'
- character also looses its significance as the
- terminator of the range expression if it
- appears immediately after the opening '[', at
- which point it is treated one of the
- characters of the range. If you want both '-'
- and ']' to be part of the range, the '-'
- should come first and the ']' second.
-
- [^chars] - The same as [chars] except that it matches any
- single character that doesn't appear in
- 'chars'.
-
- Note that wildcards never match the initial dot in filenames
- that start with '.'. The initial '.' must be explicitly
- specified in the filename. This again mimics the globbing
- behavior of most unix shells, and its rational is based in
- the fact that in unix, files with names that start with '.'
- are usually hidden configuration files, which are not listed
- by default by the ls command.
-
- The following is a complete example of how to use the file
- expansion function.
-
- #include &lt;stdio.h&gt;
- #include &lt;libtecla.h&gt;
-
- int main(int argc, char *argv[])
- {
- ExpandFile *ef; /* The expansion resource object */
- char *filename; /* The filename being expanded */
- FileExpansion *expn; /* The results of the expansion */
- int i;
-
- ef = new_ExpandFile();
- if(!ef)
- return 1;
-
- for(arg = *(argv++); arg; arg = *(argv++)) {
- if((expn = ef_expand_file(ef, arg, -1)) == NULL) {
- fprintf(stderr, "Error expanding %s (%s).\n", arg,
- ef_last_error(ef));
- } else {
- printf("%s matches the following files:\n", arg);
- for(i=0; i&lt;expn-&gt;nfile; i++)
- printf(" %s\n", expn-&gt;files[i]);
- }
- }
-
- ef = del_ExpandFile(ef);
- return 0;
- }
-
- Descriptions of the functions used above are as follows:
-
- ExpandFile *new_ExpandFile(void)
-
- This function creates the resources used by the
- ef_expand_file() function. In particular, it maintains the
- memory that is used to record the array of matching
- filenames that is returned by ef_expand_file(). This array
- is expanded as needed, so there is no built in limit to the
- number of files that can be matched.
-
- ExpandFile *del_ExpandFile(ExpandFile *ef)
-
- This function deletes the resources that were returned by a
- previous call to new_ExpandFile(). It always returns NULL
- (ie a deleted object). It does nothing if the ef argument is
- NULL.
-
- A container of the following type is returned by
- ef_expand_file().
-
- typedef struct {
- int exists; /* True if the files in files[] exist */
- int nfile; /* The number of files in files[] */
- char **files; /* An array of 'nfile' filenames. */
- } FileExpansion;
-
- FileExpansion *ef_expand_file(ExpandFile *ef,
- const char *path,
- int pathlen)
-
- The ef_expand_file() function performs filename expansion,
- as documented at the start of this section. Its first argu-
- ment is a resource object returned by new_ExpandFile(). A
- pointer to the start of the filename to be matched is passed
- via the path argument. This must be a normal NUL terminated
- string, but unless a length of -1 is passed in pathlen, only
- the first pathlen characters will be used in the filename
- expansion. If the length is specified as -1, the whole of
- the string will be expanded.
-
- The function returns a pointer to a container who's contents
- are the results of the expansion. If there were no wildcards
- in the filename, the nfile member will be 1, and the exists
- member should be queried if it is important to know if the
- expanded file currently exists or not. If there were wild-
- cards, then the contained files[] array will contain the
- names of the nfile existing files that matched the wild-
- carded filename, and the exists member will have the value
- 1. Note that the returned container belongs to the specified
- ef object, and its contents will change on each call, so if
- you need to retain the results of more than one call to
- ef_expand_file(), you should either make a private copy of
- the returned results, or create multiple file-expansion
- resource objects via multiple calls to new_ExpandFile().
-
- On error, NULL is returned, and an explanation of the error
- can be determined by calling ef_last_error(ef).
-
- const char *ef_last_error(ExpandFile *ef)
-
- This function returns the message which describes the error
- that occurred on the last call to ef_expand_file(), for the
- given (ExpandFile *ef) resource object.
-
- int ef_list_expansions(FileExpansion *result, FILE *fp,
- int terminal_width);
-
- The ef_list_expansions() function provides a convenient way
- to list the filename expansions returned by
- ef_expand_file(). Like the unix ls command, it arranges the
- filenames into equal width columns, each column having the
- width of the largest file. The number of columns used is
- thus determined by the length of the longest filename, and
- the specified terminal width. Beware that filenames that are
- longer than the specified terminal width are printed without
- being truncated, so output longer than the specified termi-
- nal width can occur. The list is written to the stdio stream
- specified by the fp argument.
-
-
-</pre><h2>THREAD SAFETY</h2><pre>
- In multi-threaded programs, you should use the libtecla_r.a
- version of the library. This uses POSIX reentrant functions
- where available (hence the _r suffix), and disables features
- that rely on non-reentrant system functions. Currently there
- are no features disabled in this module.
-
- Using the libtecla_r.a version of the library, it is safe to
- use the facilities of this module in multiple threads, pro-
- vided that each thread uses a separately allocated Expand-
- File object. In other words, if two threads want to do file
- expansion, they should each call new_ExpandFile() to allo-
- cate their own file-expansion objects.
-
-
-</pre><h2>FILES</h2><pre>
- libtecla.a - The tecla library
- libtecla.h - The tecla header file.
-
-
-</pre><h2>SEE ALSO</h2><pre>
- <a href="libtecla.html">libtecla(3)</a>, <a href="gl_get_line.html">gl_get_line(3)</a>, <a href="cpl_complete_word.html">cpl_complete_word(3)</a>,
- <a href="pca_lookup_file.html">pca_lookup_file(3)</a>
-</pre><h2>AUTHOR</h2><pre>
- Martin Shepherd (mcs@astro.caltech.edu)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-</pre>
-</body>
diff --git a/libtecla-1.4.1/html/enhance.html b/libtecla-1.4.1/html/enhance.html
deleted file mode 100644
index 9f6bb09..0000000
--- a/libtecla-1.4.1/html/enhance.html
+++ /dev/null
@@ -1,111 +0,0 @@
-<head>
-<title>Manual Page</title>
-</head>
-<body>
-<pre>
-</pre><h2>NAME</h2><pre>
- enhance - A program that adds command-line editing to third
- party programs.
-
-</pre><h2>SYNOPSIS</h2><pre>
- enhance command [ argument ... ]
-
-
-</pre><h2>DESCRIPTION</h2><pre>
- The enhance program provides enhanced command-line editing
- facilities to users of third party applications, to which
- one doesn't have any source code. It does this by placing a
- pseudo-terminal between the application and the real termi-
- nal. It uses the tecla command-line editing library to read
- input from the real terminal, then forwards each just com-
- pleted input line to the application via the pseudo-
- terminal. All output from the application is forwarded back
- unchanged to the real terminal.
-
- Whenever the application stops generating output for more
- than a tenth of a second, the enhance program treats the
- latest incomplete output line as the prompt, and redisplays
- any incompleted input line that the user has typed after it.
- Note that the small delay, which is imperceptible to the
- user, isn't necessary for correct operation of the program.
- It is just an optimization, designed to stop the input line
- from being redisplayed so often that it slows down output.
-
-
-</pre><h2>DEFICIENCIES</h2><pre>
- The one major problem that hasn't been solved yet, is how to
- deal with applications that change whether typed input is
- echo'd by their controlling terminal. For example, programs
- that ask for a password, such as ftp and telnet, temporarily
- tell their controlling terminal not to echo what the user
- types. Since this request goes to the application side of
- the psuedo terminal, the enhance program has no way of know-
- ing that this has happened, and continues to echo typed
- input to its controlling terminal, while the user types
- their password.
-
- Furthermore, before executing the host application, the
- enhance program initially sets the pseudo terminal to noecho
- mode, so that everything that it sends to the program
- doesn't get redundantly echoed. If a program that switches
- to noecho mode explicitly restores echoing afterwards,
- rather than restoring the terminal modes that were previ-
- ously in force, then subsequently, every time that you enter
- a new input line, a duplicate copy will be displayed on the
- next line.
-
-
-</pre><h2>FILES</h2><pre>
- libtecla.a - The tecla library.
- ~/.teclarc - The tecla personal customization file.
-
-
-</pre><h2>SEE ALSO</h2><pre>
- <a href="libtecla.html">libtecla(3)</a>
-
-
-</pre><h2>AUTHOR</h2><pre>
- Martin Shepherd (mcs@astro.caltech.edu)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-</pre>
-</body>
diff --git a/libtecla-1.4.1/html/gl_get_line.html b/libtecla-1.4.1/html/gl_get_line.html
deleted file mode 100644
index dcc45a0..0000000
--- a/libtecla-1.4.1/html/gl_get_line.html
+++ /dev/null
@@ -1,2295 +0,0 @@
-<head>
-<title>Manual Page</title>
-</head>
-<body>
-<pre>
-</pre><h2>NAME</h2><pre>
- gl_get_line, new_GetLine, del_GetLine,
- gl_customize_completion, gl_change_terminal,
- gl_configure_getline, gl_load_history, gl_save_history,
- gl_group_history, gl_show_history, gl_watch_fd,
- gl_terminal_size, gl_resize_history, gl_limit_history,
- gl_clear_history, gl_toggle_history, gl_lookup_history,
- gl_state_of_history, gl_range_of_history,
- gl_size_of_history, gl_echo_mode, gl_replace_prompt,
- gl_prompt_style, gl_ignore_signal, gl_trap_signal,
- gl_last_signal - allow the user to compose an input line
-
-</pre><h2>SYNOPSIS</h2><pre>
- #include &lt;stdio.h&gt;
- #include &lt;libtecla.h&gt;
-
- GetLine *new_GetLine(size_t linelen, size_t histlen);
-
- GetLine *del_GetLine(GetLine *gl);
-
- char *gl_get_line(GetLine *gl, const char *prompt,
- const char *start_line, int start_pos);
-
- int gl_customize_completion(GetLine *gl, void *data,
- CplMatchFn *match_fn);
-
- int gl_change_terminal(GetLine *gl, FILE *input_fp,
- FILE *output_fp, const char *term);
-
- int gl_configure_getline(GetLine *gl,
- const char *app_string,
- const char *app_file,
- const char *user_file);
-
- int gl_save_history(GetLine *gl, const char *filename,
- const char *comment, int max_lines);
-
- int gl_load_history(GetLine *gl, const char *filename,
- const char *comment);
-
- int gl_watch_fd(GetLine *gl, int fd, GlFdEvent event,
- GlFdEventFn *callback, void *data);
-
- int gl_group_history(GetLine *gl, unsigned stream);
-
- int gl_show_history(GetLine *gl, FILE *fp,
- const char *fmt, int all_groups,
- int max_lines);
-
- int gl_resize_history(GetLine *gl, size_t bufsize);
-
- void gl_limit_history(GetLine *gl, int max_lines);
- void gl_clear_history(GetLine *gl, int all_groups);
-
- void gl_toggle_history(GetLine *gl, int enable);
-
- GlTerminalSize gl_terminal_size(GetLine *gl,
- int def_ncolumn,
- int def_nline);
-
- int gl_lookup_history(GetLine *gl, unsigned long id,
- GlHistoryLine *hline);
-
- void gl_state_of_history(GetLine *gl,
- GlHistoryState *state);
-
- void gl_range_of_history(GetLine *gl,
- GlHistoryRange *range);
-
- void gl_size_of_history(GetLine *gl, GlHistorySize *size);
-
- void gl_echo_mode(GetLine *gl, int enable);
-
- void gl_replace_prompt(GetLine *gl, const char *prompt);
-
- void gl_prompt_style(GetLine *gl, GlPromptStyle style);
-
- int gl_ignore_signal(GetLine *gl, int signo);
-
- int gl_trap_signal(GetLine *gl, int signo, unsigned flags,
- GlAfterSignal after, int errno_value);
-
- int gl_last_signal(const GetLine *gl);
-
-
-
-</pre><h2>DESCRIPTION</h2><pre>
- The gl_get_line() function is part of the tecla library (see
- the <a href="libtecla.html">libtecla(3)</a> man page). If the user is typing at a termi-
- nal, it prompts them for an line of input, then provides
- interactive editing facilities, similar to those of the unix
- tcsh shell. In addition to simple command-line editing, it
- supports recall of previously entered command lines, TAB
- completion of file names, and in-line wild-card expansion of
- filenames.
-
-
-</pre><h2>AN EXAMPLE</h2><pre>
- The following shows a complete example of how to use the
- gl_get_line() function to get input from the user:
-
- #include &lt;stdio.h&gt;
- #include &lt;locale.h&gt;
- #include &lt;libtecla.h&gt;
- int main(int argc, char *argv[])
- {
- char *line; /* The line that the user typed */
- GetLine *gl; /* The gl_get_line() resource object */
-
- setlocale(LC_CTYPE, ""); /* Adopt the user's choice */
- /* of character set. */
-
- gl = new_GetLine(1024, 2048);
- if(!gl)
- return 1;
-
- while((line=gl_get_line(gl, "$ ", NULL, -1)) != NULL &amp;&amp;
- strcmp(line, "exit\n") != 0)
- printf("You typed: %s\n", line);
-
- gl = del_GetLine(gl);
- return 0;
- }
-
- In the example, first the resources needed by the
- gl_get_line() function are created by calling new_GetLine().
- This allocates the memory used in subsequent calls to the
- gl_get_line() function, including the history buffer for
- recording previously entered lines. Then one or more lines
- are read from the user, until either an error occurs, or the
- user types exit. Then finally the resources that were allo-
- cated by new_GetLine(), are returned to the system by cal-
- ling del_GetLine(). Note the use of the NULL return value of
- del_GetLine() to make gl NULL. This is a safety precaution.
- If the program subsequently attempts to pass gl to
- gl_get_line(), said function will complain, and return an
- error, instead of attempting to use the deleted resource
- object.
-
-
-
-</pre><h2>THE FUNCTIONS USED IN THE EXAMPLE</h2><pre>
- The descriptions of the functions used in the example are as
- follows:
-
- GetLine *new_GetLine(size_t linelen, size_t histlen)
-
- This function creates the resources used by the
- gl_get_line() function and returns an opaque pointer to the
- object that contains them. The maximum length of an input
- line is specified via the linelen argument, and the number
- of bytes to allocate for storing history lines is set by the
- histlen argument. History lines are stored back-to-back in a
- single buffer of this size. Note that this means that the
- number of history lines that can be stored at any given
- time, depends on the lengths of the individual lines. If
- you want to place an upper limit on the number of lines that
- can be stored, see the gl_limit_history() function described
- later. If you don't want history at all, specify histlen as
- zero, and no history buffer will be allocated.
-
- On error, a message is printed to stderr and NULL is
- returned.
-
- GetLine *del_GetLine(GetLine *gl)
-
- This function deletes the resources that were returned by a
- previous call to new_GetLine(). It always returns NULL (ie a
- deleted object). It does nothing if the gl argument is NULL.
-
- char *gl_get_line(GetLine *gl, const char *prompt,
- const char *start_line, int start_pos);
-
- The gl_get_line() function can be called any number of times
- to read input from the user. The gl argument must have been
- previously returned by a call to new_GetLine(). The prompt
- argument should be a normal NUL terminated string, specify-
- ing the prompt to present the user with. By default prompts
- are displayed literally, but if enabled with the
- gl_prompt_style() function (see later), prompts can contain
- directives to do underlining, switch to and from bold fonts,
- or turn highlighting on and off.
-
- If you want to specify the initial contents of the line, for
- the user to edit, pass the desired string via the start_line
- argument. You can then specify which character of this line
- the cursor is initially positioned over, using the start_pos
- argument. This should be -1 if you want the cursor to follow
- the last character of the start line. If you don't want to
- preload the line in this manner, send start_line as NULL,
- and set start_pos to -1.
-
- The gl_get_line() function returns a pointer to the line
- entered by the user, or NULL on error or at the end of the
- input. The returned pointer is part of the specified gl
- resource object, and thus should not be free'd by the
- caller, or assumed to be unchanging from one call to the
- next. When reading from a user at a terminal, there will
- always be a newline character at the end of the returned
- line. When standard input is being taken from a pipe or a
- file, there will similarly be a newline unless the input
- line was too long to store in the internal buffer. In the
- latter case you should call gl_get_line() again to read the
- rest of the line. Note that this behavior makes
- gl_get_line() similar to fgets(). In fact when stdin isn't
- connected to a terminal,gl_get_line() just calls fgets().
-
-
-</pre><h2>OPTIONAL PROMPT FORMATTING</h2><pre>
- Whereas by default the prompt string that you specify is
- displayed literally, without any special interpretation of
- the characters within it, the gl_prompt_style() function can
- be used to enable optional formatting directives within the
- prompt.
-
- void gl_prompt_style(GetLine *gl, GlPromptStyle style);
-
- The style argument, which specifies the formatting style,
- can take any of the following values:
-
- GL_FORMAT_PROMPT - In this style, the formatting
- directives described below, when
- included in prompt strings, are
- interpreted as follows:
-
- %B - Display subsequent
- characters with a bold
- font.
- %b - Stop displaying characters
- with the bold font.
- %F - Make subsequent characters
- flash.
- %f - Turn off flashing
- characters.
- %U - Underline subsequent
- characters.
- %u - Stop underlining
- characters.
- %P - Switch to a pale (half
- brightness) font.
- %p - Stop using the pale font.
- %S - Highlight subsequent
- characters (also known as
- standout mode).
- %s - Stop highlighting
- characters.
- %V - Turn on reverse video.
- %v - Turn off reverse video.
- %% - Display a single %
- character.
-
- For example, in this mode, a prompt
- string like "%UOK%u$ " would
- display the prompt "OK$ ",
- but with the OK part
- underlined.
-
- Note that although a pair of
- characters that starts with a %
- character, but doesn't match any of
- the above directives is displayed
- literally, if a new directive is
- subsequently introduced which does
- match, the displayed prompt will
- change, so it is better to always
- use %% to display a literal %.
-
- Also note that not all terminals
- support all of these text
- attributes, and that some substitute
- a different attribute for missing
- ones.
-
- GL_LITERAL_PROMPT - In this style, the prompt string is
- printed literally. This is the
- default style.
-
-
-
-</pre><h2>THE AVAILABLE KEY BINDING FUNCTIONS</h2><pre>
- The gl_get_line() function provides a number of functions
- which can be bound to key sequences. The names of these
- functions, and what they do, are given below.
-
- user-interrupt - Send a SIGINT signal to the
- parent process.
- abort - Send a SIGABRT signal to the
- parent process.
- suspend - Suspend the parent process.
- stop-output - Pause terminal output.
- start-output - Resume paused terminal output.
- literal-next - Arrange for the next character
- to be treated as a normal
- character. This allows control
- characters to be entered.
- cursor-right - Move the cursor one character
- right.
- cursor-left - Move the cursor one character
- left.
- insert-mode - Toggle between insert mode and
- overwrite mode.
- beginning-of-line - Move the cursor to the
- beginning of the line.
- end-of-line - Move the cursor to the end of
- the line.
- delete-line - Delete the contents of the
- current line.
- kill-line - Delete everything that follows
- the cursor.
- backward-kill-line - Delete all characters between
- the cursor and the start of the
- line.
- forward-word - Move to the end of the word
- which follows the cursor.
- forward-to-word - Move the cursor to the start of
- the word that follows the
- cursor.
- backward-word - Move to the start of the word
- which precedes the cursor.
- goto-column - Move the cursor to the
- 1-relative column in the line
- specified by any preceding
- digit-argument sequences (see
- ENTERING REPEAT COUNTS below).
- find-parenthesis - If the cursor is currently
- over a parenthesis character,
- move it to the matching
- parenthesis character. If not
- over a parenthesis character
- move right to the next close
- parenthesis.
- forward-delete-char - Delete the character under the
- cursor.
- backward-delete-char - Delete the character which
- precedes the cursor.
- list-or-eof - This is intended for binding
- to ^D. When invoked when the
- cursor is within the line it
- displays all possible
- completions then redisplays
- the line unchanged. When
- invoked on an empty line, it
- signals end-of-input (EOF) to
- the caller of gl_get_line().
- del-char-or-list-or-eof - This is intended for binding
- to ^D. When invoked when the
- cursor is within the line it
- invokes forward-delete-char.
- When invoked at the end of the
- line it displays all possible
- completions then redisplays
- the line unchanged. When
- invoked on an empty line, it
- signals end-of-input (EOF) to
- the caller of gl_get_line().
- forward-delete-word - Delete the word which follows
- the cursor.
- backward-delete-word - Delete the word which precedes
- the cursor.
- upcase-word - Convert all of the characters
- of the word which follows the
- cursor, to upper case.
- downcase-word - Convert all of the characters
- of the word which follows the
- cursor, to lower case.
- capitalize-word - Capitalize the word which
- follows the cursor.
- change-case - If the next character is upper
- case, toggle it to lower case
- and vice versa.
- redisplay - Redisplay the line.
- clear-screen - Clear the terminal, then
- redisplay the current line.
- transpose-chars - Swap the character under the
- cursor with the character just
- before the cursor.
- set-mark - Set a mark at the position of
- the cursor.
- exchange-point-and-mark - Move the cursor to the last
- mark that was set, and move
- the mark to where the cursor
- used to be.
- kill-region - Delete the characters that lie
- between the last mark that was
- set, and the cursor.
- copy-region-as-kill - Copy the text between the mark
- and the cursor to the cut
- buffer, without deleting the
- original text.
- yank - Insert the text that was last
- deleted, just before the
- current position of the cursor.
- append-yank - Paste the current contents of
- the cut buffer, after the
- cursor.
- up-history - Recall the next oldest line
- that was entered. Note that
- in vi mode you are left in
- command mode.
- down-history - Recall the next most recent
- line that was entered. If no
- history recall session is
- currently active, the next
- line from a previous recall
- session is recalled. Note that
- in vi mode you are left in
- command mode.
- history-search-backward - Recall the next oldest line
- who's prefix matches the string
- which currently precedes the
- cursor (in vi command-mode the
- character under the cursor is
- also included in the search
- string). Note that in vi mode
- you are left in command mode.
- history-search-forward - Recall the next newest line
- who's prefix matches the string
- which currently precedes the
- cursor (in vi command-mode the
- character under the cursor is
- also included in the search
- string). Note that in vi mode
- you are left in command mode.
- history-re-search-backward -Recall the next oldest line
- who's prefix matches that
- established by the last
- invocation of either
- history-search-forward or
- history-search-backward.
- history-re-search-forward - Recall the next newest line
- who's prefix matches that
- established by the last
- invocation of either
- history-search-forward or
- history-search-backward.
- complete-word - Attempt to complete the
- incomplete word which
- precedes the cursor. Unless
- the host program has customized
- word completion, filename
- completion is attempted. In vi
- commmand mode the character
- under the cursor is also
- included in the word being
- completed, and you are left in
- vi insert mode.
- expand-filename - Within the command line, expand
- wild cards, tilde expressions
- and dollar expressions in the
- filename which immediately
- precedes the cursor. In vi
- commmand mode the character
- under the cursor is also
- included in the filename being
- expanded, and you are left in
- vi insert mode.
- list-glob - List any filenames which match
- the wild-card, tilde and dollar
- expressions in the filename
- which immediately precedes the
- cursor, then redraw the input
- line unchanged.
- list-history - Display the contents of the
- history list for the current
- history group. If a repeat
- count of &gt; 1 is specified,
- only that many of the most
- recent lines are displayed.
- See the "ENTERING REPEAT
- COUNTS" section.
- read-from-file - Temporarily switch to reading
- input from the file who's
- name precedes the cursor.
- read-init-files - Re-read teclarc configuration
- files.
- beginning-of-history - Move to the oldest line in the
- history list. Note that in vi
- mode you are left in command
- mode.
- end-of-history - Move to the newest line in the
- history list (ie. the current
- line). Note that in vi mode
- this leaves you in command
- mode.
- digit-argument - Enter a repeat count for the
- next key-binding function.
- For details, see the ENTERING
- REPEAT COUNTS section.
- newline - Terminate and return the
- current contents of the
- line, after appending a
- newline character. The newline
- character is normally '\n',
- but will be the first
- character of the key-sequence
- that invoked the newline
- action, if this happens to be
- a printable character. If the
- action was invoked by the
- '\n' newline character or the
- '\r' carriage return
- character, the line is
- appended to the history
- buffer.
- repeat-history - Return the line that is being
- edited, then arrange for the
- next most recent entry in the
- history buffer to be recalled
- when gl_get_line() is
- next called. Repeatedly
- invoking this action causes
- successive historical input
- lines to be re-executed. Note
- that this action is equivalent
- to the 'Operate' action in
- ksh.
- ring-bell - Ring the terminal bell, unless
- the bell has been silenced via
- the nobeep configuration
- option (see the THE TECLA
- CONFIGURATION FILE section).
- forward-copy-char - Copy the next character into
- the cut buffer (NB. use repeat
- counts to copy more than one).
- backward-copy-char - Copy the previous character
- into the cut buffer.
- forward-copy-word - Copy the next word into the cut
- buffer.
- backward-copy-word - Copy the previous word into the
- cut buffer.
- forward-find-char - Move the cursor to the next
- occurrence of the next
- character that you type.
- backward-find-char - Move the cursor to the last
- occurrence of the next
- character that you type.
- forward-to-char - Move the cursor to the
- character just before the next
- occurrence of the next
- character that the user types.
- backward-to-char - Move the cursor to the
- character just after the last
- occurrence before the cursor
- of the next character that the
- user types.
- repeat-find-char - Repeat the last
- backward-find-char,
- forward-find-char,
- backward-to-char or
- forward-to-char.
- invert-refind-char - Repeat the last
- backward-find-char,
- forward-find-char,
- backward-to-char, or
- forward-to-char in the
- opposite direction.
- delete-to-column - Delete the characters from the
- cursor up to the column that
- is specified by the repeat
- count.
- delete-to-parenthesis - Delete the characters from the
- cursor up to and including
- the matching parenthesis, or
- next close parenthesis.
- forward-delete-find - Delete the characters from the
- cursor up to and including the
- following occurence of the
- next character typed.
- backward-delete-find - Delete the characters from the
- cursor up to and including the
- preceding occurence of the
- next character typed.
- forward-delete-to - Delete the characters from the
- cursor up to, but not
- including, the following
- occurence of the next
- character typed.
- backward-delete-to - Delete the characters from the
- cursor up to, but not
- including, the preceding
- occurence of the next
- character typed.
- delete-refind - Repeat the last *-delete-find
- or *-delete-to action.
- delete-invert-refind - Repeat the last *-delete-find
- or *-delete-to action, in the
- opposite direction.
- copy-to-column - Copy the characters from the
- cursor up to the column that
- is specified by the repeat
- count, into the cut buffer.
- copy-to-parenthesis - Copy the characters from the
- cursor up to and including
- the matching parenthesis, or
- next close parenthesis, into
- the cut buffer.
- forward-copy-find - Copy the characters from the
- cursor up to and including the
- following occurence of the
- next character typed, into the
- cut buffer.
- backward-copy-find - Copy the characters from the
- cursor up to and including the
- preceding occurence of the
- next character typed, into the
- cut buffer.
- forward-copy-to - Copy the characters from the
- cursor up to, but not
- including, the following
- occurence of the next
- character typed, into the cut
- buffer.
- backward-copy-to - Copy the characters from the
- cursor up to, but not
- including, the preceding
- occurence of the next
- character typed, into the cut
- buffer.
- copy-refind - Repeat the last *-copy-find
- or *-copy-to action.
- copy-invert-refind - Repeat the last *-copy-find
- or *-copy-to action, in the
- opposite direction.
- vi-mode - Switch to vi mode from emacs
- mode.
- emacs-mode - Switch to emacs mode from vi
- mode.
- vi-insert - From vi command mode, switch to
- insert mode.
- vi-overwrite - From vi command mode, switch to
- overwrite mode.
- vi-insert-at-bol - From vi command mode, move the
- cursor to the start of the line
- and switch to insert mode.
- vi-append-at-eol - From vi command mode, move the
- cursor to the end of the line
- and switch to append mode.
- vi-append - From vi command mode, move the
- cursor one position right, and
- switch to insert mode.
- vi-replace-char - From vi command mode, replace
- the character under the cursor
- with the the next character
- entered.
- vi-forward-change-char - From vi command mode, delete
- the next character then enter
- insert mode.
- vi-backward-change-char - From vi command mode, delete
- the preceding character then
- enter insert mode.
- vi-forward-change-word - From vi command mode, delete
- the next word then enter
- insert mode.
- vi-backward-change-word - From vi command mode, delete
- the preceding word then
- enter insert mode.
- vi-change-rest-of-line - From vi command mode, delete
- from the cursor to the end of
- the line, then enter insert
- mode.
- vi-change-line - From vi command mode, delete
- the current line, then enter
- insert mode.
- vi-change-to-bol - From vi command mode, delete
- all characters between the
- cursor and the beginning of
- the line, then enter insert
- mode.
- vi-change-to-column - From vi command mode, delete
- the characters from the cursor
- up to the column that is
- specified by the repeat count,
- then enter insert mode.
- vi-change-to-parenthesis - Delete the characters from the
- cursor up to and including
- the matching parenthesis, or
- next close parenthesis, then
- enter vi insert mode.
- vi-forward-change-find - From vi command mode, delete
- the characters from the
- cursor up to and including the
- following occurence of the
- next character typed, then
- enter insert mode.
- vi-backward-change-find - From vi command mode, delete
- the characters from the
- cursor up to and including the
- preceding occurence of the
- next character typed, then
- enter insert mode.
- vi-forward-change-to - From vi command mode, delete
- the characters from the
- cursor up to, but not
- including, the following
- occurence of the next
- character typed, then enter
- insert mode.
- vi-backward-change-to - From vi command mode, delete
- the characters from the
- cursor up to, but not
- including, the preceding
- occurence of the next
- character typed, then enter
- insert mode.
- vi-change-refind - Repeat the last
- vi-*-change-find or
- vi-*-change-to action.
- vi-change-invert-refind - Repeat the last
- vi-*-change-find or
- vi-*-change-to action, in the
- opposite direction.
- vi-undo - In vi mode, undo the last
- editing operation.
- vi-repeat-change - In vi command mode, repeat the
- last command that modified the
- line.
-
-
-</pre><h2>DEFAULT KEY BINDINGS IN EMACS MODE</h2><pre>
- The following default key bindings, which can be overriden
- by the tecla configuration file, are designed to mimic most
- of the bindings of the unix tcsh shell, when it is in emacs
- editing mode.
-
- This is the default editing mode of the tecla library.
-
- Note that a key sequence like ^A or C-a means hold the
- control-key down while pressing the letter A, and that where
- you see \E or M- in a binding, this represents the escape
- key or the Meta modifier key. Also note that to
- gl_get_line(), pressing the escape key before a key is
- equivalent to pressing the meta key at the same time as that
- key. Thus the key sequence M-p can be typed in two ways, by
- pressing the escape key, followed by pressing p, or by
- pressing the Meta key at the same time as p.
-
- Under UNIX the terminal driver sets a number of special keys
- for certain functions. The tecla library attempts to use the
- same keybindings to maintain consistency. The key sequences
- shown for the following 6 bindings are thus just examples of
- what they will probably be set to. If you have used the stty
- command to change these keys, then the default bindings
- should match.
-
- ^C -&gt; user-interrupt
- ^\ -&gt; abort
- ^Z -&gt; suspend
- ^Q -&gt; start-output
- ^S -&gt; stop-output
- ^V -&gt; literal-next
-
- The cursor keys are refered to by name, as follows. This is
- necessary because different types of terminals generate dif-
- ferent key sequences when their cursor keys are pressed.
-
- right -&gt; cursor-right
- left -&gt; cursor-left
- up -&gt; up-history
- down -&gt; down-history
-
- The remaining bindings don't depend on the terminal sett-
- tings.
-
- ^F -&gt; cursor-right
- ^B -&gt; cursor-left
- M-i -&gt; insert-mode
- ^A -&gt; beginning-of-line
- ^E -&gt; end-of-line
- ^U -&gt; delete-line
- ^K -&gt; kill-line
- M-f -&gt; forward-word
- M-b -&gt; backward-word
- ^D -&gt; del-char-or-list-or-eof
- ^H -&gt; backward-delete-char
- ^? -&gt; backward-delete-char
- M-d -&gt; forward-delete-word
- M-^H -&gt; backward-delete-word
- M-^? -&gt; backward-delete-word
- M-u -&gt; upcase-word
- M-l -&gt; downcase-word
- M-c -&gt; capitalize-word
- ^R -&gt; redisplay
- ^L -&gt; clear-screen
- ^T -&gt; transpose-chars
- ^@ -&gt; set-mark
- ^X^X -&gt; exchange-point-and-mark
- ^W -&gt; kill-region
- M-w -&gt; copy-region-as-kill
- ^Y -&gt; yank
- ^P -&gt; up-history
- ^N -&gt; down-history
- M-p -&gt; history-search-backward
- M-n -&gt; history-search-forward
- ^I -&gt; complete-word
- ^X* -&gt; expand-filename
- ^X^F -&gt; read-from-file
- ^X^R -&gt; read-init-files
- ^Xg -&gt; list-glob
- ^Xh -&gt; list-history
- M-&lt; -&gt; beginning-of-history
- M-&gt; -&gt; end-of-history
- \n -&gt; newline
- \r -&gt; newline
- M-o -&gt; repeat-history
- M-^V -&gt; vi-mode
-
- M-0, M-1, ... M-9 -&gt; digit-argument (see below)
-
- Note that ^I is what the TAB key generates, and that ^@ can
- be generated not only by pressing the control key and the @
- key simultaneously, but also by pressing the control key and
- the space bar at the same time.
-
-
-</pre><h2>DEFAULT KEY BINDINGS IN VI MODE</h2><pre>
- The following default key bindings are designed to mimic the
- vi style of editing as closely as possible. This means that
- very few editing functions are provided in the initial char-
- acter input mode, editing functions instead being provided
- by the vi command mode. Vi command mode is entered whenever
- the escape character is pressed, or whenever a key-sequence
- that starts with a meta character is entered. In addition to
- mimicing vi, libtecla provides bindings for tab completion,
- wild-card expansion of file names, and historical line
- recall.
-
- To learn how to tell the tecla library to use vi mode
- instead of the default emacs editing mode, see the section
- entitled THE TECLA CONFIGURATION FILE.
-
- As already mentioned above in the emacs section, Note that a
- key sequence like ^A or C-a means hold the control-key down
- while pressing the letter A, and that where you see \E or M-
- in a binding, this represents the escape key or the Meta
- modifier key. Also note that to gl_get_line(), pressing the
- escape key before a key is equivalent to pressing the meta
- key at the same time as that key. Thus the key sequence M-p
- can be typed in two ways, by pressing the escape key, fol-
- lowed by pressing p, or by pressing the Meta key at the same
- time as p.
-
- Under UNIX the terminal driver sets a number of special keys
- for certain functions. The tecla library attempts to use the
- same keybindings to maintain consistency, binding them both
- in input mode and in command mode. The key sequences shown
- for the following 6 bindings are thus just examples of what
- they will probably be set to. If you have used the stty com-
- mand to change these keys, then the default bindings should
- match.
-
- ^C -&gt; user-interrupt
- ^\ -&gt; abort
- ^Z -&gt; suspend
- ^Q -&gt; start-output
- ^S -&gt; stop-output
- ^V -&gt; literal-next
- M-^C -&gt; user-interrupt
- M-^\ -&gt; abort
- M-^Z -&gt; suspend
- M-^Q -&gt; start-output
- M-^S -&gt; stop-output
-
- Note that above, most of the bindings are defined twice,
- once as a raw control code like ^C and then a second time as
- a meta character like M-^C. The former is the binding for vi
- input mode, whereas the latter is the binding for vi command
- mode. Once in command mode all key-sequences that the user
- types that they don't explicitly start with an escape or a
- meta key, have their first key secretly converted to a meta
- character before the key sequence is looked up in the key
- binding table. Thus, once in command mode, when you type the
- letter i, for example, the tecla library actually looks up
- the binding for M-i.
-
- The cursor keys are refered to by name, as follows. This is
- necessary because different types of terminals generate dif-
- ferent key sequences when their cursor keys are pressed.
-
- right -&gt; cursor-right
- left -&gt; cursor-left
- up -&gt; up-history
- down -&gt; down-history
-
- The cursor keys normally generate a keysequence that start
- with an escape character, so beware that using the arrow
- keys will put you into command mode (if you aren't already
- in command mode).
-
- The following are the terminal-independent key bindings for
- vi input mode.
-
- ^D -&gt; list-or-eof
- ^G -&gt; list-glob
- ^H -&gt; backward-delete-char
- ^I -&gt; complete-word
- \r -&gt; newline
- \n -&gt; newline
- ^L -&gt; clear-screen
- ^N -&gt; down-history
- ^P -&gt; up-history
- ^R -&gt; redisplay
- ^U -&gt; backward-kill-line
- ^W -&gt; backward-delete-word
- ^X* -&gt; expand-filename
- ^X^F -&gt; read-from-file
- ^X^R -&gt; read-init-files
- ^? -&gt; backward-delete-char
-
- The following are the key bindings that are defined in vi
- command mode, this being specified by them all starting with
- a meta character. As mentioned above, once in command mode
- the initial meta character is optional. For example, you
- might enter command mode by typing Esc, and then press h
- twice to move the cursor two positions to the left. Both h
- characters get quietly converted to M-h before being com-
- pared to the key-binding table, the first one because Escape
- followed by a character is always converted to the
- equivalent meta character, and the second because command
- mode was already active.
-
- M-\ -&gt; cursor-right (Meta-space)
- M-$ -&gt; end-of-line
- M-* -&gt; expand-filename
- M-+ -&gt; down-history
- M-- -&gt; up-history
- M-&lt; -&gt; beginning-of-history
- M-&gt; -&gt; end-of-history
- M-^ -&gt; beginning-of-line
- M-; -&gt; repeat-find-char
- M-, -&gt; invert-refind-char
- M-| -&gt; goto-column
- M-~ -&gt; change-case
- M-. -&gt; vi-repeat-change
- M-% -&gt; find-parenthesis
- M-a -&gt; vi-append
- M-A -&gt; vi-append-at-eol
- M-b -&gt; backward-word
- M-B -&gt; backward-word
- M-C -&gt; vi-change-rest-of-line
- M-cb -&gt; vi-backward-change-word
- M-cB -&gt; vi-backward-change-word
- M-cc -&gt; vi-change-line
- M-ce -&gt; vi-forward-change-word
- M-cE -&gt; vi-forward-change-word
- M-cw -&gt; vi-forward-change-word
- M-cW -&gt; vi-forward-change-word
- M-cF -&gt; vi-backward-change-find
- M-cf -&gt; vi-forward-change-find
- M-cT -&gt; vi-backward-change-to
- M-ct -&gt; vi-forward-change-to
- M-c; -&gt; vi-change-refind
- M-c, -&gt; vi-change-invert-refind
- M-ch -&gt; vi-backward-change-char
- M-c^H -&gt; vi-backward-change-char
- M-c^? -&gt; vi-backward-change-char
- M-cl -&gt; vi-forward-change-char
- M-c\ -&gt; vi-forward-change-char (Meta-c-space)
- M-c^ -&gt; vi-change-to-bol
- M-c0 -&gt; vi-change-to-bol
- M-c$ -&gt; vi-change-rest-of-line
- M-c| -&gt; vi-change-to-column
- M-c% -&gt; vi-change-to-parenthesis
- M-dh -&gt; backward-delete-char
- M-d^H -&gt; backward-delete-char
- M-d^? -&gt; backward-delete-char
- M-dl -&gt; forward-delete-char
- M-d -&gt; forward-delete-char (Meta-d-space)
- M-dd -&gt; delete-line
- M-db -&gt; backward-delete-word
- M-dB -&gt; backward-delete-word
- M-de -&gt; forward-delete-word
- M-dE -&gt; forward-delete-word
- M-dw -&gt; forward-delete-word
- M-dW -&gt; forward-delete-word
- M-dF -&gt; backward-delete-find
- M-df -&gt; forward-delete-find
- M-dT -&gt; backward-delete-to
- M-dt -&gt; forward-delete-to
- M-d; -&gt; delete-refind
- M-d, -&gt; delete-invert-refind
- M-d^ -&gt; backward-kill-line
- M-d0 -&gt; backward-kill-line
- M-d$ -&gt; kill-line
- M-D -&gt; kill-line
- M-d| -&gt; delete-to-column
- M-d% -&gt; delete-to-parenthesis
- M-e -&gt; forward-word
- M-E -&gt; forward-word
- M-f -&gt; forward-find-char
- M-F -&gt; backward-find-char
- M-- -&gt; up-history
- M-h -&gt; cursor-left
- M-H -&gt; beginning-of-history
- M-i -&gt; vi-insert
- M-I -&gt; vi-insert-at-bol
- M-j -&gt; down-history
- M-J -&gt; history-search-forward
- M-k -&gt; up-history
- M-K -&gt; history-search-backward
- M-l -&gt; cursor-right
- M-L -&gt; end-of-history
- M-n -&gt; history-re-search-forward
- M-N -&gt; history-re-search-backward
- M-p -&gt; append-yank
- M-P -&gt; yank
- M-r -&gt; vi-replace-char
- M-R -&gt; vi-overwrite
- M-s -&gt; vi-forward-change-char
- M-S -&gt; vi-change-line
- M-t -&gt; forward-to-char
- M-T -&gt; backward-to-char
- M-u -&gt; vi-undo
- M-w -&gt; forward-to-word
- M-W -&gt; forward-to-word
- M-x -&gt; forward-delete-char
- M-X -&gt; backward-delete-char
- M-yh -&gt; backward-copy-char
- M-y^H -&gt; backward-copy-char
- M-y^? -&gt; backward-copy-char
- M-yl -&gt; forward-copy-char
- M-y\ -&gt; forward-copy-char (Meta-y-space)
- M-ye -&gt; forward-copy-word
- M-yE -&gt; forward-copy-word
- M-yw -&gt; forward-copy-word
- M-yW -&gt; forward-copy-word
- M-yb -&gt; backward-copy-word
- M-yB -&gt; backward-copy-word
- M-yf -&gt; forward-copy-find
- M-yF -&gt; backward-copy-find
- M-yt -&gt; forward-copy-to
- M-yT -&gt; backward-copy-to
- M-y; -&gt; copy-refind
- M-y, -&gt; copy-invert-refind
- M-y^ -&gt; copy-to-bol
- M-y0 -&gt; copy-to-bol
- M-y$ -&gt; copy-rest-of-line
- M-yy -&gt; copy-line
- M-Y -&gt; copy-line
- M-y| -&gt; copy-to-column
- M-y% -&gt; copy-to-parenthesis
- M-^E -&gt; emacs-mode
- M-^H -&gt; cursor-left
- M-^? -&gt; cursor-left
- M-^L -&gt; clear-screen
- M-^N -&gt; down-history
- M-^P -&gt; up-history
- M-^R -&gt; redisplay
- M-^D -&gt; list-or-eof
- M-^I -&gt; complete-word
- M-\r -&gt; newline
- M-\n -&gt; newline
- M-^X^R -&gt; read-init-files
- M-^Xh -&gt; list-history
-
- M-0, M-1, ... M-9 -&gt; digit-argument (see below)
-
- Note that ^I is what the TAB key generates.
-
-
-</pre><h2>ENTERING REPEAT COUNTS</h2><pre>
- Many of the key binding functions described previously, take
- an optional count, typed in before the target keysequence.
- This is interpreted as a repeat count by most bindings. A
- notable exception is the goto-column binding, which inter-
- prets the count as a column number.
-
- By default you can specify this count argument by pressing
- the meta key while typing in the numeric count. This relies
- on the digit-argument action being bound to Meta-0, Meta-1
- etc. Once any one of these bindings has been activated, you
- can optionally take your finger off the meta key to type in
- the rest of the number, since every numeric digit thereafter
- is treated as part of the number, unless it is preceded by
- the literal-next binding. As soon as a non-digit, or literal
- digit key is pressed the repeat count is terminated and
- either causes the just typed character to be added to the
- line that many times, or causes the next key-binding func-
- tion to be given that argument.
-
- For example, in emacs mode, typing:
-
- M-12a
-
- causes the letter 'a' to be added to the line 12 times,
- whereas
-
- M-4M-c
-
- Capitalizes the next 4 words.
-
- In vi command mode the Meta modifier is automatically added
- to all characters typed in, so to enter a count in vi
- command-mode, just involves typing in the number, just as at
- it does in the vi editor itself. So for example, in vi com-
- mand mode, typing:
-
- 4w2x
-
- moves the cursor four words to the right, then deletes two
- characters.
-
- You can also bind digit-argument to other key sequences. If
- these end in a numeric digit, that digit gets appended to
- the current repeat count. If it doesn't end in a numeric
- digit, a new repeat count is started with a value of zero,
- and can be completed by typing in the number, after letting
- go of the key which triggered the digit-argument action.
-
-
-</pre><h2>THE TECLA CONFIGURATION FILE</h2><pre>
- By default, the first call to gl_get_line() looks for a file
- called .teclarc in your home directory (ie. ~/.teclarc). If
- it finds this file, it reads it, interpreting each line as
- defining a new key binding or an editing configuration
- option. Since the emacs keybindings are installed by
- default, if you want to use the non-default vi editing mode,
- the most important item to go in this file is the following
- line:
-
- edit-mode vi
-
- This will re-configure the default bindings for vi-mode. The
- complete set of arguments that this command accepts are:
-
- vi - Install key-bindings like those of the vi
- editor.
- emacs - Install key-bindings like those of the emacs
- editor. This is the default.
- none - Use just the native line editing facilities
- provided by the terminal driver.
-
- To prevent the terminal bell from being rung, such as when
- an unrecognized control-sequence is typed, place the follow-
- ing line in the configuration file:
-
- nobeep
-
- An example of a key binding line in the configuration file
- is the following.
-
- bind M-[2~ insert-mode
-
- On many keyboards, the above key sequence is generated when
- one presses the insert key, so with this keybinding, one can
- toggle between the emacs-mode insert and overwrite modes by
- hitting one key. One could also do it by typing out the
- above sequence of characters one by one. As explained above,
- the M- part of this sequence can be typed either by pressing
- the escape key before the following key, or by pressing the
- Meta key at the same time as the following key. Thus if you
- had set the above key binding, and the insert key on your
- keyboard didn't generate the above key sequence, you could
- still type it in either of the following 2 ways.
-
- 1. Hit the escape key momentarily, then press '[', then '2', then
- finally '~'.
-
- 2. Press the meta key at the same time as pressing the '[' key,
- then press '2', then '~'.
-
- If you set a keybinding for a key-sequence that is already
- bound to a function, the new binding overrides the old one.
- If in the new binding you omit the name of the new function
- to bind to the key-sequence, the original binding becomes
- undefined.
-
- Starting with versions of libtecla later than 1.3.3 it is
- now possible to bind keysequences that begin with a print-
- able character. Previously key-sequences were required to
- start with a control or meta character.
-
- Note that the special keywords "up", "down", "left" and
- "right" refer to the arrow keys, and are thus not treated as
- keysequences. So, for example, to rebind the up and down
- arrow keys to use the history search mechanism instead of
- the simple history recall method, you could place the fol-
- lowing in your configuration file:
-
- bind up history-search-backwards
- bind down history-search-backwards
-
- To unbind an existing binding, you can do this with the bind
- command by omitting to name any action to rebind the key
- sequence to. For example, by not specifying an action func-
- tion, the following command unbinds the default beginning-
- of-line action from the ^A key sequence:
-
- bind ^A
-
-
-</pre><h2>ALTERNATE CONFIGURATION SOURCES</h2><pre>
- As mentioned above, by default users have the option of con-
- figuring the behavior of gl_get_line() via a configuration
- file called .teclarc in their home directories. The fact
- that all applications share this same configuration file is
- both an advantage and a disadvantage. In most cases it is
- an advantage, since it encourages uniformity, and frees the
- user from having to configure each application separately.
- In some applications, however, this single means of confi-
- guration is a problem. This is particularly true of embedded
- software, where there's no filesystem to read a configura-
- tion file from, and also in applications where a radically
- different choice of keybindings is needed to emulate a
- legacy keyboard interface. To cater for such cases, the
- following function allows the application to control where
- configuration information is read from.
-
-
- int gl_configure_getline(GetLine *gl,
- const char *app_string,
- const char *app_file,
- const char *user_file);
-
-
- It allows the configuration commands that would normally be
- read from a user's ~/.teclarc file, to be read from any or
- none of, a string, an application specific configuration
- file, and/or a user-specific configuration file. If this
- function is called before the first call to gl_get_line(),
- the default behavior of reading ~/.teclarc on the first call
- to gl_get_line() is disabled, so all configuration must be
- achieved using the configuration sources specified with this
- function.
-
- If app_string != NULL, then it is interpreted as a string
- containing one or more configuration commands, separated
- from each other in the string by embedded newline charac-
- ters. If app_file != NULL then it is interpreted as the full
- pathname of an application-specific configuration file. If
- user_file != NULL then it is interpreted as the full path-
- name of a user-specific configuration file, such as
- ~/.teclarc. For example, in the following call,
-
- gl_configure_getline(gl, "edit-mode vi \n nobeep",
- "/usr/share/myapp/teclarc",
- "~/.teclarc");
-
- the app_string argument causes the calling application to
- start in vi edit-mode, instead of the default emacs mode,
- and turns off the use of the terminal bell by the library.
- It then attempts to read system-wide configuration commands
- from an optional file called /usr/share/myapp/teclarc, then
- finally reads user-specific configuration commands from an
- optional .teclarc file in the user's home directory. Note
- that the arguments are listed in ascending order of prior-
- ity, with the contents of app_string being potentially over-
- riden by commands in app_file, and commands in app_file
- potentially being overriden by commands in user_file.
- You can call this function as many times as needed, the
- results being cumulative, but note that copies of any
- filenames specified via the app_file and user_file arguments
- are recorded internally for subsequent use by the read-
- init-files key-binding function, so if you plan to call this
- function multiple times, be sure that the last call speci-
- fies the filenames that you want re-read when the user
- requests that the configuration files be re-read.
-
-
-</pre><h2>FILENAME AND TILDE COMPLETION</h2><pre>
- With the default key bindings, pressing the TAB key (aka.
- ^I) results in gl_get_line() attempting to complete the
- incomplete filename that precedes the cursor. gl_get_line()
- searches backwards from the cursor, looking for the start of
- the filename, stopping when it hits either a space or the
- start of the line. If more than one file has the specified
- prefix, gl_get_line() completes the filename up to the point
- at which the ambiguous matches start to differ, then lists
- the possible matches.
-
- In addition to literally written filenames, gl_get_line()
- can complete files that start with ~/ and ~user/ expressions
- and that contain $envvar expressions. In particular, if you
- hit TAB within an incomplete ~user, expression,
- gl_get_line() will attempt to complete the username, listing
- any ambiguous matches.
-
- The completion binding is implemented using the
- cpl_word_completions() function, which is also available
- separately to users of this library. See the
- cpl_word_completions(3) man page for more details.
-
-
-</pre><h2>CUSTOMIZED WORD COMPLETION</h2><pre>
- If in your application, you would like to have TAB comple-
- tion complete other things in addition to or instead of
- filenames, you can arrange this by registering an alternate
- completion callback function, via a call to the
- gl_customize_completion() function.
-
- int gl_customize_completion(GetLine *gl, void *data,
- CplMatchFn *match_fn);
-
- The data argument provides a way for your application to
- pass arbitrary, application-specific information to the
- callback function. This is passed to the callback every time
- that it is called. It might for example, point to the symbol
- table from which possible completions are to be sought. The
- match_fn argument specifies the callback function to be
- called. The CplMatchFn function type is defined in
- libtecla.h, as is a CPL_MATCH_FN() macro that you can use to
- declare and prototype callback functions. The declaration
- and responsibilities of callback functions are described in
- depth in the <a href="cpl_complete_word.html">cpl_complete_word(3)</a> man page.
-
- In brief, the callback function is responsible for looking
- backwards in the input line, back from the point at which
- the user pressed TAB, to find the start of the word being
- completed. It then must lookup possible completions of this
- word, and record them one by one in the WordCompletion
- object that is passed to it as an argument, by calling the
- cpl_add_completion() function. If the callback function
- wishes to provide filename completion in addition to its own
- specific completions, it has the option of itself calling
- the builtin file-name completion callback. This also, is
- documented in the <a href="cpl_complete_word.html">cpl_complete_word(3)</a> man page.
-
- Note that if you would like gl_get_line() to return the
- current input line when a successful completion is been
- made, you can arrange this when you call
- cpl_add_completion(), by making the last character of the
- continuation suffix a newline character. If you do this, the
- input line will be updated to display the completion,
- together with any contiuation suffix up to the newline char-
- acter, then gl_get_line() will return this input line.
-
-
-</pre><h2>FILENAME EXPANSION</h2><pre>
- With the default key bindings, pressing ^X* causes
- gl_get_line() to expand the filename that precedes the cur-
- sor, replacing ~/ and ~user/ expressions with the
- corresponding home directories, and replacing $envvar
- expressions with the value of the specified environment
- variable, then if there are any wildcards, replacing the so
- far expanded filename with a space-separated list of the
- files which match the wild cards.
-
- The expansion binding is implemented using the
- ef_expand_file() function. See the <a href="ef_expand_file.html">ef_expand_file(3)</a> man
- page for more details.
-
-
-</pre><h2>RECALLING PREVIOUSLY TYPED LINES</h2><pre>
- Every time that a new line is entered by the user, it is
- appended to a list of historical input lines maintained
- within the GetLine resource object. You can traverse up and
- down this list using the up and down arrow keys. Alterna-
- tively, you can do the same with the ^P, and ^N keys, and in
- vi command mode you can alternatively use the k and j char-
- acters. Thus pressing up-arrow once, replaces the current
- input line with the previously entered line. Pressing up-
- arrow again, replaces this with the line that was entered
- before it, etc.. Having gone back one or more lines into the
- history list, one can return to newer lines by pressing
- down-arrow one or more times. If you do this sufficient
- times, you will return to the original line that you were
- entering when you first hit up-arrow.
-
- Note that in vi mode, all of the history recall functions
- switch the library into command mode.
-
- In emacs mode the M-p and M-n keys work just like the ^P and
- ^N keys, except that they skip all but those historical
- lines which share the prefix that precedes the cursor. In vi
- command mode the upper case K and J characters do the same
- thing, except that the string that they search for includes
- the character under the cursor as well as what precedes it.
-
- Thus for example, suppose that you were in emacs mode, and
- you had just entered the following list of commands in the
- order shown:
-
- ls ~/tecla/
- cd ~/tecla
- ls -l getline.c
- emacs ~/tecla/getline.c
-
- If you next typed:
-
- ls
-
- and then hit M-p, then rather than returning the previously
- typed emacs line, which doesn't start with "ls",
- gl_get_line() would recall the "ls -l getline.c" line.
- Pressing M-p again would recall the "ls ~/tecla/" line.
-
-
-</pre><h2>HISTORY FILES</h2><pre>
- To save the contents of the history buffer before quitting
- your application, and subsequently restore them when you
- next start the application, the following functions are pro-
- vided.
-
-
- int gl_save_history(GetLine *gl, const char *filename,
- const char *comment, int max_lines);
- int gl_load_history(GetLine *gl, const char *filename,
- const char *comment);
-
-
- The filename argument specifies the name to give the history
- file when saving, or the name of an existing history file,
- when loading. This may contain home-directory and environ-
- ment variable expressions, such as "~/.myapp_history" or
- "$HOME/.myapp_history".
- Along with each history line, extra information about it,
- such as when it was entered by the user, and what its nest-
- ing level is, is recorded as a comment preceding the line in
- the history file. Writing this as a comment allows the his-
- tory file to double as a command file, just in case you wish
- to replay a whole session using it. Since comment prefixes
- differ in different languages, the comment argument is pro-
- vided for specifying the comment prefix. For example, if
- your application were a unix shell, such as the bourne
- shell, you would specify "#" here. Whatever you choose for
- the comment character, you must specify the same prefix to
- gl_load_history() that you used when you called
- gl_save_history() to write the history file.
-
- The max_lines must be either -1 to specify that all lines in
- the history list be saved, or a positive number specifying a
- ceiling on how many of the most recent lines should be
- saved.
-
- Both fuctions return non-zero on error, after writing an
- error message to stderr. Note that gl_load_history() does
- not consider the non-existence of a file to be an error.
-
-
-</pre><h2>MULTIPLE HISTORY LISTS</h2><pre>
- If your application uses a single GetLine object for enter-
- ing many different types of input lines, you may wish
- gl_get_line() to distinguish the different types of lines in
- the history list, and only recall lines that match the
- current type of line. To support this requirement,
- gl_get_line() marks lines being recorded in the history list
- with an integer identifier chosen by the application. Ini-
- tially this identifier is set to 0 by new_GetLine(), but it
- can be changed subsequently by calling gl_group_history().
-
-
- int gl_group_history(GetLine *gl, unsigned id);
-
-
- The integer identifier id can be any number chosen by the
- application, but note that gl_save_history() and
- gl_load_history() preserve the association between identif-
- iers and historical input lines between program invokations,
- so you should choose fixed identifiers for the different
- types of input line used by your application.
-
- Whenever gl_get_line() appends a new input line to the his-
- tory list, the current history identifier is recorded with
- it, and when it is asked to recall a historical input line,
- it only recalls lines that are marked with the current iden-
- tifier.
-
-</pre><h2>DISPLAYING HISTORY</h2><pre>
- The history list can be displayed by calling
- gl_show_history().
-
-
- int gl_show_history(GetLine *gl, FILE *fp,
- const char *fmt,
- int all_groups,
- int max_lines);
-
-
- This displays the current contents of the history list to
- the stdio output stream fp. If the max_lines argument is
- greater than or equal to zero, then no more than this number
- of the most recent lines will be displayed. If the
- all_groups argument is non-zero, lines from all history
- groups are displayed. Otherwise just those of the currently
- selected history group are displayed. The format string
- argument, fmt, determines how the line is displayed. This
- can contain arbitrary characters which are written verbatim,
- interleaved with any of the following format directives:
-
- %D - The date on which the line was originally
- entered, formatted like 2001-11-20.
- %T - The time of day when the line was entered,
- formatted like 23:59:59.
- %N - The sequential entry number of the line in
- the history buffer.
- %G - The number of the history group which the
- line belongs to.
- %% - A literal % character.
- %H - The history line itself.
-
- Thus a format string like "%D %T %H0 would output something
- like:
-
- 2001-11-20 10:23:34 Hello world
-
- Note the inclusion of an explicit newline character in the
- format string.
-
-
-</pre><h2>LOOKING UP HISTORY</h2><pre>
- The gl_lookup_history() function allows the calling applica-
- tion to look up lines in the history list.
-
-
- typedef struct {
- const char *line; /* The requested historical */
- /* line. */
- unsigned group; /* The history group to which */
- /* the line belongs. */
- time_t timestamp; /* The date and time at which */
- /* the line was originally */
- /* entered. */
- } GlHistoryLine;
-
- int gl_lookup_history(GetLine *gl, unsigned long id,
- GlHistoryLine *hline);
-
-
- The id argument indicates which line to look up, where the
- first line that was entered in the history list after
- new_GetLine() was called, is denoted by 0, and subsequently
- entered lines are denoted with successively higher numbers.
- Note that the range of lines currently preserved in the his-
- tory list can be queried by calling the
- gl_range_of_history() function, described later. If the
- requested line is in the history list, the details of the
- line are recorded in the variable pointed to by the hline
- argument, and 1 is returned. Otherwise 0 is returned, and
- the variable pointed to by hline is left unchanged.
-
- Beware that the string returned in hline-&gt;line is part of
- the history buffer, so it must not be modified by the
- caller, and will be recycled on the next call to any func-
- tion that takes gl as its argument. Therefore you should
- make a private copy of this string if you need to keep it
- around.
-
-
-</pre><h2>MISCELLANEOUS HISTORY CONFIGURATION</h2><pre>
- If you wish to change the size of the history buffer that
- was originally specified in the call to new_GetLine(), you
- can do so with the gl_resize_history() function.
-
-
- int gl_resize_history(GetLine *gl, size_t histlen);
-
-
- The histlen argument specifies the new size in bytes, and if
- you specify this as 0, the buffer will be deleted.
-
- As mentioned in the discussion of new_GetLine(), the number
- of lines that can be stored in the history buffer, depends
- on the lengths of the individual lines. For example, a 1000
- byte buffer could equally store 10 lines of average length
- 100 bytes, or 2 lines of average length 50 bytes. Although
- the buffer is never expanded when new lines are added, a
- list of pointers into the buffer does get expanded when
- needed to accomodate the number of lines currently stored in
- the buffer. To place an upper limit on the number of lines
- in the buffer, and thus a ceiling on the amount of memory
- used in this list, you can call the gl_limit_history()
- function.
-
-
- void gl_limit_history(GetLine *gl, int max_lines);
-
-
- The max_lines should either be a positive number &gt;= 0,
- specifying an upper limit on the number of lines in the
- buffer, or be -1 to cancel any previously specified limit.
- When a limit is in effect, only the max_lines most recently
- appended lines are kept in the buffer. Older lines are dis-
- carded.
-
- To discard lines from the history buffer, use the
- gl_clear_history() function.
-
- void gl_clear_history(GetLine *gl, int all_groups);
-
- The all_groups argument tells the function whether to delete
- just the lines associated with the current history group
- (see gl_group_history()), or all historical lines in the
- buffer.
-
- The gl_toggle_history() function allows you to toggle his-
- tory on and off without losing the current contents of the
- history list.
-
-
- void gl_toggle_history(GetLine *gl, int enable);
-
-
- Setting the enable argument to 0 turns off the history
- mechanism, and setting it to 1 turns it back on. When his-
- tory is turned off, no new lines will be added to the his-
- tory list, and history lookup key-bindings will act as
- though there is nothing in the history buffer.
-
-
-</pre><h2>QUERYING HISTORY INFORMATION</h2><pre>
- The configured state of the history list can be queried with
- the gl_history_state() function.
-
-
- typedef struct {
- int enabled; /* True if history is enabled */
- unsigned group; /* The current history group */
- int max_lines; /* The current upper limit on the */
- /* number of lines in the history */
- /* list, or -1 if unlimited. */
- } GlHistoryState;
-
- void gl_state_of_history(GetLine *gl,
- GlHistoryState *state);
-
- On return, the status information is recorded in the vari-
- able pointed to by the state argument.
-
- The gl_range_of_history() function returns the number and
- range of lines in the history list.
-
-
- typedef struct {
- unsigned long oldest; /* The sequential entry number */
- /* of the oldest line in the */
- /* history list. */
- unsigned long newest; /* The sequential entry number */
- /* of the newest line in the */
- /* history list. */
- int nlines; /* The number of lines in the */
- /* history list. */
- } GlHistoryRange;
-
- void gl_range_of_history(GetLine *gl, GlHistoryRange *range);
-
- The return values are recorded in the variable pointed to by
- the range argument. If the nlines member of this structure
- is greater than zero, then the oldest and newest members
- report the range of lines in the list, and
- newest=oldest+nlines-1. Otherwise they are both zero.
-
- The gl_size_of_history() function returns the total size of
- the history buffer and the amount of the buffer that is
- currently occupied.
-
- typedef struct {
- size_t size; /* The size of the history buffer */
- /* (bytes). */
- size_t used; /* The number of bytes of the */
- /* history buffer that are */
- /* currently occupied. */
- } GlHistorySize;
-
- void gl_size_of_history(GetLine *gl, GlHistorySize *size);
-
- On return, the size information is recorded in the variable
- pointed to by the size argument.
-
-
-</pre><h2>CHANGING TERMINALS</h2><pre>
- The new_GetLine() constructor function assumes that input is
- to be read from stdin, and output written to stdout. The
- following function allows you to switch to different input
- and output streams.
-
- int gl_change_terminal(GetLine *gl, FILE *input_fp,
- FILE *output_fp, const char *term);
-
- The gl argument is the object that was returned by
- new_GetLine(). The input_fp argument specifies the stream
- to read from, and output_fp specifies the stream to be writ-
- ten to. Only if both of these refer to a terminal, will
- interactive terminal input be enabled. Otherwise
- gl_get_line() will simply call fgets() to read command
- input. If both streams refer to a terminal, then they must
- refer to the same terminal, and the type of this terminal
- must be specified via the term argument. The value of the
- term argument is looked up in the terminal information data-
- base (terminfo or termcap), in order to determine which spe-
- cial control sequences are needed to control various aspects
- of the terminal. new_GetLine() for example, passes the
- return value of getenv("TERM") in this argument. Note that
- if one or both of input_fp and output_fp don't refer to a
- terminal, then it is legal to pass NULL instead of a termi-
- nal type.
-
- Note that if you want to pass file descriptors to
- gl_change_terminal(), you can do this by creating stdio
- stream wrappers using the POSIX fdopen() function.
-
-
-</pre><h2>EXTERNAL EVENT HANDLING</h2><pre>
- While gl_get_line() is waiting for keyboard input from the
- user, you can ask it to also watch for activity on arbitrary
- file descriptors, such as network sockets, pipes etc, and
- have it call functions of your choosing when activity is
- seen. This works on any system that has the select() system
- call, which is most, if not all flavors of unix. Registering
- a file descriptor to be watched by gl_get_line() involves
- calling the gl_watch_fd() function.
-
-
- int gl_watch_fd(GetLine *gl, int fd, GlFdEvent event,
- GlFdEventFn *callback, void *data);
-
-
- If this returns non-zero, then it means that either your
- arguments are invalid, or that this facility isn't supported
- on the host system.
-
- The fd argument is the file descriptor to be watched. The
- event argument specifies what type of activity is of
- interest, chosen from the following enumerated values:
-
-
- GLFD_READ - Watch for the arrival of data to be read.
- GLFD_WRITE - Watch for the ability to write to the file
- descriptor without blocking.
- GLFD_URGENT - Watch for the arrival of urgent
- out-of-band data on the file descriptor.
-
-
- The callback argument is the function to call when the
- selected activity is seen. It should be defined with the
- following macro, which is defined in libtecla.h.
-
-
- #define GL_FD_EVENT_FN(fn) GlFdStatus (fn)(GetLine *gl, \
- void *data, int fd, \
- GlFdEvent event)
-
- The data argument of the gl_watch_fd() function is passed to
- the callback function for its own use, and can point to any-
- thing you like, including NULL. The file descriptor and the
- event argument are also passed to the callback function, and
- this potentially allows the same callback function to be
- registered to more than one type of event and/or more than
- one file descriptor. The return value of the callback func-
- tion should be one of the following values.
-
-
- GLFD_ABORT - Tell gl_get_line() to abort with an
- error (errno won't be set, so set it
- appropriately yourself if you need it).
- GLFD_REFRESH - Redraw the input line then continue
- waiting for input. Return this if
- your callback wrote to the terminal.
- GLFD_CONTINUE - Continue to wait for input, without
- redrawing the line.
-
- Note that before calling the callback, gl_get_line() blocks
- most signals, and leaves its own signal handlers installed,
- so if you need to catch a particular signal you will need to
- both temporarily install your own signal handler, and
- unblock the signal. Be sure to re-block the signal (if it
- was originally blocked) and reinstate the original signal
- handler, if any, before returning.
-
- Your callback shouldn't try to read from the terminal, which
- is left in raw mode as far as input is concerned. You can
- however write to the terminal as usual, since features like
- conversion of newline to carriage-return/linefeed are re-
- enabled while the callback is running. If your callback
- function does write to the terminal, be sure to output a
- newline first, and when your callback returns, tell
- gl_get_line() that the input line needs to be redrawn, by
- returning the GLFD_REFRESH status code.
-
- To remove a callback function that you previously registered
- for a given file descriptor and event, simply call
- gl_watch_fd() with the same file descriptor and event argu-
- ments, but with a callback argument of 0. The data argument
- is ignored in this case.
-
-
-</pre><h2>SIGNAL HANDLING DEFAULTS</h2><pre>
- By default, the gl_get_line() function intercepts a number
- of signals. This is particularly important for signals which
- would by default terminate the process, since the terminal
- needs to be restored to a usable state before this happens.
- In this section, the signals that are trapped by default,
- and how gl_get_line() responds to them, is described. Chang-
- ing these defaults is the topic of the following section.
-
- When the following subset of signals are caught,
- gl_get_line() first restores the terminal settings and sig-
- nal handling to how they were before gl_get_line() was
- called, resends the signal, to allow the calling
- application's signal handlers to handle it, then if the pro-
- cess still exists, gl_get_line() returns NULL and sets errno
- as specified below.
-
-
- SIGINT - This signal is generated both by the keyboard
- interrupt key (usually ^C), and the keyboard
- break key.
-
- errno=EINTR
-
- SIGHUP - This signal is generated when the controlling
- terminal exits.
-
- errno=ENOTTY
-
- SIGPIPE - This signal is generated when a program attempts
- to write to a pipe who's remote end isn't being
- read by any process. This can happen for example
- if you have called gl_change_terminal() to
- redirect output to a pipe hidden under a pseudo
- terminal.
-
- errno=EPIPE
-
- SIGQUIT - This signal is generated by the keyboard quit
- key (usually ^\).
-
- errno=EINTR
-
- SIGABRT - This signal is generated by the standard C,
- abort() function. By default it both
- terminates the process and generates a core
- dump.
-
- errno=EINTR
-
- SIGTERM - This is the default signal that the UN*X
- kill command sends to processes.
-
- errno=EINTR
-
- Note that in the case of all of the above signals, POSIX
- mandates that by default the process is terminated, with the
- addition of a core dump in the case of the SIGQUIT signal.
- In other words, if the calling application doesn't override
- the default handler by supplying its own signal handler,
- receipt of the corresponding signal will terminate the
- application before gl_get_line() returns.
-
- If gl_get_line() aborts with errno set to EINTR, you can
- find out what signal caused it to abort, by calling the fol-
- lowing function.
-
- int gl_last_signal(const GetLine *gl);
-
- This returns the numeric code (eg. SIGINT) of the last sig-
- nal that was received during the most recent call to
- gl_get_line(), or -1 if no signals were received.
-
- On systems that support it, when a SIGWINCH (window change)
- signal is received, gl_get_line() queries the terminal to
- find out its new size, redraws the current input line to
- accomodate the new size, then returns to waiting for key-
- board input from the user. Unlike other signals, this signal
- isn't resent to the application.
-
- Finally, the following signals cause gl_get_line() to first
- restore the terminal and signal environment to that which
- prevailed before gl_get_line() was called, then resend the
- signal to the application. If the process still exists after
- the signal has been delivered, then gl_get_line() then re-
- establishes its own signal handlers, switches the terminal
- back to raw mode, redisplays the input line, and goes back
- to awaiting terminal input from the user.
-
- SIGCONT - This signal is generated when a suspended
- process is resumed.
-
- SIGPWR - This signal is generated when a power failure
- occurs (presumably when the system is on a
- UPS).
-
- SIGALRM - This signal is generated when a timer
- expires.
- SIGUSR1 - An application specific signal.
-
- SIGUSR2 - Another application specific signal.
-
- SIGVTALRM - This signal is generated when a virtual
- timer expires (see man setitimer(2)).
-
- SIGXCPU - This signal is generated when a process
- exceeds its soft CPU time limit.
-
- SIGTSTP - This signal is generated by the terminal
- suspend key, which is usually ^Z, or the
- delayed terminal suspend key, which is
- usually ^Y.
-
- SIGTTIN - This signal is generated if the program
- attempts to read from the terminal while the
- program is running in the background.
-
- SIGTTOU - This signal is generated if the program
- attempts to write to the terminal while the
- program is running in the background.
-
-
- Obviously not all of the above signals are supported on all
- systems, so code to support them is conditionally compiled
- into the tecla library.
-
- Note that if SIGKILL, which by definition can't be caught,
- or any of the hardware generated exception signals, such as
- SIGSEGV, SIGBUS and SIGFPE, are received and unhandled while
- gl_get_line() has the terminal in raw mode, the program will
- be terminated without the terminal having been restored to a
- usable state. In practice, job-control shells usually reset
- the terminal settings when a process relinquishes the con-
- trolling terminal, so this is only a problem with older
- shells.
-
-
-</pre><h2>CUSTOMIZED SIGNAL HANDLING</h2><pre>
- The previous section listed the signals that gl_get_line()
- traps by default, and described how it responds to them.
- This section describes how to both add and remove signals
- from the list of trapped signals, and how to specify how
- gl_get_line() should respond to a given signal.
-
- If you don't need gl_get_line() to do anything in response
- to a signal that it normally traps, you can tell to
- gl_get_line() to ignore that signal by calling
- gl_ignore_signal().
-
- int gl_ignore_signal(GetLine *gl, int signo);
- The signo argument is the number of the signal (eg. SIGINT)
- that you want to have ignored. If the specified signal isn't
- currently one of those being trapped, this function does
- nothing.
-
- The gl_trap_signal() function allows you to either add a new
- signal to the list that gl_get_line() traps, or modify how
- it responds to a signal that it already traps.
-
- int gl_trap_signal(GetLine *gl, int signo, unsigned flags,
- GlAfterSignal after, int errno_value);
-
- The signo argument is the number of the signal that you wish
- to have trapped. The flags argument is a set of flags which
- determine the environment in which the application's signal
- handler is invoked, the after argument tells gl_get_line()
- what to do after the application's signal handler returns,
- and errno_value tells gl_get_line() what to set errno to if
- told to abort.
-
- The flags argument is a bitwise OR of zero or more of the
- following enumerators:
-
- GLS_RESTORE_SIG - Restore the caller's signal
- environment while handling the
- signal.
-
- GLS_RESTORE_TTY - Restore the caller's terminal settings
- while handling the signal.
-
- GLS_RESTORE_LINE - Move the cursor to the start of the
- line following the input line before
- invoking the application's signal
- handler.
-
- GLS_REDRAW_LINE - Redraw the input line when the
- application's signal handler returns.
-
- GLS_UNBLOCK_SIG - Normally, if the calling program has
- a signal blocked (man sigprocmask),
- gl_get_line() does not trap that
- signal. This flag tells gl_get_line()
- to trap the signal and unblock it for
- the duration of the call to
- gl_get_line().
-
- GLS_DONT_FORWARD - If this flag is included, the signal
- will not be forwarded to the signal
- handler of the calling program.
-
- Two commonly useful flag combinations are also enumerated as
- follows:
- GLS_RESTORE_ENV = GLS_RESTORE_SIG | GLS_RESTORE_TTY |
- GLS_REDRAW_LINE
-
- GLS_SUSPEND_INPUT = GLS_RESTORE_ENV | GLS_RESTORE_LINE
-
-
- If your signal handler, or the default system signal handler
- for this signal, if you haven't overriden it, never either
- writes to the terminal, nor suspends or terminates the cal-
- ling program, then you can safely set the flags argument to
- 0.
-
- If your signal handler always writes to the terminal, reads
- from it, or suspends or terminates the program, you should
- specify the flags argument as GL_SUSPEND_INPUT, so that:
-
- 1. The cursor doesn't get left in the middle of the input
- line.
- 2. So that the user can type in input and have it echoed.
- 3. So that you don't need to end each output line with
- \r\n, instead of just \n.
-
- The GL_RESTORE_ENV combination is the same as
- GL_SUSPEND_INPUT, except that it doesn't move the cursor,
- and if your signal handler doesn't read or write anything to
- the terminal, the user won't see any visible indication that
- a signal was caught. This can be useful if you have a signal
- handler that only occasionally writes to the terminal, where
- using GL_SUSPEND_LINE would cause the input line to be
- unnecessarily duplicated when nothing had been written to
- the terminal. Such a signal handler, when it does write to
- the terminal, should be sure to start a new line at the
- start of its first write, by writing a new line before
- returning. If the signal arrives while the user is entering
- a line that only occupies a signal terminal line, or if the
- cursor is on the last terminal line of a longer input line,
- this will have the same effect as GL_SUSPEND_INPUT. Other-
- wise it will start writing on a line that already contains
- part of the displayed input line. This doesn't do any harm,
- but it looks a bit ugly, which is why the GL_SUSPEND_INPUT
- combination is better if you know that you are always going
- to be writting to the terminal.
-
- The after argument, which determines what gl_get_line() does
- after the application's signal handler returns (if it
- returns), can take any one of the following values:
-
- GLS_RETURN - Return the completed input line, just as
- though the user had pressed the return
- key.
-
- GLS_ABORT - Cause gl_get_line() to return NULL.
- GLS_CONTINUE - Resume command line editing.
-
- The errno_value argument is intended to be combined with the
- GLS_ABORT option, telling gl_get_line() what to set the
- standard errno variable to before returning NULL to the cal-
- ling program. It can also, however, be used with the
- GL_RETURN option, in case you wish to have a way to distin-
- guish between an input line that was entered using the
- return key, and one that was entered by the receipt of a
- signal.
-
-
-</pre><h2>THE TERMINAL SIZE</h2><pre>
- On most systems the combination of the TIOCGWINSZ ioctl and
- the SIGWINCH signal is used to maintain an accurate idea of
- the terminal size. The terminal size is newly queried every
- time that gl_get_line() is called and whenever a SIGWINCH
- signal is received.
-
- On the few systems where this mechanism isn't available, at
- startup new_GetLine() first looks for the LINES and COLUMNS
- environment variables. If these aren't found, or they con-
- tain unusable values, then if a terminal information data-
- base like terminfo or termcap is available, the default size
- of the terminal is looked up in this database. If this too
- fails to provide the terminal size, a default size of 80
- columns by 24 lines is used. If this default isn't appropri-
- ate for your system, gl_terminal_size() can be used to sup-
- ply a different fallback.
-
- The gl_terminal_size() function allows you to query the
- current size of the terminal, and install an alternate fall-
- back size for cases where the size isn't available. Beware
- that the terminal size won't be available if reading from a
- pipe or a file, so the default values can be important even
- on systems that do support ways of finding out the terminal
- size.
-
- typedef struct {
- int nline; /* The terminal has nline lines */
- int ncolumn; /* The terminal has ncolumn columns */
- } GlTerminalSize;
-
- GlTerminalSize gl_terminal_size(GetLine *gl,
- int def_ncolumn,
- int def_nline);
-
- This function first updates gl_get_line()'s idea of the ter-
- minal size, then records its findings in the return value.
-
- The def_ncolumn and def_nline specify the default number of
- terminal columns and lines to use if the terminal size can't
- be determined.
-
-
-</pre><h2>HIDING WHAT YOU TYPE</h2><pre>
- When entering sensitive information, such as passwords, it
- is best not to have the text that you are entering echoed on
- the terminal. Furthermore, such text should not be recorded
- in the history list, since somebody finding your terminal
- unattended could then recall it, or somebody snooping
- through your directories could see it in your history file.
- With this in mind, the gl_echo_mode() function allows you to
- toggle on and off the display and archival of any text that
- is subsequently entered in calls to gl_get_line().
-
-
- int gl_echo_mode(GetLine *gl, int enable);
-
-
- The enable argument specifies whether entered text should be
- visible or not. If it is 0, then subsequently entered lines
- will not be visible on the terminal, and will not be
- recorded in the history list. If it is 1, then subsequent
- input lines will be displayed as they are entered, and pro-
- vided that history hasn't been turned off via a call to
- gl_toggle_history(), then they will also be archived in the
- history list. Finally, if the enable argument is -1, then
- the echoing mode is left unchanged, which allows you to
- non-destructively query the current setting via the return
- value. In all cases, the return value of the function is 0
- if echoing was disabled before the function was called, and
- 1 if it was enabled.
-
- When echoing is turned off, note that although tab comple-
- tion will invisibly complete your prefix as far as possible,
- ambiguous completions will not be displayed.
-
-
-</pre><h2>CALLBACK FUNCTION FACILITIES</h2><pre>
- Unless otherwise stated, callback functions, such as tab
- completion callbacks and event callbacks should not call any
- functions in this module. The following functions, however,
- are designed specifically to be used by callback functions.
-
- Calling the gl_replace_prompt() function from a callback
- tells gl_get_line() to display a different prompt when the
- callback returns. It has no effect if called when
- gl_get_line() is not being called.
-
- void gl_replace_prompt(GetLine *gl, const char *prompt);
-
-
-
-</pre><h2>INTERNATIONAL CHARACTER SETS</h2><pre>
- Since libtecla version 1.4.0, gl_get_line() has been 8-bit
- clean. This means that all 8-bit characters that are print-
- able in the user's current locale are now displayed verbatim
- and included in the returned input line. Assuming that the
- calling program correctly contains a call like the follow-
- ing,
-
- setlocale(LC_CTYPE, "");
-
- then the current locale is determined by the first of the
- environment variables LC_CTYPE, LC_ALL, and LANG, that is
- found to contain a valid locale name. If none of these vari-
- ables are defined, or the program neglects to call setlo-
- cale, then the default C locale is used, which is US 7-bit
- ASCII. On most unix-like platforms, you can get a list of
- valid locales by typing the command:
-
- locale -a
-
- at the shell prompt.
-
-
-</pre><h2> Meta keys and locales</h2><pre>
- Beware that in most locales other than the default C locale,
- meta characters become printable, and they are then no
- longer considered to match M-c style key bindings. This
- allows international characters to be entered with the com-
- pose key without unexpectedly triggering meta key bindings.
- You can still invoke meta bindings, since there are actually
- two ways to do this. For example the binding M-c can also be
- invoked by pressing the escape key momentarily, then press-
- ing the c key, and this will work regardless of locale.
- Moreover, many modern terminal emulators, such as gnome's
- gnome-terminal's and KDE's konsole terminals, already gen-
- erate escape pairs like this when you use the meta key,
- rather than a real meta character, and other emulators usu-
- ally have a way to request this behavior, so you can con-
- tinue to use the meta key on most systems.
-
- For example, although xterm terminal emulators generate real
- 8-bit meta characters by default when you use the meta key,
- they can be configured to output the equivalent escape pair
- by setting their EightBitInput X resource to False. You can
- either do this by placing a line like the following in your
- ~/.Xdefaults file,
-
- XTerm*EightBitInput: False
-
- or by starting an xterm with an -xrm '*EightBitInput: False'
- command-line argument. In recent versions of xterm you can
- toggle this feature on and off with the "Meta Sends Escape"
- option in the menu that is displayed when you press the left
- mouse button and the control key within an xterm window. In
- CDE, dtterms can be similarly coerced to generate escape
- pairs in place of meta characters, by setting the
- Dtterm*KshMode resource to True.
-
-
-</pre><h2> Entering international characters</h2><pre>
- If you don't have a keyboard that generates all of the
- international characters that you need, there is usually a
- compose key that will allow you to enter special characters,
- or a way to create one. For example, under X windows on
- unix-like systems, if your keyboard doesn't have a compose
- key, you can designate a redundant key to serve this purpose
- with the xmodmap command. For example, on many PC keyboards
- there is a microsoft-windows key, which is otherwise useless
- under Linux. On my PC the xev program reports that pressing
- this key generates keycode 115, so to turn this key into a
- compose key, I do the following:
-
- xmodmap -e 'keycode 115 = Multi_key'
-
- I can then enter an i with a umlaut over it by typing this
- key, followed by ", followed by i.
-
-
-</pre><h2>THREAD SAFETY</h2><pre>
- In a multi-threaded program, you should use the libtecla_r.a
- version of the library. This uses reentrant versions of sys-
- tem functions, where available. Unfortunately neither ter-
- minfo nor termcap were designed to be reentrant, so you
- can't safely use the functions of the getline module in mul-
- tiple threads (you can use the separate file-expansion and
- word-completion modules in multiple threads, see the
- corresponding man pages for details). However due to the use
- of POSIX reentrant functions for looking up home directories
- etc, it is safe to use this module from a single thread of a
- multi-threaded program, provided that your other threads
- don't use any termcap or terminfo functions.
-
-
-</pre><h2>FILES</h2><pre>
- libtecla.a - The tecla library
- libtecla.h - The tecla header file.
- ~/.teclarc - The personal tecla customization file.
-
-
-</pre><h2>SEE ALSO</h2><pre>
- <a href="libtecla.html">libtecla(3)</a>, <a href="ef_expand_file.html">ef_expand_file(3)</a>, <a href="cpl_complete_word.html">cpl_complete_word(3)</a>,
- <a href="pca_lookup_file.html">pca_lookup_file(3)</a>
-
-
-</pre><h2>AUTHOR</h2><pre>
- Martin Shepherd (mcs@astro.caltech.edu)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-</pre>
-</body>
diff --git a/libtecla-1.4.1/html/libtecla.html b/libtecla-1.4.1/html/libtecla.html
deleted file mode 100644
index 914c1e9..0000000
--- a/libtecla-1.4.1/html/libtecla.html
+++ /dev/null
@@ -1,163 +0,0 @@
-<head>
-<title>Manual Page</title>
-</head>
-<body>
-<pre>
-</pre><h2>NAME</h2><pre>
- libtecla - An interactive command-line input library.
-
-</pre><h2>SYNOPSIS</h2><pre>
- gcc ... -ltecla -lcurses
-
-
-</pre><h2>DESCRIPTION</h2><pre>
- The tecla library provides programs with interactive command
- line editing facilities, similar to those of the unix tcsh
- shell. In addition to simple command-line editing, it sup-
- ports recall of previously entered command lines, TAB com-
- pletion of file names or other tokens, and in-line wild-card
- expansion of filenames. The internal functions which perform
- file-name completion and wild-card expansion are also avail-
- able externally for optional use by the calling program.
-
- The various parts of the library are documented in the fol-
- lowing man pages:
-
- <a href="gl_get_line.html">gl_get_line(3)</a> - The interactive line-input module.
- <a href="cpl_complete_word.html">cpl_complete_word(3)</a> - The word completion module.
- <a href="ef_expand_file.html">ef_expand_file(3)</a> - The filename expansion module.
- <a href="pca_lookup_file.html">pca_lookup_file(3)</a> - A directory-list based filename
- lookup and completion module.
-
- In addition there is one optional application distributed
- with the library:
-
- <a href="enhance.html">enhance(3)</a> - Add command-line editing to third
- party applications.
-
-
-</pre><h2>THREAD SAFETY</h2><pre>
- If the library is compiled with -D_POSIX_C_SOURCE=199506L,
- reentrant versions of as many functions as possible are
- used. This includes using getpwuid_r() and getpwnam_r()
- instead of getpwuid() and getpwnam() when looking up the
- home directories of specific users in the password file (for
- ~user/ expansion), and readdir_r() instead of readdir() for
- reading directory entries when doing filename completion.
- The reentrant version of the library is usually called
- libtecla_r.a instead of libtecla.a, so if only the latter is
- available, it probably isn't the correct version to link
- with threaded programs.
-
- Reentrant functions for iterating through the password file
- aren't available, so when the library is compiled to be
- reentrant, TAB completion of incomplete usernames in ~user-
- name/ expressions is disabled. This doesn't disable expan-
- sion of complete ~username expressions, which can be done
- reentrantly, or expansion of the parts of filenames that
- follow them, so this doesn't remove much functionality.
-
- The terminfo functions setupterm(), tigetstr(), tigetnum()
- and tputs() also aren't reentrant, but very few programs
- will want to interact with multiple terminals, so this
- shouldn't prevent this library from being used in threaded
- programs.
-
-
-</pre><h2>LIBRARY VERSION NUMBER</h2><pre>
- The version number of the library can be queried using the
- following function.
-
- void libtecla_version(int *major, int *minor, int *micro);
-
-
- On return, this function records the three components of the
- libtecla version number in *major, *minor, *micro. The for-
- mal meaning of the three components is as follows.
-
-
- major - Incrementing this number implies that a change has
- been made to the library's public interface, which
- makes it binary incompatible with programs that
- were linked with previous shared versions of the
- tecla library.
-
- minor - This number is incremented by one whenever
- additional functionality, such as new functions or
- modules, are added to the library.
-
- micro - This is incremented whenever modifications to the
- library are made which make no changes to the
- public interface, but which fix bugs and/or improve
- the behind-the-scenes implementation.
-
-
-
-</pre><h2>TRIVIA</h2><pre>
- In Spanish, a "tecla" is the key of a keyboard. Since this
- library centers on keyboard input, and given that I wrote
- much of the library while working in Chile, this seemed like
- a suitable name.
-
-
-</pre><h2>FILES</h2><pre>
- libtecla.a - The tecla library.
- libtecla.h - The tecla header file.
- ~/.teclarc - The tecla personal customization file.
-
-
-
-</pre><h2>SEE ALSO</h2><pre>
- <a href="gl_get_line.html">gl_get_line(3)</a>, <a href="ef_expand_file.html">ef_expand_file(3)</a>, <a href="cpl_complete_word.html">cpl_complete_word(3)</a>,
- <a href="pca_lookup_file.html">pca_lookup_file(3)</a>, <a href="enhance.html">enhance(3)</a>
-
-
-</pre><h2>AUTHOR</h2><pre>
- Martin Shepherd (mcs@astro.caltech.edu)
-
-
-</pre><h2>ACKNOWLEDGMENTS</h2><pre>
- Markus Gyger - Lots of assistance, including help with
- shared libraries, configuration information,
- particularly for Solaris; modifications to
- support C++ compilers, improvements for ksh
- users, faster cursor motion, output
- buffering, and changes to make gl_get_line()
- 8-bit clean.
- Mike MacFaden - Suggestions, feedback and testing that led
- to many of the major new functions that were
- added in version 1.4.0.
- Tim Eliseo - Many vi-mode bindings and fixes.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-</pre>
-</body>
diff --git a/libtecla-1.4.1/html/pca_lookup_file.html b/libtecla-1.4.1/html/pca_lookup_file.html
deleted file mode 100644
index 40c9f2b..0000000
--- a/libtecla-1.4.1/html/pca_lookup_file.html
+++ /dev/null
@@ -1,371 +0,0 @@
-<head>
-<title>Manual Page</title>
-</head>
-<body>
-<pre>
-</pre><h2>NAME</h2><pre>
- pca_lookup_file, del_PathCache, del_PcaPathConf,
- new_PathCache, new_PcaPathConf, pca_last_error,
- pca_path_completions, pca_scan_path, pca_set_check_fn,
- ppc_file_start, ppc_literal_escapes - lookup a file in a
- list of directories
-
-</pre><h2>SYNOPSIS</h2><pre>
- #include &lt;libtecla.h&gt;
-
- PathCache *new_PathCache(void);
-
- PathCache *del_PathCache(PathCache *pc);
-
- int pca_scan_path(PathCache *pc, const char *path);
-
- void pca_set_check_fn(PathCache *pc, CplCheckFn *check_fn,
- void *data);
-
- char *pca_lookup_file(PathCache *pc, const char *name,
- int name_len, int literal);
-
- const char *pca_last_error(PathCache *pc);
-
- CPL_MATCH_FN(pca_path_completions);
-
-
-
-</pre><h2>DESCRIPTION</h2><pre>
- The PathCache object is part of the tecla library (see the
- <a href="libtecla.html">libtecla(3)</a> man page).
-
- PathCache objects allow an application to search for files
- in any colon separated list of directories, such as the unix
- execution PATH environment variable. Files in absolute
- directories are cached in a PathCache object, whereas rela-
- tive directories are scanned as needed. Using a PathCache
- object, you can look up the full pathname of a simple
- filename, or you can obtain a list of the possible comple-
- tions of a given filename prefix. By default all files in
- the list of directories are targets for lookup and comple-
- tion, but a versatile mechanism is provided for only select-
- ing specific types of files. The obvious application of this
- facility is to provide Tab-completion and lookup of execut-
- able commands in the unix PATH, so an optional callback
- which rejects all but executable files, is provided.
-
-
-</pre><h2>AN EXAMPLE</h2><pre>
- Under UNIX, the following example program looks up and
- displays the full pathnames of each of the command names on
- the command line.
- #include &lt;stdio.h&gt;
- #include &lt;stdlib.h&gt;
- #include &lt;libtecla.h&gt;
-
- int main(int argc, char *argv[])
- {
- int i;
- /*
- * Create a cache for executable files.
- */
- PathCache *pc = new_PathCache();
- if(!pc)
- exit(1);
- /*
- * Scan the user's PATH for executables.
- */
- if(pca_scan_path(pc, getenv("PATH"))) {
- fprintf(stderr, "%s\n", pca_last_error(pc));
- exit(1);
- }
- /*
- * Arrange to only report executable files.
- */
- pca_set_check_fn(pc, cpl_check_exe, NULL);
- /*
- * Lookup and display the full pathname of each of the
- * commands listed on the command line.
- */
- for(i=1; i&lt;argc; i++) {
- char *cmd = pca_lookup_file(pc, argv[i], -1, 0);
- printf("The full pathname of '%s' is %s\n", argv[i],
- cmd ? cmd : "unknown");
- }
- pc = del_PathCache(pc); /* Clean up */
- return 0;
- }
-
- The following is an example of what this does on my laptop
- under linux:
-
- $ ./example less more blob
- The full pathname of 'less' is /usr/bin/less
- The full pathname of 'more' is /bin/more
- The full pathname of 'blob' is unknown
- $
-
-
-</pre><h2>FUNCTION DESCRIPTIONS</h2><pre>
- In order to use the facilities of this module, you must
- first allocate a PathCache object by calling the
- new_PathCache() constructor function.
-
- PathCache *new_PathCache(void)
-
- This function creates the resources needed to cache and
- lookup files in a list of directories. It returns NULL on
- error.
-
-
-</pre><h2>POPULATING THE CACHE</h2><pre>
- Once you have created a cache, it needs to be populated with
- files. To do this, call the pca_scan_path() function.
-
- int pca_scan_path(PathCache *pc, const char *path);
-
- Whenever this function is called, it discards the current
- contents of the cache, then scans the list of directories
- specified in its path argument for files. The path argument
- must be a string containing a colon-separated list of direc-
- tories, such as "/usr/bin:/home/mcs/bin:.". This can include
- directories specified by absolute pathnames such as
- "/usr/bin", as well as sub-directories specified by relative
- pathnames such as "." or "bin". Files in the absolute direc-
- tories are immediately cached in the specified PathCache
- object, whereas sub-directories, whose identities obviously
- change whenever the current working directory is changed,
- are marked to be scanned on the fly whenever a file is
- looked up.
-
- On success this function return 0. On error it returns 1,
- and a description of the error can be obtained by calling
- pca_last_error(pc).
-
-
-</pre><h2>LOOKING UP FILES</h2><pre>
- Once the cache has been populated with files, you can look
- up the full pathname of a file, simply by specifying its
- filename to pca_lookup_file().
-
- char *pca_lookup_file(PathCache *pc, const char *name,
- int name_len, int literal);
-
- To make it possible to pass this function a filename which
- is actually part of a longer string, the name_len argument
- can be used to specify the length of the filename at the
- start of the name[] argument. If you pass -1 for this
- length, the length of the string will be determined with
- strlen(). If the name[] string might contain backslashes
- that escape the special meanings of spaces and tabs within
- the filename, give the literal argument, the value 0. Other-
- wise, if backslashes should be treated as normal characters,
- pass 1 for the value of the literal argument.
-
-
-</pre><h2>FILENAME COMPLETION</h2><pre>
- Looking up the potential completions of a filename-prefix in
- the filename cache, is achieved by passing the provided
- pca_path_completions() callback function to the
- cpl_complete_word() function (see the <a href="cpl_complete_word.html">cpl_complete_word(3)</a>
- man page).
-
- CPL_MATCH_FN(pca_path_completions);
-
- This callback requires that its data argument be a pointer
- to a PcaPathConf object. Configuration objects of this type
- are allocated by calling new_PcaPathConf().
-
- PcaPathConf *new_PcaPathConf(PathCache *pc);
-
- This function returns an object initialized with default
- configuration parameters, which determine how the
- cpl_path_completions() callback function behaves. The func-
- tions which allow you to individually change these parame-
- ters are discussed below.
-
- By default, the pca_path_completions() callback function
- searches backwards for the start of the filename being com-
- pleted, looking for the first un-escaped space or the start
- of the input line. If you wish to specify a different loca-
- tion, call ppc_file_start() with the index at which the
- filename starts in the input line. Passing start_index=-1
- re-enables the default behavior.
-
- void ppc_file_start(PcaPathConf *ppc, int start_index);
-
- By default, when pca_path_completions() looks at a filename
- in the input line, each lone backslash in the input line is
- interpreted as being a special character which removes any
- special significance of the character which follows it, such
- as a space which should be taken as part of the filename
- rather than delimiting the start of the filename. These
- backslashes are thus ignored while looking for completions,
- and subsequently added before spaces, tabs and literal
- backslashes in the list of completions. To have unescaped
- backslashes treated as normal characters, call
- ppc_literal_escapes() with a non-zero value in its literal
- argument.
-
- void ppc_literal_escapes(PcaPathConf *ppc, int literal);
-
- When you have finished with a PcaPathConf variable, you can
- pass it to the del_PcaPathConf() destructor function to
- reclaim its memory.
-
- PcaPathConf *del_PcaPathConf(PcaPathConf *ppc);
-
-</pre><h2>BEING SELECTIVE</h2><pre>
- If you are only interested in certain types or files, such
- as, for example, executable files, or files whose names end
- in a particular suffix, you can arrange for the file comple-
- tion and lookup functions to be selective in the filenames
- that they return. This is done by registering a callback
- function with your PathCache object. Thereafter, whenever a
- filename is found which either matches a filename being
- looked up, or matches a prefix which is being completed,
- your callback function will be called with the full pathname
- of the file, plus any application-specific data that you
- provide, and if the callback returns 1 the filename will be
- reported as a match, and if it returns 0, it will be
- ignored. Suitable callback functions and their prototypes
- should be declared with the following macro. The CplCheckFn
- typedef is also provided in case you wish to declare
- pointers to such functions.
-
- #define CPL_CHECK_FN(fn) int (fn)(void *data, \
- const char *pathname)
- typedef CPL_CHECK_FN(CplCheckFn);
-
- Registering one of these functions involves calling the
- pca_set_check_fn() function. In addition to the callback
- function, passed via the check_fn argument, you can pass a
- pointer to anything via the data argument. This pointer will
- be passed on to your callback function, via its own data
- argument, whenever it is called, so this provides a way to
- pass appplication specific data to your callback.
-
- void pca_set_check_fn(PathCache *pc, CplCheckFn *check_fn,
- void *data);
-
- Note that these callbacks are passed the full pathname of
- each matching file, so the decision about whether a file is
- of interest can be based on any property of the file, not
- just its filename. As an example, the provided
- cpl_check_exe() callback function looks at the executable
- permissions of the file and the permissions of its parent
- directories, and only returns 1 if the user has execute per-
- mission to the file. This callback function can thus be used
- to lookup or complete command names found in the directories
- listed in the user's PATH environment variable. The example
- program given earlier in this man page provides a demonstra-
- tion of this.
-
- Beware that if somebody tries to complete an empty string,
- your callback will get called once for every file in the
- cache, which could number in the thousands. If your callback
- does anything time consuming, this could result in an unac-
- ceptable delay for the user, so callbacks should be kept
- short.
- To improve performance, whenever one of these callbacks is
- called, the choice that it makes is cached, and the next
- time the corresponding file is looked up, instead of calling
- the callback again, the cached record of whether it was
- accepted or rejected is used. Thus if somebody tries to com-
- plete an empty string, and hits tab a second time when noth-
- ing appears to happen, there will only be one long delay,
- since the second pass will operate entirely from the cached
- dispositions of the files. These cached dipositions are dis-
- carded whenever pca_scan_path() is called, and whenever
- pca_set_check_fn() is called with changed callback function
- or data arguments.
-
-
-</pre><h2>ERROR HANDLING</h2><pre>
- If pca_scan_path() reports that an error occurred by return-
- ing 1, you can obtain a terse description of the error by
- calling pca_last_error(pc). This returns an internal string
- containing an error message.
-
- const char *pca_last_error(PathCache *pc);
-
-
-
-</pre><h2>CLEANING UP</h2><pre>
- Once you have finished using a PathCache object, you can
- reclaim its resources by passing it to the del_PathCache()
- destructor function. This takes a pointer to one of these
- objects, and always returns NULL.
-
- PathCache *del_PathCache(PathCache *pc);
-
-
-</pre><h2>THREAD SAFETY</h2><pre>
- In multi-threaded programs, you should use the libtecla_r.a
- version of the library. This uses POSIX reentrant functions
- where available (hence the _r suffix), and disables features
- that rely on non-reentrant system functions. In the case of
- this module, the only disabled feature is username comple-
- tion in ~username/ expressions, in cpl_path_completions().
-
- Using the libtecla_r.a version of the library, it is safe to
- use the facilities of this module in multiple threads, pro-
- vided that each thread uses a separately allocated PathCache
- object. In other words, if two threads want to do path
- searching, they should each call new_PathCache() to allocate
- their own caches.
-
-
-</pre><h2>FILES</h2><pre>
- libtecla.a - The tecla library
- libtecla.h - The tecla header file.
-</pre><h2>SEE ALSO</h2><pre>
- <a href="libtecla.html">libtecla(3)</a>, <a href="gl_get_line.html">gl_get_line(3)</a>, <a href="ef_expand_file.html">ef_expand_file(3)</a>,
- <a href="cpl_complete_word.html">cpl_complete_word(3)</a>
-
-
-</pre><h2>AUTHOR</h2><pre>
- Martin Shepherd (mcs@astro.caltech.edu)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-</pre>
-</body>
diff --git a/libtecla-1.4.1/man3/cfc_file_start.3 b/libtecla-1.4.1/man3/cfc_file_start.3
deleted file mode 100644
index 36c83a3..0000000
--- a/libtecla-1.4.1/man3/cfc_file_start.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/cpl_complete_word.3
diff --git a/libtecla-1.4.1/man3/cfc_literal_escapes.3 b/libtecla-1.4.1/man3/cfc_literal_escapes.3
deleted file mode 100644
index 36c83a3..0000000
--- a/libtecla-1.4.1/man3/cfc_literal_escapes.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/cpl_complete_word.3
diff --git a/libtecla-1.4.1/man3/cfc_set_check_fn.3 b/libtecla-1.4.1/man3/cfc_set_check_fn.3
deleted file mode 100644
index 36c83a3..0000000
--- a/libtecla-1.4.1/man3/cfc_set_check_fn.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/cpl_complete_word.3
diff --git a/libtecla-1.4.1/man3/cpl_add_completion.3 b/libtecla-1.4.1/man3/cpl_add_completion.3
deleted file mode 100644
index 36c83a3..0000000
--- a/libtecla-1.4.1/man3/cpl_add_completion.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/cpl_complete_word.3
diff --git a/libtecla-1.4.1/man3/cpl_file_completions.3 b/libtecla-1.4.1/man3/cpl_file_completions.3
deleted file mode 100644
index 36c83a3..0000000
--- a/libtecla-1.4.1/man3/cpl_file_completions.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/cpl_complete_word.3
diff --git a/libtecla-1.4.1/man3/cpl_last_error.3 b/libtecla-1.4.1/man3/cpl_last_error.3
deleted file mode 100644
index 36c83a3..0000000
--- a/libtecla-1.4.1/man3/cpl_last_error.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/cpl_complete_word.3
diff --git a/libtecla-1.4.1/man3/cpl_list_completions.3 b/libtecla-1.4.1/man3/cpl_list_completions.3
deleted file mode 100644
index 36c83a3..0000000
--- a/libtecla-1.4.1/man3/cpl_list_completions.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/cpl_complete_word.3
diff --git a/libtecla-1.4.1/man3/cpl_record_error.3 b/libtecla-1.4.1/man3/cpl_record_error.3
deleted file mode 100644
index 36c83a3..0000000
--- a/libtecla-1.4.1/man3/cpl_record_error.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/cpl_complete_word.3
diff --git a/libtecla-1.4.1/man3/del_CplFileConf.3 b/libtecla-1.4.1/man3/del_CplFileConf.3
deleted file mode 100644
index 36c83a3..0000000
--- a/libtecla-1.4.1/man3/del_CplFileConf.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/cpl_complete_word.3
diff --git a/libtecla-1.4.1/man3/del_ExpandFile.3 b/libtecla-1.4.1/man3/del_ExpandFile.3
deleted file mode 100644
index f4299df..0000000
--- a/libtecla-1.4.1/man3/del_ExpandFile.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/ef_expand_file.3
diff --git a/libtecla-1.4.1/man3/del_GetLine.3 b/libtecla-1.4.1/man3/del_GetLine.3
deleted file mode 100644
index 6bd3d1f..0000000
--- a/libtecla-1.4.1/man3/del_GetLine.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/gl_get_line.3
diff --git a/libtecla-1.4.1/man3/del_PathCache.3 b/libtecla-1.4.1/man3/del_PathCache.3
deleted file mode 100644
index e5a136e..0000000
--- a/libtecla-1.4.1/man3/del_PathCache.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/pca_lookup_file.3
diff --git a/libtecla-1.4.1/man3/del_PcaPathConf.3 b/libtecla-1.4.1/man3/del_PcaPathConf.3
deleted file mode 100644
index e5a136e..0000000
--- a/libtecla-1.4.1/man3/del_PcaPathConf.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/pca_lookup_file.3
diff --git a/libtecla-1.4.1/man3/del_WordCompletion.3 b/libtecla-1.4.1/man3/del_WordCompletion.3
deleted file mode 100644
index 36c83a3..0000000
--- a/libtecla-1.4.1/man3/del_WordCompletion.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/cpl_complete_word.3
diff --git a/libtecla-1.4.1/man3/ef_last_error.3 b/libtecla-1.4.1/man3/ef_last_error.3
deleted file mode 100644
index f4299df..0000000
--- a/libtecla-1.4.1/man3/ef_last_error.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/ef_expand_file.3
diff --git a/libtecla-1.4.1/man3/ef_list_expansions.3 b/libtecla-1.4.1/man3/ef_list_expansions.3
deleted file mode 100644
index f4299df..0000000
--- a/libtecla-1.4.1/man3/ef_list_expansions.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/ef_expand_file.3
diff --git a/libtecla-1.4.1/man3/gl_change_terminal.3 b/libtecla-1.4.1/man3/gl_change_terminal.3
deleted file mode 100644
index 6bd3d1f..0000000
--- a/libtecla-1.4.1/man3/gl_change_terminal.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/gl_get_line.3
diff --git a/libtecla-1.4.1/man3/gl_clear_history.3 b/libtecla-1.4.1/man3/gl_clear_history.3
deleted file mode 100644
index 6bd3d1f..0000000
--- a/libtecla-1.4.1/man3/gl_clear_history.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/gl_get_line.3
diff --git a/libtecla-1.4.1/man3/gl_configure_getline.3 b/libtecla-1.4.1/man3/gl_configure_getline.3
deleted file mode 100644
index 6bd3d1f..0000000
--- a/libtecla-1.4.1/man3/gl_configure_getline.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/gl_get_line.3
diff --git a/libtecla-1.4.1/man3/gl_customize_completion.3 b/libtecla-1.4.1/man3/gl_customize_completion.3
deleted file mode 100644
index 6bd3d1f..0000000
--- a/libtecla-1.4.1/man3/gl_customize_completion.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/gl_get_line.3
diff --git a/libtecla-1.4.1/man3/gl_echo_mode.3 b/libtecla-1.4.1/man3/gl_echo_mode.3
deleted file mode 100644
index 6bd3d1f..0000000
--- a/libtecla-1.4.1/man3/gl_echo_mode.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/gl_get_line.3
diff --git a/libtecla-1.4.1/man3/gl_get_line.3 b/libtecla-1.4.1/man3/gl_get_line.3
deleted file mode 100644
index 51fc9d8..0000000
--- a/libtecla-1.4.1/man3/gl_get_line.3
+++ /dev/null
@@ -1,2329 +0,0 @@
-.\" Copyright (C) 2000, 2001 by Martin C. Shepherd
-.\"
-.\" All rights reserved.
-.\"
-.\" Permission is hereby granted, free of charge, to any person obtaining a
-.\" copy of this software and associated documentation files (the
-.\" "Software"), to deal in the Software without restriction, including
-.\" without limitation the rights to use, copy, modify, merge, publish,
-.\" distribute, and/or sell copies of the Software, and to permit persons
-.\" to whom the Software is furnished to do so, provided that the above
-.\" copyright notice(s) and this permission notice appear in all copies of
-.\" the Software and that both the above copyright notice(s) and this
-.\" permission notice appear in supporting documentation.
-.\"
-.\" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-.\" OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
-.\" OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
-.\" HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
-.\" INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
-.\" FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
-.\" NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
-.\" WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-.\"
-.\" Except as contained in this notice, the name of a copyright holder
-.\" shall not be used in advertising or otherwise to promote the sale, use
-.\" or other dealings in this Software without prior written authorization
-.\" of the copyright holder.
-.TH gl_get_line 3
-.SH NAME
-gl_get_line, new_GetLine, del_GetLine, gl_customize_completion, gl_change_terminal, gl_configure_getline, gl_load_history, gl_save_history, gl_group_history, gl_show_history, gl_watch_fd, gl_terminal_size, gl_resize_history, gl_limit_history, gl_clear_history, gl_toggle_history, gl_lookup_history, gl_state_of_history, gl_range_of_history, gl_size_of_history, gl_echo_mode, gl_replace_prompt, gl_prompt_style, gl_ignore_signal, gl_trap_signal, gl_last_signal \- allow the user to compose an input line
-.SH SYNOPSIS
-.nf
-#include <stdio.h>
-#include <libtecla.h>
-
-GetLine *new_GetLine(size_t linelen, size_t histlen);
-
-GetLine *del_GetLine(GetLine *gl);
-
-char *gl_get_line(GetLine *gl, const char *prompt,
- const char *start_line, int start_pos);
-
-int gl_customize_completion(GetLine *gl, void *data,
- CplMatchFn *match_fn);
-
-int gl_change_terminal(GetLine *gl, FILE *input_fp,
- FILE *output_fp, const char *term);
-
-int gl_configure_getline(GetLine *gl,
- const char *app_string,
- const char *app_file,
- const char *user_file);
-
-int gl_save_history(GetLine *gl, const char *filename,
- const char *comment, int max_lines);
-
-int gl_load_history(GetLine *gl, const char *filename,
- const char *comment);
-
-int gl_watch_fd(GetLine *gl, int fd, GlFdEvent event,
- GlFdEventFn *callback, void *data);
-
-int gl_group_history(GetLine *gl, unsigned stream);
-
-int gl_show_history(GetLine *gl, FILE *fp,
- const char *fmt, int all_groups,
- int max_lines);
-
-int gl_resize_history(GetLine *gl, size_t bufsize);
-
-void gl_limit_history(GetLine *gl, int max_lines);
-
-void gl_clear_history(GetLine *gl, int all_groups);
-
-void gl_toggle_history(GetLine *gl, int enable);
-
-GlTerminalSize gl_terminal_size(GetLine *gl,
- int def_ncolumn,
- int def_nline);
-
-int gl_lookup_history(GetLine *gl, unsigned long id,
- GlHistoryLine *hline);
-
-void gl_state_of_history(GetLine *gl,
- GlHistoryState *state);
-
-void gl_range_of_history(GetLine *gl,
- GlHistoryRange *range);
-
-void gl_size_of_history(GetLine *gl, GlHistorySize *size);
-
-void gl_echo_mode(GetLine *gl, int enable);
-
-void gl_replace_prompt(GetLine *gl, const char *prompt);
-
-void gl_prompt_style(GetLine *gl, GlPromptStyle style);
-
-int gl_ignore_signal(GetLine *gl, int signo);
-
-int gl_trap_signal(GetLine *gl, int signo, unsigned flags,
- GlAfterSignal after, int errno_value);
-
-int gl_last_signal(const GetLine *gl);
-
-.fi
-
-.SH DESCRIPTION
-
-The \f3gl_get_line()\f1 function is part of the tecla library (see
-the libtecla(3) man page). If the user is typing at a terminal, it
-prompts them for an line of input, then provides interactive editing
-facilities, similar to those of the unix \f3tcsh\f1 shell. In addition
-to simple command-line editing, it supports recall of previously
-entered command lines, TAB completion of file names, and in-line
-wild-card expansion of filenames.
-.sp
-.SH AN EXAMPLE
-
-The following shows a complete example of how to use the
-\f3gl_get_line()\f1 function to get input from the user:
-
-.nf
- #include <stdio.h>
- #include <locale.h>
- #include <libtecla.h>
-
- int main(int argc, char *argv[])
- {
- char *line; /* The line that the user typed */
- GetLine *gl; /* The gl_get_line() resource object */
-
- setlocale(LC_CTYPE, ""); /* Adopt the user's choice */
- /* of character set. */
-
- gl = new_GetLine(1024, 2048);
- if(!gl)
- return 1;
-
- while((line=gl_get_line(gl, "$ ", NULL, -1)) != NULL &&
- strcmp(line, "exit\\n") != 0)
- printf("You typed: %s\\n", line);
-
- gl = del_GetLine(gl);
- return 0;
- }
-.fi
-.sp
-In the example, first the resources needed by the \f3gl_get_line()\f1 function
-are created by calling \f3new_GetLine()\f1. This allocates the memory used in
-subsequent calls to the \f3gl_get_line()\f1 function, including the history
-buffer for recording previously entered lines. Then one or more lines are read
-from the user, until either an error occurs, or the user types \f3exit\f1. Then
-finally the resources that were allocated by \f3new_GetLine()\f1, are returned
-to the system by calling \f3del_GetLine()\f1. Note the use of the \f3NULL\f1
-return value of \f3del_GetLine()\f1 to make \f3gl\f1 \f3NULL\f1. This is a
-safety precaution. If the program subsequently attempts to pass \f3gl\f1 to
-\f3gl_get_line()\f1, said function will complain, and return an error, instead of
-attempting to use the deleted resource object.
-
-.sp
-.SH THE FUNCTIONS USED IN THE EXAMPLE
-The descriptions of the functions used in the example are as follows:
-.sp
-.nf
- GetLine *new_GetLine(size_t linelen, size_t histlen)
-.fi
-.sp
-This function creates the resources used by the \f3gl_get_line()\f1
-function and returns an opaque pointer to the object that contains
-them. The maximum length of an input line is specified via the
-\f3linelen\f1 argument, and the number of bytes to allocate for
-storing history lines is set by the \f3histlen\f1 argument. History
-lines are stored back-to-back in a single buffer of this size. Note
-that this means that the number of history lines that can be stored at
-any given time, depends on the lengths of the individual lines. If
-you want to place an upper limit on the number of lines that can be
-stored, see the \f3gl_limit_history()\f1 function described later. If
-you don't want history at all, specify \f3histlen\f1 as zero, and no
-history buffer will be allocated.
-.sp
-On error, a message is printed to \f3stderr\f1 and \f3NULL\f1 is returned.
-.sp
-.nf
- GetLine *del_GetLine(GetLine *gl)
-.fi
-.sp
-This function deletes the resources that were returned by a previous
-call to \f3new_GetLine()\f1. It always returns \f3NULL\f1 (ie a
-deleted object). It does nothing if the \f3gl\f1 argument is
-\f3NULL\f1.
-.sp
-.nf
- char *gl_get_line(GetLine *gl, const char *prompt,
- const char *start_line, int start_pos);
-.fi
-.sp
-The \f3gl_get_line()\f1 function can be called any number of
-times to read input from the user. The \f3gl\f1 argument
-must have been previously returned by a call to
-\f3new_GetLine()\f1. The \f3prompt\f1 argument should be a
-normal \f3NUL\f1 terminated string, specifying the prompt to
-present the user with. By default prompts are displayed
-literally, but if enabled with the \f3gl_prompt_style()\f1
-function (see later), prompts can contain directives to do
-underlining, switch to and from bold fonts, or turn
-highlighting on and off.
-
-If you want to specify the initial contents of the line, for
-the user to edit, pass the desired string via the
-\f3start_line\f1 argument. You can then specify which
-character of this line the cursor is initially positioned
-over, using the \f3start_pos\f1 argument. This should be -1
-if you want the cursor to follow the last character of the
-start line. If you don't want to preload the line in this
-manner, send \f3start_line\f1 as \f3NULL\f1, and set
-\f3start_pos\f1 to -1.
-
-The \f3gl_get_line()\f1 function returns a pointer to the line entered
-by the user, or \f3NULL\f1 on error or at the end of the input. The
-returned pointer is part of the specified \f3gl\f1 resource object,
-and thus should not be free'd by the caller, or assumed to be
-unchanging from one call to the next. When reading from a user at a
-terminal, there will always be a newline character at the end of the
-returned line. When standard input is being taken from a pipe or a
-file, there will similarly be a newline unless the input line was too
-long to store in the internal buffer. In the latter case you should
-call \f3gl_get_line()\f1 again to read the rest of the line. Note that
-this behavior makes \f3gl_get_line()\f1 similar to \f3fgets()\f1. In
-fact when \f3stdin\f1 isn't connected to a terminal,\f3gl_get_line()\f1
-just calls \f3fgets()\f1.
-
-.SH OPTIONAL PROMPT FORMATTING
-
-Whereas by default the prompt string that you specify is
-displayed literally, without any special interpretation of
-the characters within it, the \f3gl_prompt_style()\f1
-function can be used to enable optional formatting
-directives within the prompt.
-.sp
-.nf
- void gl_prompt_style(GetLine *gl, GlPromptStyle style);
-.fi
-.sp
-The \f3style\f1 argument, which specifies the formatting
-style, can take any of the following values:
-.sp
-.nf
- GL_FORMAT_PROMPT - In this style, the formatting
- directives described below, when
- included in prompt strings, are
- interpreted as follows:
-
- %B - Display subsequent
- characters with a bold
- font.
- %b - Stop displaying characters
- with the bold font.
- %F - Make subsequent characters
- flash.
- %f - Turn off flashing
- characters.
- %U - Underline subsequent
- characters.
- %u - Stop underlining
- characters.
- %P - Switch to a pale (half
- brightness) font.
- %p - Stop using the pale font.
- %S - Highlight subsequent
- characters (also known as
- standout mode).
- %s - Stop highlighting
- characters.
- %V - Turn on reverse video.
- %v - Turn off reverse video.
- %% - Display a single %
- character.
-
- For example, in this mode, a prompt
- string like \f3"%UOK%u$ "\f1 would
- display the prompt \f3"OK$ "\f1,
- but with the \f3OK\f1 part
- underlined.
-
- Note that although a pair of
- characters that starts with a %
- character, but doesn't match any of
- the above directives is displayed
- literally, if a new directive is
- subsequently introduced which does
- match, the displayed prompt will
- change, so it is better to always
- use %% to display a literal %.
-
- Also note that not all terminals
- support all of these text
- attributes, and that some substitute
- a different attribute for missing
- ones.
-
- GL_LITERAL_PROMPT - In this style, the prompt string is
- printed literally. This is the
- default style.
-.fi
-.sp
-
-.SH THE AVAILABLE KEY BINDING FUNCTIONS
-
-The \f3gl_get_line()\f1 function provides a number of functions which
-can be bound to key sequences. The names of these functions, and what
-they do, are given below.
-
-.nf
- user-interrupt - Send a SIGINT signal to the
- parent process.
- abort - Send a SIGABRT signal to the
- parent process.
- suspend - Suspend the parent process.
- stop-output - Pause terminal output.
- start-output - Resume paused terminal output.
- literal-next - Arrange for the next character
- to be treated as a normal
- character. This allows control
- characters to be entered.
- cursor-right - Move the cursor one character
- right.
- cursor-left - Move the cursor one character
- left.
- insert-mode - Toggle between insert mode and
- overwrite mode.
- beginning-of-line - Move the cursor to the
- beginning of the line.
- end-of-line - Move the cursor to the end of
- the line.
- delete-line - Delete the contents of the
- current line.
- kill-line - Delete everything that follows
- the cursor.
- backward-kill-line - Delete all characters between
- the cursor and the start of the
- line.
- forward-word - Move to the end of the word
- which follows the cursor.
- forward-to-word - Move the cursor to the start of
- the word that follows the
- cursor.
- backward-word - Move to the start of the word
- which precedes the cursor.
- goto-column - Move the cursor to the
- 1-relative column in the line
- specified by any preceding
- digit-argument sequences (see
- ENTERING REPEAT COUNTS below).
- find-parenthesis - If the cursor is currently
- over a parenthesis character,
- move it to the matching
- parenthesis character. If not
- over a parenthesis character
- move right to the next close
- parenthesis.
- forward-delete-char - Delete the character under the
- cursor.
- backward-delete-char - Delete the character which
- precedes the cursor.
- list-or-eof - This is intended for binding
- to ^D. When invoked when the
- cursor is within the line it
- displays all possible
- completions then redisplays
- the line unchanged. When
- invoked on an empty line, it
- signals end-of-input (EOF) to
- the caller of gl_get_line().
- del-char-or-list-or-eof - This is intended for binding
- to ^D. When invoked when the
- cursor is within the line it
- invokes forward-delete-char.
- When invoked at the end of the
- line it displays all possible
- completions then redisplays
- the line unchanged. When
- invoked on an empty line, it
- signals end-of-input (EOF) to
- the caller of gl_get_line().
- forward-delete-word - Delete the word which follows
- the cursor.
- backward-delete-word - Delete the word which precedes
- the cursor.
- upcase-word - Convert all of the characters
- of the word which follows the
- cursor, to upper case.
- downcase-word - Convert all of the characters
- of the word which follows the
- cursor, to lower case.
- capitalize-word - Capitalize the word which
- follows the cursor.
- change-case - If the next character is upper
- case, toggle it to lower case
- and vice versa.
- redisplay - Redisplay the line.
- clear-screen - Clear the terminal, then
- redisplay the current line.
- transpose-chars - Swap the character under the
- cursor with the character just
- before the cursor.
- set-mark - Set a mark at the position of
- the cursor.
- exchange-point-and-mark - Move the cursor to the last
- mark that was set, and move
- the mark to where the cursor
- used to be.
- kill-region - Delete the characters that lie
- between the last mark that was
- set, and the cursor.
- copy-region-as-kill - Copy the text between the mark
- and the cursor to the cut
- buffer, without deleting the
- original text.
- yank - Insert the text that was last
- deleted, just before the
- current position of the cursor.
- append-yank - Paste the current contents of
- the cut buffer, after the
- cursor.
- up-history - Recall the next oldest line
- that was entered. Note that
- in vi mode you are left in
- command mode.
- down-history - Recall the next most recent
- line that was entered. If no
- history recall session is
- currently active, the next
- line from a previous recall
- session is recalled. Note that
- in vi mode you are left in
- command mode.
- history-search-backward - Recall the next oldest line
- who's prefix matches the string
- which currently precedes the
- cursor (in vi command-mode the
- character under the cursor is
- also included in the search
- string). Note that in vi mode
- you are left in command mode.
- history-search-forward - Recall the next newest line
- who's prefix matches the string
- which currently precedes the
- cursor (in vi command-mode the
- character under the cursor is
- also included in the search
- string). Note that in vi mode
- you are left in command mode.
- history-re-search-backward -Recall the next oldest line
- who's prefix matches that
- established by the last
- invocation of either
- history-search-forward or
- history-search-backward.
- history-re-search-forward - Recall the next newest line
- who's prefix matches that
- established by the last
- invocation of either
- history-search-forward or
- history-search-backward.
- complete-word - Attempt to complete the
- incomplete word which
- precedes the cursor. Unless
- the host program has customized
- word completion, filename
- completion is attempted. In vi
- commmand mode the character
- under the cursor is also
- included in the word being
- completed, and you are left in
- vi insert mode.
- expand-filename - Within the command line, expand
- wild cards, tilde expressions
- and dollar expressions in the
- filename which immediately
- precedes the cursor. In vi
- commmand mode the character
- under the cursor is also
- included in the filename being
- expanded, and you are left in
- vi insert mode.
- list-glob - List any filenames which match
- the wild-card, tilde and dollar
- expressions in the filename
- which immediately precedes the
- cursor, then redraw the input
- line unchanged.
- list-history - Display the contents of the
- history list for the current
- history group. If a repeat
- count of > 1 is specified,
- only that many of the most
- recent lines are displayed.
- See the "ENTERING REPEAT
- COUNTS" section.
- read-from-file - Temporarily switch to reading
- input from the file who's
- name precedes the cursor.
- read-init-files - Re-read teclarc configuration
- files.
- beginning-of-history - Move to the oldest line in the
- history list. Note that in vi
- mode you are left in command
- mode.
- end-of-history - Move to the newest line in the
- history list (ie. the current
- line). Note that in vi mode
- this leaves you in command
- mode.
- digit-argument - Enter a repeat count for the
- next key-binding function.
- For details, see the ENTERING
- REPEAT COUNTS section.
- newline - Terminate and return the
- current contents of the
- line, after appending a
- newline character. The newline
- character is normally '\\n',
- but will be the first
- character of the key-sequence
- that invoked the newline
- action, if this happens to be
- a printable character. If the
- action was invoked by the
- '\\n' newline character or the
- '\\r' carriage return
- character, the line is
- appended to the history
- buffer.
- repeat-history - Return the line that is being
- edited, then arrange for the
- next most recent entry in the
- history buffer to be recalled
- when \f3gl_get_line()\f1 is
- next called. Repeatedly
- invoking this action causes
- successive historical input
- lines to be re-executed. Note
- that this action is equivalent
- to the 'Operate' action in
- ksh.
- ring-bell - Ring the terminal bell, unless
- the bell has been silenced via
- the \f3nobeep\f1 configuration
- option (see the THE TECLA
- CONFIGURATION FILE section).
- forward-copy-char - Copy the next character into
- the cut buffer (NB. use repeat
- counts to copy more than one).
- backward-copy-char - Copy the previous character
- into the cut buffer.
- forward-copy-word - Copy the next word into the cut
- buffer.
- backward-copy-word - Copy the previous word into the
- cut buffer.
- forward-find-char - Move the cursor to the next
- occurrence of the next
- character that you type.
- backward-find-char - Move the cursor to the last
- occurrence of the next
- character that you type.
- forward-to-char - Move the cursor to the
- character just before the next
- occurrence of the next
- character that the user types.
- backward-to-char - Move the cursor to the
- character just after the last
- occurrence before the cursor
- of the next character that the
- user types.
- repeat-find-char - Repeat the last
- backward-find-char,
- forward-find-char,
- backward-to-char or
- forward-to-char.
- invert-refind-char - Repeat the last
- backward-find-char,
- forward-find-char,
- backward-to-char, or
- forward-to-char in the
- opposite direction.
- delete-to-column - Delete the characters from the
- cursor up to the column that
- is specified by the repeat
- count.
- delete-to-parenthesis - Delete the characters from the
- cursor up to and including
- the matching parenthesis, or
- next close parenthesis.
- forward-delete-find - Delete the characters from the
- cursor up to and including the
- following occurence of the
- next character typed.
- backward-delete-find - Delete the characters from the
- cursor up to and including the
- preceding occurence of the
- next character typed.
- forward-delete-to - Delete the characters from the
- cursor up to, but not
- including, the following
- occurence of the next
- character typed.
- backward-delete-to - Delete the characters from the
- cursor up to, but not
- including, the preceding
- occurence of the next
- character typed.
- delete-refind - Repeat the last *-delete-find
- or *-delete-to action.
- delete-invert-refind - Repeat the last *-delete-find
- or *-delete-to action, in the
- opposite direction.
- copy-to-column - Copy the characters from the
- cursor up to the column that
- is specified by the repeat
- count, into the cut buffer.
- copy-to-parenthesis - Copy the characters from the
- cursor up to and including
- the matching parenthesis, or
- next close parenthesis, into
- the cut buffer.
- forward-copy-find - Copy the characters from the
- cursor up to and including the
- following occurence of the
- next character typed, into the
- cut buffer.
- backward-copy-find - Copy the characters from the
- cursor up to and including the
- preceding occurence of the
- next character typed, into the
- cut buffer.
- forward-copy-to - Copy the characters from the
- cursor up to, but not
- including, the following
- occurence of the next
- character typed, into the cut
- buffer.
- backward-copy-to - Copy the characters from the
- cursor up to, but not
- including, the preceding
- occurence of the next
- character typed, into the cut
- buffer.
- copy-refind - Repeat the last *-copy-find
- or *-copy-to action.
- copy-invert-refind - Repeat the last *-copy-find
- or *-copy-to action, in the
- opposite direction.
- vi-mode - Switch to vi mode from emacs
- mode.
- emacs-mode - Switch to emacs mode from vi
- mode.
- vi-insert - From vi command mode, switch to
- insert mode.
- vi-overwrite - From vi command mode, switch to
- overwrite mode.
- vi-insert-at-bol - From vi command mode, move the
- cursor to the start of the line
- and switch to insert mode.
- vi-append-at-eol - From vi command mode, move the
- cursor to the end of the line
- and switch to append mode.
- vi-append - From vi command mode, move the
- cursor one position right, and
- switch to insert mode.
- vi-replace-char - From vi command mode, replace
- the character under the cursor
- with the the next character
- entered.
- vi-forward-change-char - From vi command mode, delete
- the next character then enter
- insert mode.
- vi-backward-change-char - From vi command mode, delete
- the preceding character then
- enter insert mode.
- vi-forward-change-word - From vi command mode, delete
- the next word then enter
- insert mode.
- vi-backward-change-word - From vi command mode, delete
- the preceding word then
- enter insert mode.
- vi-change-rest-of-line - From vi command mode, delete
- from the cursor to the end of
- the line, then enter insert
- mode.
- vi-change-line - From vi command mode, delete
- the current line, then enter
- insert mode.
- vi-change-to-bol - From vi command mode, delete
- all characters between the
- cursor and the beginning of
- the line, then enter insert
- mode.
- vi-change-to-column - From vi command mode, delete
- the characters from the cursor
- up to the column that is
- specified by the repeat count,
- then enter insert mode.
- vi-change-to-parenthesis - Delete the characters from the
- cursor up to and including
- the matching parenthesis, or
- next close parenthesis, then
- enter vi insert mode.
- vi-forward-change-find - From vi command mode, delete
- the characters from the
- cursor up to and including the
- following occurence of the
- next character typed, then
- enter insert mode.
- vi-backward-change-find - From vi command mode, delete
- the characters from the
- cursor up to and including the
- preceding occurence of the
- next character typed, then
- enter insert mode.
- vi-forward-change-to - From vi command mode, delete
- the characters from the
- cursor up to, but not
- including, the following
- occurence of the next
- character typed, then enter
- insert mode.
- vi-backward-change-to - From vi command mode, delete
- the characters from the
- cursor up to, but not
- including, the preceding
- occurence of the next
- character typed, then enter
- insert mode.
- vi-change-refind - Repeat the last
- vi-*-change-find or
- vi-*-change-to action.
- vi-change-invert-refind - Repeat the last
- vi-*-change-find or
- vi-*-change-to action, in the
- opposite direction.
- vi-undo - In vi mode, undo the last
- editing operation.
- vi-repeat-change - In vi command mode, repeat the
- last command that modified the
- line.
-.fi
-
-.SH DEFAULT KEY BINDINGS IN EMACS MODE
-
-The following default key bindings, which can be overriden by
-the tecla configuration file, are designed to mimic most of
-the bindings of the unix \f3tcsh\f1 shell, when it is in
-emacs editing mode.
-.sp
-This is the default editing mode of the tecla library.
-.sp
-Note that a key sequence like \f3^A\f1 or \f3C-a\f1 means hold the control-key
-down while pressing the letter \f3A\f1, and that where you see \f3\\E\f1 or
-\f3M-\f1 in a binding, this represents the escape key or the Meta modifier
-key. Also note that to \f3gl_get_line()\f1, pressing the escape key before a
-key is equivalent to pressing the meta key at the same time as that key. Thus
-the key sequence \f3M-p\f1 can be typed in two ways, by pressing the escape
-key, followed by pressing \f3p\f1, or by pressing the Meta key at the same time
-as \f3p\f1.
-.sp
-Under UNIX the terminal driver sets a number of special keys for certain
-functions. The tecla library attempts to use the same keybindings to maintain
-consistency. The key sequences shown for the following 6 bindings are thus just
-examples of what they will probably be set to. If you have used the \f3stty\f1
-command to change these keys, then the default bindings should match.
-
-.nf
- ^C -> user-interrupt
- ^\\ -> abort
- ^Z -> suspend
- ^Q -> start-output
- ^S -> stop-output
- ^V -> literal-next
-.fi
-
-The cursor keys are refered to by name, as follows. This is necessary
-because different types of terminals generate different key sequences
-when their cursor keys are pressed.
-
- right -> cursor-right
- left -> cursor-left
- up -> up-history
- down -> down-history
-
-The remaining bindings don't depend on the terminal setttings.
-
-.nf
- ^F -> cursor-right
- ^B -> cursor-left
- M-i -> insert-mode
- ^A -> beginning-of-line
- ^E -> end-of-line
- ^U -> delete-line
- ^K -> kill-line
- M-f -> forward-word
- M-b -> backward-word
- ^D -> del-char-or-list-or-eof
- ^H -> backward-delete-char
- ^? -> backward-delete-char
- M-d -> forward-delete-word
- M-^H -> backward-delete-word
- M-^? -> backward-delete-word
- M-u -> upcase-word
- M-l -> downcase-word
- M-c -> capitalize-word
- ^R -> redisplay
- ^L -> clear-screen
- ^T -> transpose-chars
- ^@ -> set-mark
- ^X^X -> exchange-point-and-mark
- ^W -> kill-region
- M-w -> copy-region-as-kill
- ^Y -> yank
- ^P -> up-history
- ^N -> down-history
- M-p -> history-search-backward
- M-n -> history-search-forward
- ^I -> complete-word
- ^X* -> expand-filename
- ^X^F -> read-from-file
- ^X^R -> read-init-files
- ^Xg -> list-glob
- ^Xh -> list-history
- M-< -> beginning-of-history
- M-> -> end-of-history
- \\n -> newline
- \\r -> newline
- M-o -> repeat-history
- M-^V -> vi-mode
-
- M-0, M-1, ... M-9 -> digit-argument (see below)
-.fi
-
-Note that ^I is what the TAB key generates, and that ^@ can be
-generated not only by pressing the control key and the @ key
-simultaneously, but also by pressing the control key and the space bar
-at the same time.
-
-.SH DEFAULT KEY BINDINGS IN VI MODE
-
-The following default key bindings are designed to mimic the
-vi style of editing as closely as possible. This means that
-very few editing functions are provided in the initial
-character input mode, editing functions instead being
-provided by the vi command mode. Vi command mode is entered
-whenever the escape character is pressed, or whenever a
-key-sequence that starts with a meta character is entered. In
-addition to mimicing vi, libtecla provides bindings for tab
-completion, wild-card expansion of file names, and historical
-line recall.
-.sp
-To learn how to tell the tecla library to use vi mode instead
-of the default emacs editing mode, see the section entitled
-THE TECLA CONFIGURATION FILE.
-.sp
-As already mentioned above in the emacs section, Note that a
-key sequence like \f3^A\f1 or \f3C-a\f1 means hold the
-control-key down while pressing the letter \f3A\f1, and that
-where you see \f3\\E\f1 or \f3M-\f1 in a binding, this
-represents the escape key or the Meta modifier key. Also note
-that to \f3gl_get_line()\f1, pressing the escape key before a
-key is equivalent to pressing the meta key at the same time
-as that key. Thus the key sequence \f3M-p\f1 can be typed in
-two ways, by pressing the escape key, followed by pressing
-\f3p\f1, or by pressing the Meta key at the same time as
-\f3p\f1.
-.sp
-Under UNIX the terminal driver sets a number of special keys
-for certain functions. The tecla library attempts to use the
-same keybindings to maintain consistency, binding them both
-in input mode and in command mode. The key sequences shown
-for the following 6 bindings are thus just examples of what
-they will probably be set to. If you have used the \f3stty\f1
-command to change these keys, then the default bindings
-should match.
-
-.nf
- ^C -> user-interrupt
- ^\\ -> abort
- ^Z -> suspend
- ^Q -> start-output
- ^S -> stop-output
- ^V -> literal-next
- M-^C -> user-interrupt
- M-^\\ -> abort
- M-^Z -> suspend
- M-^Q -> start-output
- M-^S -> stop-output
-.fi
-
-Note that above, most of the bindings are defined twice, once
-as a raw control code like \f3^C\f1 and then a second time as
-a meta character like \f3M-^C\f1. The former is the binding
-for vi input mode, whereas the latter is the binding for vi
-command mode. Once in command mode all key-sequences that the
-user types that they don't explicitly start with an escape or
-a meta key, have their first key secretly converted to a meta
-character before the key sequence is looked up in the key
-binding table. Thus, once in command mode, when you type the
-letter \f3i\f1, for example, the tecla library actually looks
-up the binding for \f3M-i\f1.
-
-The cursor keys are refered to by name, as follows. This is necessary
-because different types of terminals generate different key sequences
-when their cursor keys are pressed.
-
- right -> cursor-right
- left -> cursor-left
- up -> up-history
- down -> down-history
-
-The cursor keys normally generate a keysequence that start
-with an escape character, so beware that using the arrow keys
-will put you into command mode (if you aren't already in
-command mode).
-.sp
-The following are the terminal-independent key bindings for vi input
-mode.
-
-.nf
- ^D -> list-or-eof
- ^G -> list-glob
- ^H -> backward-delete-char
- ^I -> complete-word
- \\r -> newline
- \\n -> newline
- ^L -> clear-screen
- ^N -> down-history
- ^P -> up-history
- ^R -> redisplay
- ^U -> backward-kill-line
- ^W -> backward-delete-word
- ^X* -> expand-filename
- ^X^F -> read-from-file
- ^X^R -> read-init-files
- ^? -> backward-delete-char
-.fi
-
-The following are the key bindings that are defined in vi
-command mode, this being specified by them all starting with
-a meta character. As mentioned above, once in command mode
-the initial meta character is optional. For example, you
-might enter command mode by typing Esc, and then press h
-twice to move the cursor two positions to the left. Both h
-characters get quietly converted to M-h before being compared
-to the key-binding table, the first one because Escape
-followed by a character is always converted to the equivalent
-meta character, and the second because command mode was
-already active.
-
-.nf
- M-\\ -> cursor-right (Meta-space)
- M-$ -> end-of-line
- M-* -> expand-filename
- M-+ -> down-history
- M-- -> up-history
- M-< -> beginning-of-history
- M-> -> end-of-history
- M-^ -> beginning-of-line
- M-; -> repeat-find-char
- M-, -> invert-refind-char
- M-| -> goto-column
- M-~ -> change-case
- M-. -> vi-repeat-change
- M-% -> find-parenthesis
- M-a -> vi-append
- M-A -> vi-append-at-eol
- M-b -> backward-word
- M-B -> backward-word
- M-C -> vi-change-rest-of-line
- M-cb -> vi-backward-change-word
- M-cB -> vi-backward-change-word
- M-cc -> vi-change-line
- M-ce -> vi-forward-change-word
- M-cE -> vi-forward-change-word
- M-cw -> vi-forward-change-word
- M-cW -> vi-forward-change-word
- M-cF -> vi-backward-change-find
- M-cf -> vi-forward-change-find
- M-cT -> vi-backward-change-to
- M-ct -> vi-forward-change-to
- M-c; -> vi-change-refind
- M-c, -> vi-change-invert-refind
- M-ch -> vi-backward-change-char
- M-c^H -> vi-backward-change-char
- M-c^? -> vi-backward-change-char
- M-cl -> vi-forward-change-char
- M-c\\ -> vi-forward-change-char (Meta-c-space)
- M-c^ -> vi-change-to-bol
- M-c0 -> vi-change-to-bol
- M-c$ -> vi-change-rest-of-line
- M-c| -> vi-change-to-column
- M-c% -> vi-change-to-parenthesis
- M-dh -> backward-delete-char
- M-d^H -> backward-delete-char
- M-d^? -> backward-delete-char
- M-dl -> forward-delete-char
- M-d -> forward-delete-char (Meta-d-space)
- M-dd -> delete-line
- M-db -> backward-delete-word
- M-dB -> backward-delete-word
- M-de -> forward-delete-word
- M-dE -> forward-delete-word
- M-dw -> forward-delete-word
- M-dW -> forward-delete-word
- M-dF -> backward-delete-find
- M-df -> forward-delete-find
- M-dT -> backward-delete-to
- M-dt -> forward-delete-to
- M-d; -> delete-refind
- M-d, -> delete-invert-refind
- M-d^ -> backward-kill-line
- M-d0 -> backward-kill-line
- M-d$ -> kill-line
- M-D -> kill-line
- M-d| -> delete-to-column
- M-d% -> delete-to-parenthesis
- M-e -> forward-word
- M-E -> forward-word
- M-f -> forward-find-char
- M-F -> backward-find-char
- M-- -> up-history
- M-h -> cursor-left
- M-H -> beginning-of-history
- M-i -> vi-insert
- M-I -> vi-insert-at-bol
- M-j -> down-history
- M-J -> history-search-forward
- M-k -> up-history
- M-K -> history-search-backward
- M-l -> cursor-right
- M-L -> end-of-history
- M-n -> history-re-search-forward
- M-N -> history-re-search-backward
- M-p -> append-yank
- M-P -> yank
- M-r -> vi-replace-char
- M-R -> vi-overwrite
- M-s -> vi-forward-change-char
- M-S -> vi-change-line
- M-t -> forward-to-char
- M-T -> backward-to-char
- M-u -> vi-undo
- M-w -> forward-to-word
- M-W -> forward-to-word
- M-x -> forward-delete-char
- M-X -> backward-delete-char
- M-yh -> backward-copy-char
- M-y^H -> backward-copy-char
- M-y^? -> backward-copy-char
- M-yl -> forward-copy-char
- M-y\\ -> forward-copy-char (Meta-y-space)
- M-ye -> forward-copy-word
- M-yE -> forward-copy-word
- M-yw -> forward-copy-word
- M-yW -> forward-copy-word
- M-yb -> backward-copy-word
- M-yB -> backward-copy-word
- M-yf -> forward-copy-find
- M-yF -> backward-copy-find
- M-yt -> forward-copy-to
- M-yT -> backward-copy-to
- M-y; -> copy-refind
- M-y, -> copy-invert-refind
- M-y^ -> copy-to-bol
- M-y0 -> copy-to-bol
- M-y$ -> copy-rest-of-line
- M-yy -> copy-line
- M-Y -> copy-line
- M-y| -> copy-to-column
- M-y% -> copy-to-parenthesis
- M-^E -> emacs-mode
- M-^H -> cursor-left
- M-^? -> cursor-left
- M-^L -> clear-screen
- M-^N -> down-history
- M-^P -> up-history
- M-^R -> redisplay
- M-^D -> list-or-eof
- M-^I -> complete-word
- M-\\r -> newline
- M-\\n -> newline
- M-^X^R -> read-init-files
- M-^Xh -> list-history
-
- M-0, M-1, ... M-9 -> digit-argument (see below)
-.fi
-
-Note that ^I is what the TAB key generates.
-
-.SH ENTERING REPEAT COUNTS
-
-Many of the key binding functions described previously, take
-an optional count, typed in before the target
-keysequence. This is interpreted as a repeat count by most
-bindings. A notable exception is the goto-column binding,
-which interprets the count as a column number.
-.sp
-By default you can specify this count argument by pressing
-the meta key while typing in the numeric count. This relies
-on the \f3digit-argument\f1 action being bound to Meta-0,
-Meta-1 etc. Once any one of these bindings has been
-activated, you can optionally take your finger off the meta
-key to type in the rest of the number, since every numeric
-digit thereafter is treated as part of the number, unless it
-is preceded by the \f3literal-next\f1 binding. As soon as a
-non-digit, or literal digit key is pressed the repeat count
-is terminated and either causes the just typed character to
-be added to the line that many times, or causes the next
-key-binding function to be given that argument.
-.sp
-For example, in emacs mode, typing:
-.sp
-.nf
- M-12a
-.fi
-.sp
-causes the letter 'a' to be added to the line 12 times,
-whereas
-.sp
-.nf
- M-4M-c
-.fi
-.sp
-Capitalizes the next 4 words.
-.sp
-In vi command mode the Meta modifier is automatically added
-to all characters typed in, so to enter a count in vi
-command-mode, just involves typing in the number, just as at
-it does in the vi editor itself. So for example, in vi
-command mode, typing:
-.sp
-.nf
- 4w2x
-.fi
-.sp
-moves the cursor four words to the right, then deletes two characters.
-.sp
-You can also bind \f3digit-argument\f1 to other key sequences. If
-these end in a numeric digit, that digit gets appended to the current
-repeat count. If it doesn't end in a numeric digit, a new repeat count
-is started with a value of zero, and can be completed by typing in the
-number, after letting go of the key which triggered the digit-argument
-action.
-
-.SH THE TECLA CONFIGURATION FILE
-
-By default, the first call to \f3gl_get_line()\f1 looks for a file
-called \f3\&.teclarc\f1 in your home directory (ie. \f3~/.teclarc\f1).
-If it finds this file, it reads it, interpreting each line as defining
-a new key binding or an editing configuration option. Since the emacs
-keybindings are installed by default, if you want to use the
-non-default vi editing mode, the most important item to go in this
-file is the following line:
-
-.nf
- edit-mode vi
-.fi
-
-This will re-configure the default bindings for vi-mode. The
-complete set of arguments that this command accepts are:
-.sp
-.nf
- vi - Install key-bindings like those of the vi
- editor.
- emacs - Install key-bindings like those of the emacs
- editor. This is the default.
- none - Use just the native line editing facilities
- provided by the terminal driver.
-.fi
-.sp
-To prevent the terminal bell from being rung, such as when
-an unrecognized control-sequence is typed, place the
-following line in the configuration file:
-
-.nf
- nobeep
-.fi
-
-An example of a key binding line in the configuration file is
-the following.
-
-.nf
- bind M-[2~ insert-mode
-.fi
-
-On many keyboards, the above key sequence is generated when one
-presses the \f3insert\f1 key, so with this keybinding, one can toggle
-between the emacs-mode insert and overwrite modes by hitting one
-key. One could also do it by typing out the above sequence of
-characters one by one. As explained above, the \f3M-\f1 part of this
-sequence can be typed either by pressing the escape key before the
-following key, or by pressing the Meta key at the same time as the
-following key. Thus if you had set the above key binding, and the
-insert key on your keyboard didn't generate the above key sequence,
-you could still type it in either of the following 2 ways.
-
-.nf
- 1. Hit the escape key momentarily, then press '[', then '2', then
- finally '~'.
-
- 2. Press the meta key at the same time as pressing the '[' key,
- then press '2', then '~'.
-.fi
-
-If you set a keybinding for a key-sequence that is already bound to a function,
-the new binding overrides the old one. If in the new binding you omit the name
-of the new function to bind to the key-sequence, the original binding becomes
-undefined.
-.sp
-Starting with versions of libtecla later than 1.3.3 it is now possible
-to bind keysequences that begin with a printable character. Previously
-key-sequences were required to start with a control or meta character.
-.sp
-Note that the special keywords "up", "down", "left" and "right" refer
-to the arrow keys, and are thus not treated as keysequences. So, for
-example, to rebind the up and down arrow keys to use the history
-search mechanism instead of the simple history recall method, you
-could place the following in your configuration file:
-
-.nf
- bind up history-search-backwards
- bind down history-search-backwards
-.fi
-.sp
-To unbind an existing binding, you can do this with the bind command
-by omitting to name any action to rebind the key sequence to. For
-example, by not specifying an action function, the following command
-unbinds the default beginning-of-line action from the ^A key sequence:
-
-.nf
- bind ^A
-.fi
-
-.SH ALTERNATE CONFIGURATION SOURCES
-
-As mentioned above, by default users have the option of configuring
-the behavior of \f3gl_get_line()\f1 via a configuration file called
-\f3\&.teclarc\f1 in their home directories. The fact that all
-applications share this same configuration file is both an advantage
-and a disadvantage. In most cases it is an advantage, since it
-encourages uniformity, and frees the user from having to configure
-each application separately. In some applications, however, this
-single means of configuration is a problem. This is particularly true
-of embedded software, where there's no filesystem to read a
-configuration file from, and also in applications where a radically
-different choice of keybindings is needed to emulate a legacy keyboard
-interface. To cater for such cases, the following function allows the
-application to control where configuration information is read from.
-
-.sp
-.nf
- int gl_configure_getline(GetLine *gl,
- const char *app_string,
- const char *app_file,
- const char *user_file);
-.fi
-.sp
-
-It allows the configuration commands that would normally be read from
-a user's \f3~/.teclarc\f1 file, to be read from any or none of, a
-string, an application specific configuration file, and/or a
-user-specific configuration file. If this function is called before
-the first call to \f3gl_get_line()\f1, the default behavior of
-reading \f3~/.teclarc\f1 on the first call to \f3gl_get_line()\f1 is
-disabled, so all configuration must be achieved using the
-configuration sources specified with this function.
-
-If \f3app_string != NULL\f1, then it is interpreted as a string
-containing one or more configuration commands, separated from each
-other in the string by embedded newline characters. If \f3app_file !=
-NULL\f1 then it is interpreted as the full pathname of an
-application-specific configuration file. If \f3user_file != NULL\f1
-then it is interpreted as the full pathname of a user-specific
-configuration file, such as \f3~/.teclarc\f1. For example, in the
-following call,
-
- gl_configure_getline(gl, "edit-mode vi \\n nobeep",
- "/usr/share/myapp/teclarc",
- "~/.teclarc");
-
-the \f3app_string\f1 argument causes the calling application to start
-in vi edit-mode, instead of the default emacs mode, and turns off the
-use of the terminal bell by the library. It then attempts to read
-system-wide configuration commands from an optional file called
-\f3/usr/share/myapp/teclarc\f1, then finally reads user-specific
-configuration commands from an optional \f3\&.teclarc\f1 file in the
-user's home directory. Note that the arguments are listed in ascending
-order of priority, with the contents of \f3app_string\f1 being
-potentially overriden by commands in \f3app_file\f1, and commands in
-\f3app_file\f1 potentially being overriden by commands in
-\f3user_file\f1.
-.sp
-You can call this function as many times as needed, the results being
-cumulative, but note that copies of any filenames specified via the
-\f3app_file\f1 and \f3user_file\f1 arguments are recorded internally
-for subsequent use by the \f3read-init-files\f1 key-binding function,
-so if you plan to call this function multiple times, be sure that the
-last call specifies the filenames that you want re-read when the user
-requests that the configuration files be re-read.
-
-.SH FILENAME AND TILDE COMPLETION
-
-With the default key bindings, pressing the TAB key (aka. ^I) results
-in \f3gl_get_line()\f1 attempting to complete the incomplete filename
-that precedes the cursor. \f3gl_get_line()\f1 searches backwards from
-the cursor, looking for the start of the filename, stopping when it
-hits either a space or the start of the line. If more than one file
-has the specified prefix, \f3gl_get_line()\f1 completes the filename
-up to the point at which the ambiguous matches start to differ, then
-lists the possible matches.
-.sp
-In addition to literally written filenames, \f3gl_get_line()\f1 can
-complete files that start with \f3~/\f1 and \f3~user/\f1 expressions
-and that contain \f3$envvar\f1 expressions. In particular, if you hit
-TAB within an incomplete \f3~user\f1, expression, \f3gl_get_line()\f1
-will attempt to complete the username, listing any ambiguous matches.
-.sp
-The completion binding is implemented using the
-\f3cpl_word_completions()\f1 function, which is also available
-separately to users of this library. See the
-\f3cpl_word_completions(3)\f1 man page for more details.
-
-.SH CUSTOMIZED WORD COMPLETION
-
-If in your application, you would like to have TAB completion complete
-other things in addition to or instead of filenames, you can arrange
-this by registering an alternate completion callback function, via a
-call to the \f3gl_customize_completion()\f1 function.
-.sp
-.nf
- int gl_customize_completion(GetLine *gl, void *data,
- CplMatchFn *match_fn);
-.fi
-.sp
-The \f3data\f1 argument provides a way for your application to pass
-arbitrary, application-specific information to the callback
-function. This is passed to the callback every time that it is
-called. It might for example, point to the symbol table from which
-possible completions are to be sought. The \f3match_fn\f1 argument
-specifies the callback function to be called. The \f3CplMatchFn\f1
-function type is defined in \f3libtecla.h\f1, as is a
-\f3CPL_MATCH_FN()\f1 macro that you can use to declare and prototype
-callback functions. The declaration and responsibilities of callback
-functions are described in depth in the \f1cpl_complete_word(3)\f1 man
-page.
-.sp
-In brief, the callback function is responsible for looking backwards
-in the input line, back from the point at which the user pressed TAB,
-to find the start of the word being completed. It then must lookup
-possible completions of this word, and record them one by one in the
-\f3WordCompletion\f1 object that is passed to it as an argument, by
-calling the \f3cpl_add_completion()\f1 function. If the callback
-function wishes to provide filename completion in addition to its own
-specific completions, it has the option of itself calling the builtin
-file-name completion callback. This also, is documented in the
-\f3cpl_complete_word(3)\f1 man page.
-.sp
-Note that if you would like \f3gl_get_line()\f1 to return the current
-input line when a successful completion is been made, you can arrange
-this when you call \f3cpl_add_completion()\f1, by making the last
-character of the continuation suffix a newline character. If you do
-this, the input line will be updated to display the completion,
-together with any contiuation suffix up to the newline character, then
-\f3gl_get_line()\f1 will return this input line.
-
-.SH FILENAME EXPANSION
-
-With the default key bindings, pressing \f3^X*\f1 causes
-\f3gl_get_line()\f1 to expand the filename that precedes the cursor,
-replacing \f3~/\f1 and \f3~user/\f1 expressions with the corresponding
-home directories, and replacing \f3$envvar\f1 expressions with the
-value of the specified environment variable, then if there are any
-wildcards, replacing the so far expanded filename with a
-space-separated list of the files which match the wild cards.
-.sp
-The expansion binding is implemented using the \f3ef_expand_file()\f1 function.
-See the \f3ef_expand_file(3)\f1 man page for more details.
-
-.SH RECALLING PREVIOUSLY TYPED LINES
-
-Every time that a new line is entered by the user, it is appended to a
-list of historical input lines maintained within the GetLine resource
-object. You can traverse up and down this list using the up and down
-arrow keys. Alternatively, you can do the same with the \f3^P\f1, and
-\f3^N\f1 keys, and in vi command mode you can alternatively use the k
-and j characters. Thus pressing up-arrow once, replaces the current
-input line with the previously entered line. Pressing up-arrow again,
-replaces this with the line that was entered before it, etc.. Having
-gone back one or more lines into the history list, one can return to
-newer lines by pressing down-arrow one or more times. If you do this
-sufficient times, you will return to the original line that you were
-entering when you first hit up-arrow.
-.sp
-Note that in vi mode, all of the history recall functions switch the
-library into command mode.
-.sp
-In emacs mode the \f3M-p\f1 and \f3M-n\f1 keys work just like the
-\f3^P\f1 and \f3^N\f1 keys, except that they skip all but those
-historical lines which share the prefix that precedes the cursor. In
-vi command mode the upper case \f3K\f1 and \f3J\f1 characters do the
-same thing, except that the string that they search for includes the
-character under the cursor as well as what precedes it.
-.sp
-Thus for example, suppose that you were in emacs mode, and you had
-just entered the following list of commands in the order shown:
-
-.nf
- ls ~/tecla/
- cd ~/tecla
- ls -l getline.c
- emacs ~/tecla/getline.c
-.fi
-
-If you next typed:
-
-.nf
- ls
-.fi
-
-and then hit \f3M-p\f1, then rather than returning the previously
-typed emacs line, which doesn't start with "ls", \f3gl_get_line()\f1
-would recall the "ls -l getline.c" line. Pressing \f3M-p\f1 again
-would recall the "ls ~/tecla/" line.
-
-.SH HISTORY FILES
-
-To save the contents of the history buffer before quitting your
-application, and subsequently restore them when you next start the
-application, the following functions are provided.
-
-.sp
-.nf
- int gl_save_history(GetLine *gl, const char *filename,
- const char *comment, int max_lines);
- int gl_load_history(GetLine *gl, const char *filename,
- const char *comment);
-.fi
-.sp
-
-The \f3filename\f1 argument specifies the name to give the history
-file when saving, or the name of an existing history file, when
-loading. This may contain home-directory and environment variable
-expressions, such as "~/.myapp_history" or "$HOME/.myapp_history".
-.sp
-Along with each history line, extra information about it, such as when
-it was entered by the user, and what its nesting level is, is recorded
-as a comment preceding the line in the history file. Writing this as a
-comment allows the history file to double as a command file, just in
-case you wish to replay a whole session using it. Since comment
-prefixes differ in different languages, the \f3comment\f1 argument is
-provided for specifying the comment prefix. For example, if your
-application were a unix shell, such as the bourne shell, you would
-specify "#" here. Whatever you choose for the comment character, you
-must specify the same prefix to \f3gl_load_history()\f1 that you used
-when you called \f3gl_save_history()\f1 to write the history file.
-.sp
-The \f3max_lines\f1 must be either -1 to specify that all lines in the
-history list be saved, or a positive number specifying a ceiling on
-how many of the most recent lines should be saved.
-.sp
-Both fuctions return non-zero on error, after writing an error message
-to stderr. Note that \f3gl_load_history()\f1 does not consider the
-non-existence of a file to be an error.
-
-.SH MULTIPLE HISTORY LISTS
-
-If your application uses a single \f3GetLine\f1 object for entering
-many different types of input lines, you may wish \f3gl_get_line()\f1
-to distinguish the different types of lines in the history list, and
-only recall lines that match the current type of line. To support this
-requirement, \f3gl_get_line()\f1 marks lines being recorded in the
-history list with an integer identifier chosen by the application.
-Initially this identifier is set to \f10\f3 by \f3new_GetLine()\f1,
-but it can be changed subsequently by calling
-\f3gl_group_history()\f1.
-
-.sp
-.nf
- int gl_group_history(GetLine *gl, unsigned id);
-.fi
-.sp
-
-The integer identifier \f3id\f1 can be any number chosen by the
-application, but note that \f3gl_save_history()\f1 and
-\f3gl_load_history()\f1 preserve the association between identifiers
-and historical input lines between program invokations, so you should
-choose fixed identifiers for the different types of input line used by
-your application.
-.sp
-Whenever \f3gl_get_line()\f1 appends a new input line to the history
-list, the current history identifier is recorded with it, and when it
-is asked to recall a historical input line, it only recalls lines that
-are marked with the current identifier.
-
-.SH DISPLAYING HISTORY
-
-The history list can be displayed by calling \f3gl_show_history()\f1.
-
-.sp
-.nf
- int gl_show_history(GetLine *gl, FILE *fp,
- const char *fmt,
- int all_groups,
- int max_lines);
-.fi
-.sp
-
-This displays the current contents of the history list to the stdio
-output stream \f3fp\f1. If the \f3max_lines\f1 argument is greater
-than or equal to zero, then no more than this number of the most
-recent lines will be displayed. If the \f3all_groups\f1 argument is
-non-zero, lines from all history groups are displayed. Otherwise just
-those of the currently selected history group are displayed. The
-format string argument, \f3fmt\f1, determines how the line is
-displayed. This can contain arbitrary characters which are written
-verbatim, interleaved with any of the following format directives:
-
-.nf
- %D - The date on which the line was originally
- entered, formatted like 2001-11-20.
- %T - The time of day when the line was entered,
- formatted like 23:59:59.
- %N - The sequential entry number of the line in
- the history buffer.
- %G - The number of the history group which the
- line belongs to.
- %% - A literal % character.
- %H - The history line itself.
-.fi
-
-Thus a format string like \f3"%D %T %H\n"\f1 would output something like:
-
-.nf
- 2001-11-20 10:23:34 Hello world
-.fi
-
-Note the inclusion of an explicit newline character in the format
-string.
-
-.SH LOOKING UP HISTORY
-
-The \f3gl_lookup_history()\f1 function allows the calling application
-to look up lines in the history list.
-
-.sp
-.nf
- typedef struct {
- const char *line; /* The requested historical */
- /* line. */
- unsigned group; /* The history group to which */
- /* the line belongs. */
- time_t timestamp; /* The date and time at which */
- /* the line was originally */
- /* entered. */
- } GlHistoryLine;
-
- int gl_lookup_history(GetLine *gl, unsigned long id,
- GlHistoryLine *hline);
-.fi
-.sp
-
-The \f3id\f1 argument indicates which line to look up, where the first
-line that was entered in the history list after \f3new_GetLine()\f1
-was called, is denoted by 0, and subsequently entered lines are
-denoted with successively higher numbers. Note that the range of lines
-currently preserved in the history list can be queried by calling the
-\f3gl_range_of_history()\f1 function, described later. If the
-requested line is in the history list, the details of the line are
-recorded in the variable pointed to by the \f3hline\f1 argument, and
-\f31\f1 is returned. Otherwise \f30\f1 is returned, and the variable
-pointed to by \f3hline\f1 is left unchanged.
-.sp
-Beware that the string returned in \f3hline->line\f1 is part of the
-history buffer, so it must not be modified by the caller, and will be
-recycled on the next call to any function that takes \f3gl\f1 as its
-argument. Therefore you should make a private copy of this string if
-you need to keep it around.
-
-.SH MISCELLANEOUS HISTORY CONFIGURATION
-
-If you wish to change the size of the history buffer that was
-originally specified in the call to \f3new_GetLine()\f1, you can do so
-with the \f3gl_resize_history()\f1 function.
-
-.sp
-.nf
- int gl_resize_history(GetLine *gl, size_t histlen);
-.fi
-.sp
-
-The \f3histlen\f1 argument specifies the new size in bytes, and if you
-specify this as 0, the buffer will be deleted.
-.sp
-As mentioned in the discussion of \f3new_GetLine()\f1, the number of
-lines that can be stored in the history buffer, depends on the lengths
-of the individual lines. For example, a 1000 byte buffer could equally
-store 10 lines of average length 100 bytes, or 2 lines of average
-length 50 bytes. Although the buffer is never expanded when new lines
-are added, a list of pointers into the buffer does get expanded when
-needed to accomodate the number of lines currently stored in the
-buffer. To place an upper limit on the number of lines in the buffer,
-and thus a ceiling on the amount of memory used in this list, you can
-call the \f3gl_limit_history()\f1 function.
-
-.sp
-.nf
- void gl_limit_history(GetLine *gl, int max_lines);
-.fi
-.sp
-
-The \f3max_lines\f1 should either be a positive number \f3>= 0\f1,
-specifying an upper limit on the number of lines in the buffer, or be
-\f3-1\f1 to cancel any previously specified limit. When a limit is in
-effect, only the \f3max_lines\f1 most recently appended lines are kept
-in the buffer. Older lines are discarded.
-.sp
-To discard lines from the history buffer, use the
-\f3gl_clear_history()\f1 function.
-.sp
-.nf
- void gl_clear_history(GetLine *gl, int all_groups);
-.fi
-.sp
-The \f3all_groups\f1 argument tells the function whether to delete
-just the lines associated with the current history group (see
-\f3gl_group_history()\f1), or all historical lines in the buffer.
-.sp
-The \f3gl_toggle_history()\f1 function allows you to toggle history on
-and off without losing the current contents of the history list.
-
-.sp
-.nf
- void gl_toggle_history(GetLine *gl, int enable);
-.fi
-.sp
-
-Setting the \f3enable\f1 argument to 0 turns off the history
-mechanism, and setting it to 1 turns it back on. When history is
-turned off, no new lines will be added to the history list, and
-history lookup key-bindings will act as though there is nothing in the
-history buffer.
-
-.SH QUERYING HISTORY INFORMATION
-
-The configured state of the history list can be queried with the
-\f3gl_history_state()\f1 function.
-
-.sp
-.nf
- typedef struct {
- int enabled; /* True if history is enabled */
- unsigned group; /* The current history group */
- int max_lines; /* The current upper limit on the */
- /* number of lines in the history */
- /* list, or -1 if unlimited. */
- } GlHistoryState;
-
- void gl_state_of_history(GetLine *gl,
- GlHistoryState *state);
-.fi
-.sp
-On return, the status information is recorded in the variable pointed
-to by the \f3state\f1 argument.
-.sp
-The \f3gl_range_of_history()\f1 function returns the number and
-range of lines in the history list.
-
-.sp
-.nf
-typedef struct {
- unsigned long oldest; /* The sequential entry number */
- /* of the oldest line in the */
- /* history list. */
- unsigned long newest; /* The sequential entry number */
- /* of the newest line in the */
- /* history list. */
- int nlines; /* The number of lines in the */
- /* history list. */
-} GlHistoryRange;
-
-void gl_range_of_history(GetLine *gl, GlHistoryRange *range);
-.fi
-.sp
-The return values are recorded in the variable pointed to by the
-\f3range\f1 argument. If the \f3nlines\f1 member of this structure is
-greater than zero, then the \f3oldest\f1 and \f3newest\f1 members
-report the range of lines in the list, and \f3newest=oldest+nlines-1\f1.
-Otherwise they are both zero.
-.sp
-The \f3gl_size_of_history()\f1 function returns the total size of the
-history buffer and the amount of the buffer that is currently
-occupied.
-.sp
-.nf
- typedef struct {
- size_t size; /* The size of the history buffer */
- /* (bytes). */
- size_t used; /* The number of bytes of the */
- /* history buffer that are */
- /* currently occupied. */
- } GlHistorySize;
-
- void gl_size_of_history(GetLine *gl, GlHistorySize *size);
-.fi
-.sp
-On return, the size information is recorded in the variable pointed to
-by the \f3size\f1 argument.
-
-.SH CHANGING TERMINALS
-
-The \f3new_GetLine()\f1 constructor function assumes that input is to
-be read from \f3stdin\f1, and output written to \f3stdout\f1. The
-following function allows you to switch to different input and output
-streams.
-.sp
-.nf
- int gl_change_terminal(GetLine *gl, FILE *input_fp,
- FILE *output_fp, const char *term);
-.fi
-.sp
-The \f3gl\f1 argument is the object that was returned by
-\f3new_GetLine()\f1. The \f3input_fp\f1 argument specifies the stream
-to read from, and \f3output_fp\f1 specifies the stream to be written
-to. Only if both of these refer to a terminal, will interactive
-terminal input be enabled. Otherwise \f3gl_get_line()\f1 will simply
-call \f3fgets()\f1 to read command input. If both streams refer to a
-terminal, then they must refer to the same terminal, and the type of
-this terminal must be specified via the \f3term\f1 argument. The value
-of the \f3term\f1 argument is looked up in the terminal information
-database (terminfo or termcap), in order to determine which special
-control sequences are needed to control various aspects of the
-terminal. \f3new_GetLine()\f1 for example, passes the return value of
-\f3getenv("TERM")\f1 in this argument. Note that if one or both of
-\f3input_fp\f1 and \f3output_fp\f1 don't refer to a terminal, then it
-is legal to pass \f3NULL\f1 instead of a terminal type.
-.sp
-Note that if you want to pass file descriptors to
-\f3gl_change_terminal()\f1, you can do this by creating stdio stream
-wrappers using the POSIX \f3fdopen()\f1 function.
-
-.SH EXTERNAL EVENT HANDLING
-
-While \f3gl_get_line()\f1 is waiting for keyboard input from the user,
-you can ask it to also watch for activity on arbitrary file
-descriptors, such as network sockets, pipes etc, and have it call
-functions of your choosing when activity is seen. This works on any
-system that has the \f3select()\f1 system call, which is most, if not
-all flavors of unix. Registering a file descriptor to be watched by
-\f3gl_get_line()\f1 involves calling the \f3gl_watch_fd()\f1 function.
-
-.sp
-.nf
- int gl_watch_fd(GetLine *gl, int fd, GlFdEvent event,
- GlFdEventFn *callback, void *data);
-.fi
-.sp
-
-If this returns non-zero, then it means that either your arguments are
-invalid, or that this facility isn't supported on the host system.
-.sp
-The \f3fd\f1 argument is the file descriptor to be watched. The
-\f3event\f1 argument specifies what type of activity is of interest,
-chosen from the following enumerated values:
-
-.sp
-.nf
- GLFD_READ - Watch for the arrival of data to be read.
- GLFD_WRITE - Watch for the ability to write to the file
- descriptor without blocking.
- GLFD_URGENT - Watch for the arrival of urgent
- out-of-band data on the file descriptor.
-.fi
-.sp
-
-The \f3callback\f1 argument is the function to call when the selected
-activity is seen. It should be defined with the following macro, which
-is defined in libtecla.h.
-
-.sp
-.nf
- #define GL_FD_EVENT_FN(fn) GlFdStatus (fn)(GetLine *gl, \\
- void *data, int fd, \\
- GlFdEvent event)
-.fi
-.sp
-The \f3data\f1 argument of the \f3gl_watch_fd()\f1 function is passed
-to the callback function for its own use, and can point to anything
-you like, including \f3NULL\f1. The file descriptor and the event
-argument are also passed to the callback function, and this
-potentially allows the same callback function to be registered to more
-than one type of event and/or more than one file descriptor. The
-return value of the callback function should be one of the following
-values.
-
-.sp
-.nf
- GLFD_ABORT - Tell gl_get_line() to abort with an
- error (errno won't be set, so set it
- appropriately yourself if you need it).
- GLFD_REFRESH - Redraw the input line then continue
- waiting for input. Return this if
- your callback wrote to the terminal.
- GLFD_CONTINUE - Continue to wait for input, without
- redrawing the line.
-.fi
-.sp
-Note that before calling the callback, \f3gl_get_line()\f1 blocks most
-signals, and leaves its own signal handlers installed, so if you need
-to catch a particular signal you will need to both temporarily install
-your own signal handler, and unblock the signal. Be sure to re-block
-the signal (if it was originally blocked) and reinstate the original
-signal handler, if any, before returning.
-.sp
-Your callback shouldn't try to read from the terminal, which is left
-in raw mode as far as input is concerned. You can however write to the
-terminal as usual, since features like conversion of newline to
-carriage-return/linefeed are re-enabled while the callback is
-running. If your callback function does write to the terminal, be sure
-to output a newline first, and when your callback returns, tell
-\f3gl_get_line()\f1 that the input line needs to be redrawn, by
-returning the \f3GLFD_REFRESH\f1 status code.
-.sp
-To remove a callback function that you previously registered for a
-given file descriptor and event, simply call \f3gl_watch_fd()\f1 with
-the same file descriptor and \f3event\f1 arguments, but with a
-\f3callback\f1 argument of \f30\f1. The \f3data\f1 argument is ignored
-in this case.
-
-.SH SIGNAL HANDLING DEFAULTS
-
-By default, the \f3gl_get_line()\f1 function intercepts a
-number of signals. This is particularly important for
-signals which would by default terminate the process, since
-the terminal needs to be restored to a usable state before
-this happens. In this section, the signals that are trapped
-by default, and how gl_get_line() responds to them, is
-described. Changing these defaults is the topic of the
-following section.
-.sp
-When the following subset of signals are caught, \f3gl_get_line()\f1
-first restores the terminal settings and signal handling to how they
-were before \f3gl_get_line()\f1 was called, resends the signal, to
-allow the calling application's signal handlers to handle it, then if
-the process still exists, \f3gl_get_line()\f1 returns \f3NULL\f1 and
-sets \f3errno\f1 as specified below.
-
-.sp
-.nf
- SIGINT - This signal is generated both by the keyboard
- interrupt key (usually ^C), and the keyboard
- break key.
-
- errno=EINTR
-
- SIGHUP - This signal is generated when the controlling
- terminal exits.
-
- errno=ENOTTY
-
- SIGPIPE - This signal is generated when a program attempts
- to write to a pipe who's remote end isn't being
- read by any process. This can happen for example
- if you have called \f3gl_change_terminal()\f1 to
- redirect output to a pipe hidden under a pseudo
- terminal.
-
- errno=EPIPE
-
- SIGQUIT - This signal is generated by the keyboard quit
- key (usually ^\\).
-
- errno=EINTR
-
- SIGABRT - This signal is generated by the standard C,
- abort() function. By default it both
- terminates the process and generates a core
- dump.
-
- errno=EINTR
-
- SIGTERM - This is the default signal that the UN*X
- kill command sends to processes.
-
- errno=EINTR
-.fi
-.sp
-Note that in the case of all of the above signals, POSIX mandates that
-by default the process is terminated, with the addition of a core dump
-in the case of the \f3SIGQUIT\f1 signal. In other words, if the
-calling application doesn't override the default handler by supplying
-its own signal handler, receipt of the corresponding signal will
-terminate the application before \f3gl_get_line()\f1 returns.
-.sp
-If gl_get_line() aborts with errno set to EINTR, you can find out what
-signal caused it to abort, by calling the following function.
-.sp
-.nf
- int gl_last_signal(const GetLine *gl);
-.fi
-.sp
-This returns the numeric code (eg. \f3SIGINT\f1) of the last signal
-that was received during the most recent call to \f3gl_get_line()\f1,
-or \f3-1\f1 if no signals were received.
-.sp
-On systems that support it, when a SIGWINCH (window change) signal is
-received, \f3gl_get_line()\f1 queries the terminal to find out its new
-size, redraws the current input line to accomodate the new size, then
-returns to waiting for keyboard input from the user. Unlike other
-signals, this signal isn't resent to the application.
-.sp
-Finally, the following signals cause \f3gl_get_line()\f1 to first
-restore the terminal and signal environment to that which prevailed
-before \f3gl_get_line()\f1 was called, then resend the signal to the
-application. If the process still exists after the signal has been
-delivered, then \f3gl_get_line()\f1 then re-establishes its own signal
-handlers, switches the terminal back to raw mode, redisplays the input
-line, and goes back to awaiting terminal input from the user.
-.sp
-.nf
- SIGCONT - This signal is generated when a suspended
- process is resumed.
-
- SIGPWR - This signal is generated when a power failure
- occurs (presumably when the system is on a
- UPS).
-
- SIGALRM - This signal is generated when a timer
- expires.
-
- SIGUSR1 - An application specific signal.
-
- SIGUSR2 - Another application specific signal.
-
- SIGVTALRM - This signal is generated when a virtual
- timer expires (see man setitimer(2)).
-
- SIGXCPU - This signal is generated when a process
- exceeds its soft CPU time limit.
-
- SIGTSTP - This signal is generated by the terminal
- suspend key, which is usually ^Z, or the
- delayed terminal suspend key, which is
- usually ^Y.
-
- SIGTTIN - This signal is generated if the program
- attempts to read from the terminal while the
- program is running in the background.
-
- SIGTTOU - This signal is generated if the program
- attempts to write to the terminal while the
- program is running in the background.
-.fi
-.sp
-
-Obviously not all of the above signals are supported on all systems,
-so code to support them is conditionally compiled into the tecla
-library.
-.sp
-Note that if \f3SIGKILL\f1, which by definition can't be caught, or
-any of the hardware generated exception signals, such as
-\f3SIGSEGV\f1, \f3SIGBUS\f1 and \f3SIGFPE\f1, are received and
-unhandled while \f3gl_get_line()\f1 has the terminal in raw mode, the
-program will be terminated without the terminal having been restored
-to a usable state. In practice, job-control shells usually reset the
-terminal settings when a process relinquishes the controlling
-terminal, so this is only a problem with older shells.
-
-.SH CUSTOMIZED SIGNAL HANDLING
-
-The previous section listed the signals that
-\f3gl_get_line()\f1 traps by default, and described how it
-responds to them. This section describes how to both add and
-remove signals from the list of trapped signals, and how to
-specify how \f3gl_get_line()\f1 should respond to a given
-signal.
-.sp
-If you don't need \f3gl_get_line()\f1 to do anything in
-response to a signal that it normally traps, you can tell to
-\f3gl_get_line()\f1 to ignore that signal by calling
-\f3gl_ignore_signal()\f1.
-.sp
-.nf
- int gl_ignore_signal(GetLine *gl, int signo);
-.fi
-.sp
-The \f3signo\f1 argument is the number of the signal
-(eg. \f3SIGINT\f1) that you want to have ignored. If the
-specified signal isn't currently one of those being trapped,
-this function does nothing.
-.sp
-The \f3gl_trap_signal()\f1 function allows you to either add
-a new signal to the list that \f3gl_get_line()\f1 traps, or
-modify how it responds to a signal that it already traps.
-.sp
-.nf
- int gl_trap_signal(GetLine *gl, int signo, unsigned flags,
- GlAfterSignal after, int errno_value);
-.fi
-.sp
-The \f3signo\f1 argument is the number of the signal that
-you wish to have trapped. The \f3flags\f1 argument is a set
-of flags which determine the environment in which the
-application's signal handler is invoked, the \f3after\f1
-argument tells \f3gl_get_line()\f1 what to do after the
-application's signal handler returns, and \f3errno_value\f1
-tells \f3gl_get_line()\f1 what to set \f3errno\f1 to if told
-to abort.
-.sp
-The \f3flags\f1 argument is a bitwise OR of zero or more of
-the following enumerators:
-.sp
-.nf
- GLS_RESTORE_SIG - Restore the caller's signal
- environment while handling the
- signal.
-
- GLS_RESTORE_TTY - Restore the caller's terminal settings
- while handling the signal.
-
- GLS_RESTORE_LINE - Move the cursor to the start of the
- line following the input line before
- invoking the application's signal
- handler.
-
- GLS_REDRAW_LINE - Redraw the input line when the
- application's signal handler returns.
-
- GLS_UNBLOCK_SIG - Normally, if the calling program has
- a signal blocked (man sigprocmask),
- gl_get_line() does not trap that
- signal. This flag tells gl_get_line()
- to trap the signal and unblock it for
- the duration of the call to
- gl_get_line().
-
- GLS_DONT_FORWARD - If this flag is included, the signal
- will not be forwarded to the signal
- handler of the calling program.
-.fi
-.sp
-Two commonly useful flag combinations are also enumerated as
-follows:
-.sp
-.nf
- GLS_RESTORE_ENV = GLS_RESTORE_SIG | GLS_RESTORE_TTY |
- GLS_REDRAW_LINE
-
- GLS_SUSPEND_INPUT = GLS_RESTORE_ENV | GLS_RESTORE_LINE
-.fi
-.sp
-
-If your signal handler, or the default system signal
-handler for this signal, if you haven't overriden it, never
-either writes to the terminal, nor suspends or terminates
-the calling program, then you can safely set the \f3flags\f1
-argument to \f30\f1.
-.sp
-If your signal handler always writes to the terminal, reads
-from it, or suspends or terminates the program, you should
-specify the \f3flags\f1 argument as \f3GL_SUSPEND_INPUT\f1,
-so that:
-.sp
-.nf
-1. The cursor doesn't get left in the middle of the input
- line.
-2. So that the user can type in input and have it echoed.
-3. So that you don't need to end each output line with
- \f3\\r\\n\f1, instead of just \f3\\n\f1.
-.fi
-.sp
-The \f3GL_RESTORE_ENV\f1 combination is the same as
-\f3GL_SUSPEND_INPUT\f1, except that it doesn't move the
-cursor, and if your signal handler doesn't read or write
-anything to the terminal, the user won't see any visible
-indication that a signal was caught. This can be useful if
-you have a signal handler that only occasionally writes to
-the terminal, where using \f3GL_SUSPEND_LINE\f1 would cause
-the input line to be unnecessarily duplicated when nothing
-had been written to the terminal. Such a signal handler,
-when it does write to the terminal, should be sure to start
-a new line at the start of its first write, by writing a
-'\\n' character, and should be sure to leave the cursor on a
-new line before returning. If the signal arrives while the
-user is entering a line that only occupies a signal terminal
-line, or if the cursor is on the last terminal line of a
-longer input line, this will have the same effect as
-\f3GL_SUSPEND_INPUT\f1. Otherwise it will start writing on a
-line that already contains part of the displayed input line.
-This doesn't do any harm, but it looks a bit ugly, which is
-why the \f3GL_SUSPEND_INPUT\f1 combination is better if you
-know that you are always going to be writting to the
-terminal.
-.sp
-The \f3after\f1 argument, which determines what
-\f3gl_get_line()\f1 does after the application's signal
-handler returns (if it returns), can take any one of the
-following values:
-.sp
-.nf
- GLS_RETURN - Return the completed input line, just as
- though the user had pressed the return
- key.
-
- GLS_ABORT - Cause gl_get_line() to return \f3NULL\f1.
-
- GLS_CONTINUE - Resume command line editing.
-.fi
-.sp
-The \f3errno_value\f1 argument is intended to be combined
-with the \f3GLS_ABORT\f1 option, telling \f3gl_get_line()\f1
-what to set the standard \f3errno\f1 variable to before
-returning \f3NULL\f1 to the calling program. It can also,
-however, be used with the \f3GL_RETURN\f1 option, in case
-you wish to have a way to distinguish between an input line
-that was entered using the return key, and one that was
-entered by the receipt of a signal.
-
-.SH THE TERMINAL SIZE
-
-On most systems the combination of the \f3TIOCGWINSZ\f1 ioctl and the
-\f3SIGWINCH\f1 signal is used to maintain an accurate idea of the
-terminal size. The terminal size is newly queried every time that
-\f3gl_get_line()\f1 is called and whenever a \f3SIGWINCH\f1 signal is
-received.
-.sp
-On the few systems where this mechanism isn't available, at
-startup \f3new_GetLine()\f1 first looks for the \f3LINES\f1
-and \f3COLUMNS\f1 environment variables. If these aren't
-found, or they contain unusable values, then if a terminal
-information database like terminfo or termcap is available,
-the default size of the terminal is looked up in this
-database. If this too fails to provide the terminal size, a
-default size of 80 columns by 24 lines is used. If this
-default isn't appropriate for your system,
-\f3gl_terminal_size()\f1 can be used to supply a different
-fallback.
-.sp
-The \f3gl_terminal_size()\f1 function allows you to query
-the current size of the terminal, and install an alternate
-fallback size for cases where the size isn't available.
-Beware that the terminal size won't be available if reading
-from a pipe or a file, so the default values can be
-important even on systems that do support ways of finding
-out the terminal size.
-.sp
-.nf
- typedef struct {
- int nline; /* The terminal has nline lines */
- int ncolumn; /* The terminal has ncolumn columns */
- } GlTerminalSize;
-
- GlTerminalSize gl_terminal_size(GetLine *gl,
- int def_ncolumn,
- int def_nline);
-.fi
-.sp
-This function first updates \f3gl_get_line()\f1's idea of
-the terminal size, then records its findings in the return
-value.
-.sp
-The \f3def_ncolumn\f1 and \f3def_nline\f1 specify the
-default number of terminal columns and lines to use if the
-terminal size can't be determined.
-
-.SH HIDING WHAT YOU TYPE
-
-When entering sensitive information, such as passwords, it is best not
-to have the text that you are entering echoed on the terminal.
-Furthermore, such text should not be recorded in the history list,
-since somebody finding your terminal unattended could then recall it,
-or somebody snooping through your directories could see it in your
-history file. With this in mind, the \f3gl_echo_mode()\f1
-function allows you to toggle on and off the display and archival of
-any text that is subsequently entered in calls to \f3gl_get_line()\f1.
-
-.sp
-.nf
- int gl_echo_mode(GetLine *gl, int enable);
-.fi
-.sp
-
-The \f3enable\f1 argument specifies whether entered text
-should be visible or not. If it is \f30\f1, then
-subsequently entered lines will not be visible on the
-terminal, and will not be recorded in the history list. If
-it is \f31\f1, then subsequent input lines will be displayed
-as they are entered, and provided that history hasn't been
-turned off via a call to \f3gl_toggle_history()\f1, then
-they will also be archived in the history list. Finally, if
-the \f3enable\f1 argument is \f3-1\f1, then the echoing mode
-is left unchanged, which allows you to non-destructively
-query the current setting via the return value. In all
-cases, the return value of the function is \f30\f1 if
-echoing was disabled before the function was called, and
-\f31\f1 if it was enabled.
-.sp
-When echoing is turned off, note that although tab
-completion will invisibly complete your prefix as far as
-possible, ambiguous completions will not be displayed.
-
-.SH CALLBACK FUNCTION FACILITIES
-
-Unless otherwise stated, callback functions, such as tab
-completion callbacks and event callbacks should not call any
-functions in this module. The following functions, however,
-are designed specifically to be used by callback functions.
-.sp
-Calling the \f3gl_replace_prompt()\f1 function from a
-callback tells \f3gl_get_line() to display a different
-prompt when the callback returns. It has no effect if called
-when \f3gl_get_line()\f1 is not being called.
-.sp
-.nf
- void gl_replace_prompt(GetLine *gl, const char *prompt);
-.fi
-.sp
-
-.SH INTERNATIONAL CHARACTER SETS
-
-Since libtecla version 1.4.0, \f3gl_get_line()\f1 has been 8-bit
-clean. This means that all 8-bit characters that are printable in the
-user's current locale are now displayed verbatim and included in the
-returned input line. Assuming that the calling program correctly
-contains a call like the following,
-.sp
-.nf
- setlocale(LC_CTYPE, "");
-.fi
-.sp
-then the current locale is determined by the first of the environment
-variables \f3LC_CTYPE\f1, \f3LC_ALL\f1, and \f3LANG\f1, that is found
-to contain a valid locale name. If none of these variables are
-defined, or the program neglects to call setlocale, then the default
-\f3C\f1 locale is used, which is US 7-bit ASCII. On most unix-like
-platforms, you can get a list of valid locales by typing the command:
-.sp
-.nf
- locale -a
-.fi
-.sp
-at the shell prompt.
-.sp
-.SS "Meta keys and locales"
-
-Beware that in most locales other than the default C locale, meta
-characters become printable, and they are then no longer considered to
-match \f3M-c\f1 style key bindings. This allows international
-characters to be entered with the compose key without unexpectedly
-triggering meta key bindings. You can still invoke meta bindings,
-since there are actually two ways to do this. For example the binding
-\f3M-c\f1 can also be invoked by pressing the escape key momentarily,
-then pressing the \f3c\f1 key, and this will work regardless of
-locale. Moreover, many modern terminal emulators, such as gnome's
-gnome-terminal's and KDE's konsole terminals, already generate escape
-pairs like this when you use the meta key, rather than a real meta
-character, and other emulators usually have a way to request this
-behavior, so you can continue to use the meta key on most systems.
-.sp
-For example, although xterm terminal emulators generate real 8-bit
-meta characters by default when you use the meta key, they can be
-configured to output the equivalent escape pair by setting their
-\f3EightBitInput\f1 X resource to \f3False\f1. You can either do this
-by placing a line like the following in your \f3~/.Xdefaults\f1 file,
-.sp
-.nf
- XTerm*EightBitInput: False
-.sp
-.fi
-or by starting an xterm with an \f3-xrm '*EightBitInput: False'\f1
-command-line argument. In recent versions of xterm you can toggle this
-feature on and off with the \f3"Meta Sends Escape"\f1 option in the
-menu that is displayed when you press the left mouse button and the
-control key within an xterm window. In CDE, dtterms can be similarly
-coerced to generate escape pairs in place of meta characters, by
-setting the \f3Dtterm*KshMode\f1 resource to \f3True\f1.
-.sp
-.SS "Entering international characters"
-
-If you don't have a keyboard that generates all of the international
-characters that you need, there is usually a compose key that will
-allow you to enter special characters, or a way to create one. For
-example, under X windows on unix-like systems, if your keyboard
-doesn't have a compose key, you can designate a redundant key to serve
-this purpose with the xmodmap command. For example, on many PC
-keyboards there is a microsoft-windows key, which is otherwise useless
-under Linux. On my PC the \f3xev\f1 program reports that pressing this
-key generates keycode 115, so to turn this key into a compose key, I
-do the following:
-.sp
-.nf
- xmodmap -e 'keycode 115 = Multi_key'
-.fi
-.sp
-I can then enter an i with a umlaut over it by typing this key,
-followed by \f3"\f1, followed by i.
-
-.SH THREAD SAFETY
-
-In a multi-threaded program, you should use the libtecla_r.a version
-of the library. This uses reentrant versions of system functions,
-where available. Unfortunately neither terminfo nor termcap were
-designed to be reentrant, so you can't safely use the functions of the
-getline module in multiple threads (you can use the separate
-file-expansion and word-completion modules in multiple threads, see
-the corresponding man pages for details). However due to the use of
-POSIX reentrant functions for looking up home directories etc, it is
-safe to use this module from a single thread of a multi-threaded
-program, provided that your other threads don't use any termcap or
-terminfo functions.
-
-.SH FILES
-.nf
-libtecla.a - The tecla library
-libtecla.h - The tecla header file.
-~/.teclarc - The personal tecla customization file.
-.fi
-
-.SH SEE ALSO
-libtecla(3), ef_expand_file(3), cpl_complete_word(3), pca_lookup_file(3)
-
-.SH AUTHOR
-Martin Shepherd (mcs@astro.caltech.edu)
diff --git a/libtecla-1.4.1/man3/gl_group_history.3 b/libtecla-1.4.1/man3/gl_group_history.3
deleted file mode 100644
index 6bd3d1f..0000000
--- a/libtecla-1.4.1/man3/gl_group_history.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/gl_get_line.3
diff --git a/libtecla-1.4.1/man3/gl_ignore_signal.3 b/libtecla-1.4.1/man3/gl_ignore_signal.3
deleted file mode 100644
index 6bd3d1f..0000000
--- a/libtecla-1.4.1/man3/gl_ignore_signal.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/gl_get_line.3
diff --git a/libtecla-1.4.1/man3/gl_last_signal.3 b/libtecla-1.4.1/man3/gl_last_signal.3
deleted file mode 100644
index 6bd3d1f..0000000
--- a/libtecla-1.4.1/man3/gl_last_signal.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/gl_get_line.3
diff --git a/libtecla-1.4.1/man3/gl_limit_history.3 b/libtecla-1.4.1/man3/gl_limit_history.3
deleted file mode 100644
index 6bd3d1f..0000000
--- a/libtecla-1.4.1/man3/gl_limit_history.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/gl_get_line.3
diff --git a/libtecla-1.4.1/man3/gl_load_history.3 b/libtecla-1.4.1/man3/gl_load_history.3
deleted file mode 100644
index 6bd3d1f..0000000
--- a/libtecla-1.4.1/man3/gl_load_history.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/gl_get_line.3
diff --git a/libtecla-1.4.1/man3/gl_lookup_history.3 b/libtecla-1.4.1/man3/gl_lookup_history.3
deleted file mode 100644
index 6bd3d1f..0000000
--- a/libtecla-1.4.1/man3/gl_lookup_history.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/gl_get_line.3
diff --git a/libtecla-1.4.1/man3/gl_prompt_style.3 b/libtecla-1.4.1/man3/gl_prompt_style.3
deleted file mode 100644
index 6bd3d1f..0000000
--- a/libtecla-1.4.1/man3/gl_prompt_style.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/gl_get_line.3
diff --git a/libtecla-1.4.1/man3/gl_range_of_history.3 b/libtecla-1.4.1/man3/gl_range_of_history.3
deleted file mode 100644
index 6bd3d1f..0000000
--- a/libtecla-1.4.1/man3/gl_range_of_history.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/gl_get_line.3
diff --git a/libtecla-1.4.1/man3/gl_resize_history.3 b/libtecla-1.4.1/man3/gl_resize_history.3
deleted file mode 100644
index 6bd3d1f..0000000
--- a/libtecla-1.4.1/man3/gl_resize_history.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/gl_get_line.3
diff --git a/libtecla-1.4.1/man3/gl_save_history.3 b/libtecla-1.4.1/man3/gl_save_history.3
deleted file mode 100644
index 6bd3d1f..0000000
--- a/libtecla-1.4.1/man3/gl_save_history.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/gl_get_line.3
diff --git a/libtecla-1.4.1/man3/gl_show_history.3 b/libtecla-1.4.1/man3/gl_show_history.3
deleted file mode 100644
index 6bd3d1f..0000000
--- a/libtecla-1.4.1/man3/gl_show_history.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/gl_get_line.3
diff --git a/libtecla-1.4.1/man3/gl_size_of_history.3 b/libtecla-1.4.1/man3/gl_size_of_history.3
deleted file mode 100644
index 6bd3d1f..0000000
--- a/libtecla-1.4.1/man3/gl_size_of_history.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/gl_get_line.3
diff --git a/libtecla-1.4.1/man3/gl_state_of_history.3 b/libtecla-1.4.1/man3/gl_state_of_history.3
deleted file mode 100644
index 6bd3d1f..0000000
--- a/libtecla-1.4.1/man3/gl_state_of_history.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/gl_get_line.3
diff --git a/libtecla-1.4.1/man3/gl_terminal_size.3 b/libtecla-1.4.1/man3/gl_terminal_size.3
deleted file mode 100644
index 6bd3d1f..0000000
--- a/libtecla-1.4.1/man3/gl_terminal_size.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/gl_get_line.3
diff --git a/libtecla-1.4.1/man3/gl_toggle_history.3 b/libtecla-1.4.1/man3/gl_toggle_history.3
deleted file mode 100644
index 6bd3d1f..0000000
--- a/libtecla-1.4.1/man3/gl_toggle_history.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/gl_get_line.3
diff --git a/libtecla-1.4.1/man3/gl_trap_signal.3 b/libtecla-1.4.1/man3/gl_trap_signal.3
deleted file mode 100644
index 6bd3d1f..0000000
--- a/libtecla-1.4.1/man3/gl_trap_signal.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/gl_get_line.3
diff --git a/libtecla-1.4.1/man3/gl_watch_fd.3 b/libtecla-1.4.1/man3/gl_watch_fd.3
deleted file mode 100644
index 6bd3d1f..0000000
--- a/libtecla-1.4.1/man3/gl_watch_fd.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/gl_get_line.3
diff --git a/libtecla-1.4.1/man3/libtecla_version.3 b/libtecla-1.4.1/man3/libtecla_version.3
deleted file mode 100644
index 2c9c2c7..0000000
--- a/libtecla-1.4.1/man3/libtecla_version.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/libtecla.3
diff --git a/libtecla-1.4.1/man3/new_CplFileConf.3 b/libtecla-1.4.1/man3/new_CplFileConf.3
deleted file mode 100644
index 36c83a3..0000000
--- a/libtecla-1.4.1/man3/new_CplFileConf.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/cpl_complete_word.3
diff --git a/libtecla-1.4.1/man3/new_ExpandFile.3 b/libtecla-1.4.1/man3/new_ExpandFile.3
deleted file mode 100644
index f4299df..0000000
--- a/libtecla-1.4.1/man3/new_ExpandFile.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/ef_expand_file.3
diff --git a/libtecla-1.4.1/man3/new_GetLine.3 b/libtecla-1.4.1/man3/new_GetLine.3
deleted file mode 100644
index 6bd3d1f..0000000
--- a/libtecla-1.4.1/man3/new_GetLine.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/gl_get_line.3
diff --git a/libtecla-1.4.1/man3/new_PathCache.3 b/libtecla-1.4.1/man3/new_PathCache.3
deleted file mode 100644
index e5a136e..0000000
--- a/libtecla-1.4.1/man3/new_PathCache.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/pca_lookup_file.3
diff --git a/libtecla-1.4.1/man3/new_PcaPathConf.3 b/libtecla-1.4.1/man3/new_PcaPathConf.3
deleted file mode 100644
index e5a136e..0000000
--- a/libtecla-1.4.1/man3/new_PcaPathConf.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/pca_lookup_file.3
diff --git a/libtecla-1.4.1/man3/new_WordCompletion.3 b/libtecla-1.4.1/man3/new_WordCompletion.3
deleted file mode 100644
index 36c83a3..0000000
--- a/libtecla-1.4.1/man3/new_WordCompletion.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/cpl_complete_word.3
diff --git a/libtecla-1.4.1/man3/pca_last_error.3 b/libtecla-1.4.1/man3/pca_last_error.3
deleted file mode 100644
index e5a136e..0000000
--- a/libtecla-1.4.1/man3/pca_last_error.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/pca_lookup_file.3
diff --git a/libtecla-1.4.1/man3/pca_path_completions.3 b/libtecla-1.4.1/man3/pca_path_completions.3
deleted file mode 100644
index e5a136e..0000000
--- a/libtecla-1.4.1/man3/pca_path_completions.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/pca_lookup_file.3
diff --git a/libtecla-1.4.1/man3/pca_scan_path.3 b/libtecla-1.4.1/man3/pca_scan_path.3
deleted file mode 100644
index e5a136e..0000000
--- a/libtecla-1.4.1/man3/pca_scan_path.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/pca_lookup_file.3
diff --git a/libtecla-1.4.1/man3/pca_set_check_fn.3 b/libtecla-1.4.1/man3/pca_set_check_fn.3
deleted file mode 100644
index e5a136e..0000000
--- a/libtecla-1.4.1/man3/pca_set_check_fn.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/pca_lookup_file.3
diff --git a/libtecla-1.4.1/man3/ppc_file_start.3 b/libtecla-1.4.1/man3/ppc_file_start.3
deleted file mode 100644
index e5a136e..0000000
--- a/libtecla-1.4.1/man3/ppc_file_start.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/pca_lookup_file.3
diff --git a/libtecla-1.4.1/man3/ppc_literal_escapes.3 b/libtecla-1.4.1/man3/ppc_literal_escapes.3
deleted file mode 100644
index e5a136e..0000000
--- a/libtecla-1.4.1/man3/ppc_literal_escapes.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/pca_lookup_file.3
diff --git a/libtecla-1.4.1/update_html b/libtecla-1.4.1/update_html
deleted file mode 100755
index 35625a7..0000000
--- a/libtecla-1.4.1/update_html
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/bin/sh
-
-# Convert man pages to html files.
-
-cd man3
-for page in *.3;do
- if [ "`wc -l $page | awk '{print $1}'`" -gt 1 ]; then
- html="../html/`echo $page | sed -e 's/.3$/.html/'`"
- man2html $page > $html
- for ref in "libtecla(3)" "cpl_complete_word(3)" "ef_expand_file(3)" "gl_get_line(3)" "pca_lookup_file(3)" "enhance(3)"; do
- link="`echo $ref | sed 's/(3)/.html/'`"
- ed -s $html << EOF
- 1,\$s|$ref|<a href="$link">&</a>|g
- w
- q
-EOF
- done
- fi
-done
-
-# Convert the change log into a web page.
-
-cd ../html
-echo '<HEAD><TITLE>The tecla library change log</TITLE></HEAD>' > changes.html
-echo '<BODY bgcolor=add8e6><PRE>' >> changes.html
-cat ../CHANGES >> changes.html
-echo '</PRE></BODY>' >> changes.html
-
-# Do the same to the release-notes file.
-
-cd ../html
-echo '<HEAD><TITLE>The tecla library release notes</TITLE></HEAD>' > release.html
-echo '<BODY bgcolor=add8e6><PRE>' >> release.html
-cat ../RELEASE.NOTES >> release.html
-echo '</PRE></BODY>' >> release.html
diff --git a/libtecla-1.4.1/CHANGES b/libtecla-1.6.1/CHANGES
index 45073e0..b02c224 100644
--- a/libtecla-1.4.1/CHANGES
+++ b/libtecla-1.6.1/CHANGES
@@ -2,6 +2,1257 @@ In the following log, modification dates are listed using the European
convention in which the day comes before the month (ie. DD/MM/YYYY).
The most recent modifications are listed first.
+31/10/2004 mcs@astro.caltech.edu (problem reported by Godfrey van der Linden)
+ getline.c
+ The gl_event_handler() function had the endif of a
+ conditional compilation clause in the wrong place. This
+ only upset the compiler on unusual systems that don't
+ have select(). The problem was seen under Mac OS X, due
+ to the configuration problem in 1.6.0 that caused the
+ configure script to mistakenly report that select wasn't
+ available.
+
+31/10/2004 mcs@astro.caltech.edu (info provided by Ivan Rayner)
+ configure.in configure Makefile.in
+ Ivan reported that under IRIX 6.5 it is necessary to add
+ -D_XOPEN_SOURCE=500 to the compiler flags, when compiling
+ the reentrant version of the library. Thus, whereas
+ previously I hardwired the value of DEFINES_R in
+ Makefile.in, I have now made this a variable in the
+ configure script, which is augmented with the above
+ addition, within an IRIX-specific switch clause.
+
+ Also apparently configure leaves the RANLIB variable
+ blank, instead of setting it to ":", so I have now
+ explicitly set this to ":", within the new IRIX clause of
+ the configure script.
+
+31/10/2004 mcs@astro.caltech.edu (info provided by Ivan Rayner)
+ getline.c
+ Under IRIX, the compiler warned that gl_read_unmasked()
+ was returning an int, which was then being assigned to an
+ enumeration type. This is techically fine, but it
+ highlighted the fact that I had meant to declare
+ gl_read_unmasked() to directly return the enumerated
+ type. I have now done so.
+
+26/09/2004 mcs@astro.caltech.edu
+ getline.c
+ Users can now turn off interactive command-line editing
+ by setting the TERM environment variable to the word "dumb".
+
+18/07/2004 mcs@astro.caltech.edu (problem noted by Michael MacFaden)
+ getline.c
+ Calling gl_terminal_size() on a system without support
+ for SIGWINCH caused a divide-by-zero error in an unintended
+ call to gl_erase_line(), because gl_update_size() was
+ incorrectly being called to query the terminal size,
+ instead of gl_query_size().
+
+18/07/2004 Padraig Brady (documented here by mcs@astro.caltech.edu)
+ getline.c
+ The suspend and termination signal-handlers installed by
+ gl_tty_signals(), were being installed swapped.
+
+03/06/2004 Mike Meaney (documented here by mcs@astro.caltech.edu)
+ getline.c
+ Mike pointed out the fact that the curses setupterm()
+ function is actually documented to exit the application
+ if an error occurs while its optional errret argument is
+ NULL. I hadn't noticed this, and because I didn't need
+ the extra information returned in the errret argument, I
+ was passing it a NULL. As suggested by Mike, I now pass
+ this argument a pointer to a dummy errret variable.
+
+23/05/2004 mcs@astro.caltech.edu (problem noted by John Beck)
+ man/func/cpl_complete_word.in
+ Some of the prototypes of functions and types documented
+ by the cpl_complete_word man page, weren't listed in the
+ Synopsis section of this man page. They are now listed
+ there.
+
+23/05/2004 mcs@astro.caltech.edu
+ getline.c man/func/gl_get_line.in
+ I have now added support for calling gl_normal_io() from
+ any callback functions that the application installs by
+ calling either gl_inactivity_timeout(), or gl_watch_fd().
+ Previously, if one of these callback functions called
+ gl_normal_io(), then after returning to gl_get_line(),
+ gl_get_line() would incorrectly assume that the terminal
+ was still in raw I/O mode. Now, gl_get_line() checks to
+ see if gl_normal_io() was called by the callback, and
+ if so, calls _gl_raw_io() to reinstate raw I/O mode.
+
+21/05/2004 mcs@astro.caltech.edu
+ configure.in configure
+ On Mac OS X the code that the configure script used to
+ check for select() failed due to missing symbols in
+ sys/select.h. Moving the inclusion of sys/select.h to
+ after the inclusion of sys/time.h, sys/types.h and
+ sys/unistd.h fixed this.
+
+11/05/2004 mcs@astro.caltech.edu
+ getline.c man/func/gl_get_line.in
+ If the line buffer returned by one call to gl_get_line()
+ was passed as the start_line argument of the next call to
+ gl_get_line(), then instead of the just-entered line
+ being presented back to the user for further editing, the
+ start_line argument was effectively ignored, because the
+ line buffer whose pointer was being passed back, was
+ being cleared before the start_line pointer was examined.
+ This appears to have been a case of me incorrectly
+ thinking that I had forgotten to initialize gl->line[]
+ and gl->ntotal in the gl_reset_input_line() function, and
+ then "fixing" this supposed omission. Removing this
+ erroneous fix, restored things to how they were meant to
+ be. To make it unlikely that I will make the same mistake
+ again, I have renamed the function from
+ gl_reset_input_line() to gl_reset_editor(), to stop it
+ looking as though it is meant to reset the contents of
+ the input line (that is what gl_truncate_buffer() is
+ for), explicitly stated that it doesn't clear the input
+ line, in the header comments of the function, and added a
+ prominent warning comment in the body of the function.
+
+ Also, since support for passing back the returned line
+ pointer via the start_line argument of the next call to
+ gl_get_line(), wasn't documented in the man page, but was
+ meant to be supported, and definitely used to work, I
+ have now amended the man page documentation of
+ gl_get_line() to explicitly state that this feature is
+ officially supported.
+
+2?/04/2004 Released 1.6.0
+
+22/04/2004 mcs@astro.caltech.edu (Fixed a bug reported by John Beck)
+ getline.c
+ When an error, signal, or other abnormal event aborted
+ gl_get_line(), the cleanup code that restored the
+ terminal to a sane state, also overwrote the value of
+ errno that was associated with the aborting event. An
+ I/O error occurring in the cleanup code would have also
+ overwritten the value to be returned by
+ gl_return_status(), and thus remove any possibility of
+ the caller finding out what really caused gl_get_line()
+ to abort. I have now written a new internal function
+ called, gl_record_status(), which records the completion
+ status to be returned by gl_return_status(), and the
+ value to assign to errno just before gl_get_line()
+ returns. This is called wherever code detects conditions
+ that require gl_get_line() to return early. The function
+ ensures that once an abnormal completion status has been
+ recorded for return, subsequent completions statuses
+ aren't recorded. This ensures that the caller sees the
+ original cause of the abnormal return, rather than any
+ error that occurs during cleaning up from this before
+ return.
+
+17/04/2004 mcs@astro.caltech.edu
+ getline.c
+ If an application's callback called gl_read_char() after
+ calling gl_normal_io(), it would inappropriately
+ redisplay the input line, when it called _gl_raw_io() to
+ temporarily switch the terminal back into raw mode.
+
+ To fix this, _gl_raw_io() now takes a new 'redisplay'
+ argument, which specifies whether or not to queue a
+ redisplay of the input line. I also created a new
+ gl->postpone flag, which is set by gl_normal_io(), and
+ cleared by _gl_raw_io() (when its redisplay argument is
+ true). When this flag is set, gl_flush_output() ignores
+ queued redisplays, as it generally should between calls
+ to gl_normal_io() and gl_raw_io(). Thus its effect is to
+ postpone redisplays while line editing is suspended.
+
+11/04/2004 mcs@astro.caltech.edu
+ history.c man/misc/tecla.in
+ History searches can now include the globbing operators
+ *, ?, []. When a search prefix is found to have at least
+ one of these characters, then only history lines that
+ completely match that pattern are returned.
+
+11/04/2004 mcs@astro.caltech.edu (issue raised by Mark Coiley)
+ getline.c ioutil.c
+ There appears to be a bug in Solaris's terminal I/O.
+ When the terminal file descriptor is placed in
+ non-blocking I/O mode, and the terminal is switched from
+ canonical to raw mode, characters that were previously
+ entered in canonical I/O mode don't become available to
+ be read until the user types one character more. Select()
+ incorrectly says that there are no characters available,
+ and read() returns EAGAIN. This is only a problem for
+ gl_get_line() when gl_get_line() is in non-blocking
+ server I/O mode, so most users won't have experienced any
+ problems with this.
+
+ The only way that I have found to get read() to return
+ the characters, without the user first having to type
+ another character, is to turn off non-blocking I/O before
+ calling read(). Select() still claims that there are no
+ characters available to be read, but read happily returns
+ them anyway. Fortunately, one can perform non-blocking
+ terminal reads without setting the non-blocking I/O flag
+ of the file descriptor, simply by setting the VTIME
+ terminal attribute to zero (which I already was
+ doing). Thus, when in non-blocking server I/O, I now turn
+ off the non-blocking I/O flag, attempt to read one
+ character and only if this fails, do I then call the
+ select() based event handler to implement any configured
+ non-zero timeout, before attempting the read again. Of
+ course the non-blocking I/O flag is still needed for
+ writing, so I only turn it off temporarily while reading.
+
+25/03/2004 mcs@astro.caltech.edu (bug reported by Gregory Harris)
+ Makefile.in
+ It appears that when in February, I patched Makefile.in
+ to add abolute paths to the install-sh shell-script,
+ I accidentally replaced install-sh with install.sh. I
+ corrected the name in the Makefile.
+
+25/03/2004 Gregory Harris (documented here by mcs)
+ configure.in configure
+ Greg added the configuration parameters needed to build
+ the shared version of the libtecla library under FreeBSD.
+
+25/03/2004 mcs@astro.caltech.edu
+ getline.c libtecla.h libtecla.map man/func/gl_get_line.in
+ man/func/gl_read_char.in
+ I wrote a public function called gl_read_char(). Unlike
+ gl_query_char(), this function neither prompts the user
+ for input, nor displays the character that was entered.
+ In fact it doesn't write anything to the terminal, and
+ takes pains not to disturb any incompletely entered
+ input line, and can safely be called from application
+ callback functions.
+
+21/03/2004 mcs@astro.caltech.edu
+ getline.c libtecla.h libtecla.map man/func/gl_get_line.in
+ man/func/gl_query_char.in
+ I wrote a public function called gl_query_char(), which
+ prompts the user and awaits a single-character reply,
+ without the user having to hit return.
+
+23/02/2004 mcs@astro.caltech.edu (bug reported by Gregory Harris)
+ configure.in configure getline.c enhance.c demo3.c
+ The configure script now checks for the sys/select.h
+ header file, and arranges for a C macro called
+ HAVE_SYS_SELECT_H to be set if it exists. Thus the files
+ that use select() now use this macro to conditionally
+ include sys/select.h where available. Apparently this
+ header is required under FreeBSD 5.1.
+
+23/02/2004 mcs@astro.caltech.edu
+ getline.c libtecla.h man/func/gl_get_line.in
+ I wrote two new public functions, gl_append_history() and
+ gl_automatic_history(). Together these allow the
+ application to take over the responsibility of adding
+ lines to the history list from gl_get_line(). I then
+ documented their functionality in the gl_get_line man
+ page.
+ Version 1.6.0
+ I incremented the minor version number of the library, to
+ comply with the requirement to do so when additions are
+ made to the public interface. See libtecla.map for
+ details.
+ libtecla.map
+ I added a new 1.6.0 group for the new minor version, and
+ added the above pair of functions to it.
+
+15/02/2004 mcs@astro.caltech.edu (fixes a bug reported by Satya Sahoo)
+ history.c
+ Calling gl_load_history() multiple times, eventually led
+ to a segmentation fault. This was due to the head of the
+ list of unused history string segments not getting
+ reset when the history buffer was cleared. While
+ debugging this problem I also noticed that the history
+ resizing function was way too complicated to verify, so
+ after fixing the above bug, I heavily simplified the
+ history resizing function, trading off a small reduction
+ in memory efficiency, for greatly improved clarity, and
+ thus made it much more verifiable and maintainable.
+
+14/02/2004 mcs@astro.caltech.edu (fixes a bug reported by Tim Burress).
+ getline.c
+ If gl_change_terminal() was first used to tell
+ gl_get_line to read input from a file, then called later
+ to tell it to read subsequent input from a terminal, no
+ prompt would be displayed for the first line of
+ interactive input. The problem was that on reaching the
+ end of the input file, gl_get_line() should have called
+ gl_abandon_line(), to tell the next call to gl_get_line()
+ to start inputting a new line from scratch. I have added
+ this now.
+
+14/02/2004 Krister Walfridsson (documented here by mcs@astro.caltech.edu)
+ Makefile.in
+ Krister noticed that I had failed to put $(srcdir)/ in front
+ of some invokations of install.sh. I have remedied this.
+ config.guess config.sub
+ I hadn't updated these for a long time, so apparently they
+ didn't recognise the BSD system that Krister was using.
+ I have now updated them to the versions that come with
+ autoconf-2.59.
+
+22/01/2004 mcs@astro.caltech.edu
+ keytab.c
+ When parsing key-binding specifications, backslash escaped
+ characters following ^ characters were not being expanded.
+ Thus ^\\ got interpretted as a control-\ character followed
+ by a \ character, rather than simply as a control-\
+ character.
+
+12/01/2004 mcs@astro.caltech.edu
+ cplfile.c cplmatch.c demo2.c demo3.c demo.c direader.c
+ expand.c getline.c history.c homedir.c pathutil.c pcache.c
+ configure.in configure INSTALL
+ The configuration script now takes a
+ "--without-file-system" argument. This is primarily for
+ intended for embedded systems that either don't have
+ filesystems, or where the file-system code in libtecla is
+ unwanted bloat. It sets the WITHOUT_FILE_SYSTEM
+ macro. This removes all code related to filesystem
+ access, including the entire public file-expansion,
+ file-completion and path-lookup facilities. Note that the
+ general word completion facility is still included, but
+ without the normally bundled file completion
+ callback. Actually the callback is still there, but it
+ reports no completions, regardless of what string you ask
+ it to complete.
+
+ This option is described in the INSTALL document.
+
+12/01/2004 mcs@astro.caltech.edu
+ getline.c configure.in configure INSTALL
+ The configuration script now takes a
+ "--without-file-actions" argument. This allows an
+ application author/installer to prevent users of
+ gl_get_line() from accessing the filesystem from the
+ builtin actions of gl_get_line(). It defines a macro
+ called HIDE_FILE_SYSTEM. This causes the
+ "expand-filename", "read-from-file", "read-init-files",
+ and "list-glob" action functions to be completely
+ removed. It also changes the default behavior of actions
+ such as "complete-word" and "list-or-eof" to show no
+ completions, instead of the normal default of showing
+ filename completions.
+
+ This option is described in the INSTALL document.
+
+11/01/2004 mcs@astro.caltech.edu
+ getline.c man/func/gl_get_line.in
+ In case an application's customized completion handler
+ needs to write to the terminal for some unforseen reason,
+ there needs to be a way for the it to cleanly suspend raw
+ line editing, before writing to the terminal, and the
+ caller then needs to be aware that it may need to
+ resurrect the input line when the callback returns. I
+ have now arranged that the completion callback functions
+ can call the gl_normal_io() function for this purpose,
+ and documented this in the gl_get_line() man page.
+
+11/01/2004 mcs@astro.caltech.edu (In response to a bug report by Satya Sahoo)
+ getline.c
+ The gl_configure_getline() function makes a malloc'd copy
+ of the names of the configuration files that it is asked
+ to read. Before the bug fix, if the application made one
+ or more calls to this function, the memory allocated by
+ the final call that it made before calling del_GetLine(),
+ wasn't being freed. Note that memory allocated in all but
+ the final call was being correctly freed, so the maximum
+ extent of the memory leak was the length of the file
+ name(s) passed in the final call to
+ gl_configure_getline(), and an application that didn't
+ call gl_configure_getline() didn't suffer any leak.
+
+20/12/2003 mcs@astro.caltech.edu
+ history.c
+ Ellen tested the history fix that I reported below, and
+ pointed out that it still had a problem. This turned out
+ to be because getline.c was making some incorrect
+ assumptions about the new behavior of history.c. This
+ problem and the previous one both revolved around how
+ search prefixes were stored and discarded, so I have now
+ re-written this part of the code. Previously the search
+ prefix was retained by looking for a line with that
+ prefix, and keeping a pointer to that line. This saved
+ memory, compared to storing a separate copy of the
+ prefix, but it led to all kinds of hairy
+ interdependencies, so I have now changed the code to keep
+ a separate copy of search prefixes. To keep the memory
+ requirements constant, the search prefix is stored in the
+ history buffer, like normal history lines, but not
+ referenced by the time-ordered history list. The prefix
+ can now be kept around indefinitely, until a new search
+ prefix is specified, regardless of changes to the
+ archived lines in the history buffer. This is actually
+ necessary to make the vi-mode re-search actions work
+ correctly. In particular, I no longer discard the search
+ prefix whenever a history search session ends. Also,
+ rather than have getline.c keep its own record of when a
+ history session is in progress, it now consults
+ history.c, so that failed assumptions can't cause the
+ kind of discrepancy that occurred before. For this to
+ work, getline.c now explicitly tells history.c to cancel
+ search sessions whenever it executes any non-history
+ action.
+
+14/12/2003 mcs@astro.caltech.edu (bug reported by Ellen Oschmann)
+ history.c
+ If one searched backwards for a prefix, then returned to
+ the original line, changed that line, then started
+ another backwards prefix search, getline incorrectly
+ discarded the new search prefix in the process of
+ throwing away its cached copy of the previous pre-search
+ input line. In other words getline was belatedly
+ cancelling a previous search, after a new search had
+ already partially begun, and thus messed up the new
+ search. The obvious fix was to arrange for the current
+ search to be cancelled whenever the history pointer
+ returns to its starting point, rather than waiting for
+ the next search to begin from there.
+
+14/12/2003 mcs@astro.caltech.edu
+ history.c
+ _glh_recall_line() was returning the last line in the
+ history buffer instead of the line requested by the
+ caller. This only affected the obscure "repeat-history"
+ action-function, which probably isn't used by anybody.
+
+09/12/2003 Version 1.5.0 released.
+
+28/09/2003 mcs@astro.caltech.edu
+ homedir.c
+ When the home directory of the login user is requested,
+ see if the HOME environment variable exists, and if so
+ return its value, rather than looking up the user's home
+ directory in the password file. This seems to be the
+ convention adopted by other unix programs that perform
+ tilde expansion, and it works around a strange problem,
+ where a third-party libtecla program, statically compiled
+ under an old version of RedHat, unexpectedly complained
+ that getpwd() returned an error when the program was run
+ under RedHat 9.
+
+01/09/2003 mcs@astro.caltech.edu
+ getline.c libtecla.h libtecla.map man/func/gl_get_line.in
+ man/func/gl_register_action.in.
+ It is now possible for an application to register
+ external functions as action functions. These actions are
+ initially bound to specified key-sequences, but if they
+ are registered before the user's configuration file is
+ loaded, they can also be re-bound by the user to
+ different key-sequences. The function used to register a
+ new action, is called gl_register_action(). Action
+ functions are passed a readonly copy of the input line
+ and the cursor position. They can display text to the
+ terminal, or perform other operations on the application
+ environment. Currently, they can't edit the input line or
+ move the cursor. This will require the future addition of
+ functions to queue the invokation of the built-in action
+ functions.
+
+26/08/2003 mcs@astro.caltech.edu
+ getline.c
+ I modified gl_update_buffer() to ensure that the cursor
+ stays within the input line after external line
+ modifications, and to queue a redisplay of the
+ potentially modified input line.
+
+21/07/2003 mcs@astro.caltech.edu
+ configure.in configure Makefile.in Makefile.stub INSTALL
+ By specifying --without-man-pages or --with-man-pages=no
+ as command-line arguments to the configure script, it is
+ now possible to have the configure script skip the
+ man-page preprocessing step, and arrange for the man-page
+ installation targets in the Makefile to do nothing. This
+ option is designed for people who embed libtecla within
+ other packages. It is also used by Makefile.stub when
+ the distclean target is specified.
+
+21/07/2003 mcs@astro.caltech.edu
+ configure.in configure
+ The previous workaround for recent versions of gcc
+ placing /usr/local/include at the start of the system
+ inlcude-file search path, broke something else. The fix
+ placed /usr/include before gcc's include area, which
+ meant that gcc's modified version of stdarg.h was being
+ ignored in deference to the version in /usr/include. I
+ have changed the fix to have gcc report the search path,
+ then have awk add options to CFLAGS to reorder this path,
+ plaing /usr/local/include at the end.
+
+ Also, under Solaris 9, including term.h without first
+ including curses.h results in complaints about undefined
+ symbols, such as bool. As a result the configure script's
+ test for term.h was failing. I have now modified it to
+ include curses.h in the test code that it uses to check
+ for term.h. In the process I also improved the tests for
+ curses.h and term.h to prevent an ncurses version of
+ term.h from being used with the system-default version of
+ curses.h.
+
+29/06/2003 mcs@astro.caltech.edu
+ Makefile.in direader.c homedir.c
+ On some systems (eg. linux) the _POSIX_C_SOURCE
+ feature-test macro is set by system headers, rather than
+ being an option set by a project's Makefile at
+ compilation time. In software, such as tecla, where the
+ definition of this macro is used as an indication of
+ whether to use the non-reentrant or reentrant versions of
+ system functions, this means that the reentrant functions
+ are always used, regardless of whether this macro is set
+ or not by the project Makefile. Thus, on such systems the
+ reentrant and non-reentrant versions of the tecla library
+ are essentially identical. This has a couple of
+ drawbacks. First, since thread-safe functions for
+ traversing the password file don't exist, the supposedly
+ non-reentrant version of the tecla library can't support
+ ambiguous tab-completion of usernames in ~username/
+ constructions. Secondly, on some systems the use of
+ reentrant system functions dictates the use of a shared
+ library that isn't needed for the non-reentrant
+ functions, thus making it more difficult to distribute
+ binary versions of the library.
+
+ To remedy this situation I have modified the DEFINES_R
+ variable in Makefile.in to arrange for the compiler to
+ define a C macro called PREFER_REENTRANT when it is
+ compiling the reentrant version of the tecla library.
+ This macro is now used in the source code to determine
+ when to require reentrant code. Whithin the source code,
+ wherever a potentially non-reentrant interface is used,
+ the existance of both this macro and a suitably valued
+ _POSIX_C_SOURCE macro, are tested for to see if a
+ reentrant alternative to the problem code should be used.
+
+22/06/2003 mcs@astro.caltech.edu
+ getline.c
+ I changed the way that redisplays are requested and
+ performed. Redisplays are now queued by calling
+ gl_queue_redisplay(), and subsequently performed by
+ gl_flush_output(), when the queue of already pending
+ output has been completely dispatched. This was necessary
+ to prevent event handlers from filling up the output
+ queue with redisplays, and it also simplifies a number of
+ things. In the process I removed the gl_queue_display()
+ function. I also wrote a gl_line_erased() function, which
+ is now called by all functions that erase the input
+ line. I also split the gl_abandon_line() function into
+ public and private callable parts, and used the private
+ version internally to arrange to discard the input line
+ after errors.
+
+ The raw_mode flag was not being initialized by new_GetLine().
+ It is now initialized to zero.
+
+ I removed the zapline flag, since using the endline flag to
+ communicate the desire to terminate the line, did the same
+ thing.
+
+ gl_terminal_move_cursor() now does nothing when the input
+ line isn't displayed.
+
+18/03/2003 mcs@astro.caltech.edu
+ getline.c
+ Fixed bug which was causing newlines not to be output
+ at the end of each newly entered line. I was
+ interpreting the gl->endline flag in conflicting ways in
+ two places. To fix this I have created a gl->displayed
+ flag. This flags whether an input line is currently
+ displayed.
+
+17/03/2003 mcs@astro.caltech.edu
+ getline.c libtecla.h man/func/gl_get_line.in
+ man/func/gl_erase_terminal.in libtecla.map
+ I added a new function that programs can call to clear
+ the terminal between calls to gl_get_line().
+
+11/03/2003 mcs@astro.caltech.edu
+ configure.in configure
+ Under linux when _POSIX_C_SOURCE is defined, getpwent()
+ and associated functions become undefined, because
+ _SVID_SOURCE and _BSD_SOURCE become undefined. Adding
+ these feature macros back to CFLAGS resolves this.
+
+06/03/2003 mcs@astro.caltech.edu
+ getline.c libtecla.map man/func/gl_get_line.in
+ Following the lead of Edward Chien, I wrote a function
+ called gl_bind_keyseq(), which binds a specified
+ key-sequence to a given action, or unbinds the
+ key-sequence.
+
+24/02/2003 mcs@astro.caltech.edu
+ getline.c libtecla.map man/func/cpl_complete_word.in
+ I implemented a simple function called
+ cpl_recall_matches(). This recalls the return value of
+ the last call to cpl_complete_word().
+
+19/01/2003 mcs@astro.caltech.edu
+ getline.c
+ The documented signal handling, fd event-handling,
+ inactivity timeout handling, and server-mode non-blocking
+ I/O features are now implemented for non-interactive
+ input streams, such as pipes and files.
+
+19/01/2003 mcs@astro.caltech.edu
+ getline.c libtecla.h man/func/gl_get_line.in demo3.c
+ I added a new return status enumerator to report
+ when an end-of-file condition causes gl_get_line()
+ to return NULL.
+
+13/01/2003 mcs@astro.caltech.edu
+ history.c
+ I rewrote the history facility. The previous
+ circular buffer implementation was a nightmare to change,
+ and it couldn't efficiently support certain newly
+ requested features. The new implementation stores history
+ lines in linked lists of fixed sized string segments,
+ taken from the buffer, with each line being reference
+ counted and recorded in a hash table. If the user enters
+ a line multiple times, only one copy of the line is now
+ stored. Not only does this make better use of the
+ available buffer space, but it also makes it easy to
+ ensure that a line whose prefix matches the current
+ search prefix, isn't returned more than once in sequence,
+ since we can simply see if the latest search result has
+ the same hash-table pointer as the previous one, rather
+ than having to compare strings. Another plus is that due
+ to the use of linked lists of nodes of fixed size line
+ segments, there is no longer any need to continually
+ shuffle the contents of the buffer in order to defragment
+ it. As far as the user is concerned, the visible
+ differences are as follows:
+
+ 1. If the user enters a given line multiple times in a
+ row, each one will be recorded in the history list,
+ and will thus be listed by gl_show_history(), and
+ saved in the history file. Previously only one line
+ was recorded when consecutive duplicates were entered.
+ This was a kludge to prevent history recall from
+ recalling the same line multiple times in a row. This
+ only achieved the desired result when not recalling by
+ prefix.
+
+ 2. Not only simple recall, but prefix-based history line
+ recalls now don't return the same line multiple times
+ in a row. As mentioned in (1) above, previously this
+ only worked when performing a simple recall, without a
+ search prefix.
+
+28/12/2002 mcs@astro.caltech.edu
+ getline.c
+ The one-line function, gl_buff_curpos_to_term_curpos()
+ was only being used by gl_place_cursor(), so I inlined it
+ in that function, and removed it.
+
+28/12/2002 mcs@astro.caltech.edu
+ getline.c
+ gl_suspend_process() was calling the application-level
+ gl_normal_io() and gl_raw_io() functions, where it should
+ have been calling the internal versions _gl_normal_io()
+ and _gl_raw_io().
+ Also gl_handle_signal() was masking and unmasking just
+ the signals of the first element of the gl[] array
+ argument. It now masks and unmasks all trappable signals.
+
+28/12/2002 mcs@astro.caltech.edu
+ getline.c
+ Now that the number of terminal characters used to
+ display the current input line, is recorded, the relative
+ line on which the last character of the input line
+ resides can be determined without having to call
+ gl_buff_curpos_to_term_curpos(). This is now used by
+ gl_normal_io() via gl_start_newline(), so there is now no
+ need for gl_buff_curpos_to_term_curpos() to be
+ async-signal safe. I have thus removed the annoying
+ gl->cwidth[] array, and gl_buff_curpos_to_term_curpos()
+ now calls gl_width_of_char() directly again. There is
+ also now no need for the gl_line_of_char_start() and
+ gl_line_of_char_end() functions, so I have removed them.
+
+28/12/2002 mcs@astro.caltech.edu
+ getline.c
+ Unfortunately it turns out that the terminfo/termcap
+ control sequence which is defined to delete everything
+ from the current position to the end of the terminal, is
+ only defined to work when at the start of a terminal
+ line. In gnome terminals in RedHat 8.0, if it is used
+ within a terminal line, it erases the whole terminal
+ line, rather than just what follows the cursor. Thus to
+ portably truncate the displayed input line it is
+ necessary to first use the control sequence which deletes
+ from the cursor position to the end of the line, then if
+ there are more terminal lines, move to the start of the
+ next line, and use the delete to end-of-terminal control
+ sequence, then restore the cursor position. This requires
+ that one know how many physical terminal lines are used
+ by the current input line, so I now keep a record of the
+ number of characters so far displayed to the terminal
+ following the start of the prompt, and the new
+ gl_truncate_display() function uses this information to
+ truncate the displayed input line from the current cursor
+ position.
+
+28/12/2002 mcs@astro.caltech.edu
+ getline.c
+ gl_start_newline() now moves to an empty line following
+ the input line, rather than just to the next line. It
+ also arranges for the input line to be redisplayed before
+ editing resumes. A major user of this is gl_print_info(),
+ which now need not be followed by an explicit call to
+ gl_redisplay(), since the terminal input loop in
+ gl_get_input_line() ensures that gl_redisplay() is called
+ after any action function that asserts gl->redisplay.
+ Also, all functions that erase the displayed input line
+ can now call the gl_erase_line() function, which is
+ designed to work correctly even when a terminal resize
+ invalidates the horizontal cursor position. Finally, the
+ new gl_queue_display() function is now used by functions
+ that need to arrange for the input line to be displayed
+ from scratch after the displayed line has been erased or
+ invalidated by other text being written to the terminal.
+ All of these changes are aimed at reducing the number of
+ places that directly modify gl->term_curpos and
+ gl->redisplay.
+
+22/12/2002 Markus Gyger (logged here by mcs)
+ Makefile.in update_html
+ In places where echo and sed were being used to extract
+ the base names of files, Markus substituted the basename
+ command. He also replaced explicit cp and chmod commands
+ with invokations of the install-sh script.
+ configure.in
+ Use $target_os and $target_cpu, where appropriate,
+ instead of $target.
+ configure.in
+ The Solaris man function and library man pages should
+ be in sections 3lib and 3tecla respectively, only in
+ Solaris version 2.8 and above.
+ configure.in
+ Markus provided values for the man page configuration
+ variables for HPUX.
+ man/*/*.in
+ I had missed parameterizing man page section numbers in
+ the man page titles, Markus corrected this.
+ man/func/libtecla_version.in
+ Fixed incorrect section number in the link to the
+ libtecla man page.
+ homedir.c
+ When compiled to be reentrant, although one can't use the
+ non-reentrant getpwent() function to scan the password
+ file for username completions, one can at least see if
+ the prefix being completed is a valid username, and if
+ the username of the current user minimally matches the
+ prefix, and if so list them. I simplified Markus'
+ modification by adding a prefix argument to the
+ _hd_scan_user_home_dirs() function, and redefining the
+ function description accordingly, such that now it
+ reports only those password file entries who's usernames
+ minimally match the specified prefix. Without this, it
+ would have been necessary to peak inside the private data
+ argument passed in by cf_complete_username().
+ Markus also provided code which under Solaris uses the
+ non-reentrant interfaces if the reentrant version of the
+ library isn't linked with the threads library.
+
+19/12/2002 mcs@astro.caltech.edu
+ Makefile.in
+ Markus pointed out that LDFLAGS was being picked up by
+ the configure script, but not then being interpolated
+ into te Makefile. I have thus added the necessary
+ assignment to Makefile.in and arranged for the value of
+ LDFLAGS to be passed on to recursive make's. I also did
+ the same for CPPFLAGS, which had also been omitted.
+
+18/12/2002 mcs@astro.caltech.edu
+ man/* man/*/* configure.in configure Makefile.in
+ update_html
+ It turns out that the assignment of man page sections to
+ topics differs somewhat from system to system, so this is
+ another thing that needs to be configured by the main
+ configuration script, rather than being hardwired. All
+ man pages have now been moved into suitably named
+ topic-specific sub-directories of the top-level man
+ directory, and instead of having a numeric suffix, now
+ have the .in suffix, since they are now preprocessed by
+ the configure script, in the same fashion as Makefile.in.
+ Whithin these *.in versions of the man pages, and within
+ Makefile.in, the installation subdirectory (eg. man1) and
+ the file-name suffix (eg. 1), are written using
+ configuration macros, so that they get expanded to the
+ appropriate tokens when the configure script is run. In
+ principle, the man pages could also take advantage of
+ other configuration macros, such as the one which expands
+ to the library installation directory, to include full
+ path names to installed files in the documentation, so in
+ the future this feature could have more uses than just
+ that of parameterizing man page sections.
+
+18/12/2002 mcs@astro.caltech.edu
+ man3 man3/* Makefile.in html/index.html update_html
+ Markus suggested splitting the gl_get_line(3) man page
+ into user and developer sections, and also pointed out
+ that the enhance man page should be in section 1, not
+ section 3. I have thus created a top-level man
+ directory in which to place the various sections, and
+ moved the man3 directory into it. The enhance.3 man page
+ is now in man/man1/enhance.1. I have extracted all
+ user-oriented sections from the gl_get_line(3) man page
+ and placed them in a new man7/tecla.7 man page.
+
+18/12/2002 mcs@astro.caltech.edu
+ getline.c
+ Terminal resizing was broken in normal mode, due to
+ me forcing the terminal cursor position to zero in the
+ wrong place in gl_check_caught_signal().
+
+14/12/2002 Markus Gyger (logged here by mcs)
+ configure.in configure
+ Under Solaris, recent versions of gcc search
+ /usr/local/include for header files before the system
+ directories. This caused a problem if ncurses was
+ installed under Solaris, since the termcap.h include file
+ in /usr/local/include ended up being used at compile
+ time, whereas the system default version of the curses
+ library was used at link time. Since the two libraries
+ declare tputs() differently, this evoked a complaint from
+ gcc. Markus came up with a way to force Gnu cpp to move
+ /usr/local/include to the end of the system-include-file
+ search path, where it belongs.
+
+13/12/2002 mcs@astro.caltech.edu
+ man3/gl_io_mode.3
+ I rewrote the man page which documents the new non-blocking
+ server I/O mode.
+
+12/12/2002 mcs@astro.caltech.edu
+ demo3.c
+ I wrote a new version of demo3.c, using signal handlers
+ that call gl_handle_signal() and gl_abandon_line(), where
+ previously in this demo, these functions were called from
+ the application code.
+
+05/12/2002 mcs@astro.caltech.edu
+ getline.c
+ gl_normal_io(), gl_raw_io() and gl_handle_signal() and
+ gl_abandon_line() are now signal safe, provided that
+ signal handlers that call them are installed with sa_mask's
+ that block all other signals who's handlers call them.
+ This is the case if gl_tty_signals() is used to install
+ signal handlers that call any of these functions.
+
+ A major stumbling block that had to be overcome was that
+ gl_displayed_char_width() calls isprint(), which can't
+ safely be called from a signal handler (eg. under linux,
+ the is*() functions all use thread-specific data
+ facilities to support per-thread locales, and the
+ thread-specific data facilities aren't signal safe). To
+ work around this, all functions that modify the
+ input-line buffer, now do so via accessor functions which
+ also maintain a parallel array of character widths, for
+ use by gl_buff_curpos_to_term_curpos() in place of
+ gl_displayed_char_width(). Other minor problems were the
+ need to avoid tputs(), who's signal safety isn't defined.
+
+05/12/2002 Eric Norum (logged here by mcs@astro.caltech.edu)
+ configure.in
+ Eric provided the configuration information needed
+ to build shared libraries under Darwin (Max OS X).
+
+05/12/2002 Richard Mlynarik (logged here by mcs@astro.caltech.edu)
+ configure.in
+ AC_PROG_RANLIB gets the wrong version of ranlib when
+ cross compiling, so has now been replaced by an
+ invokation of AC_CHECK_TOOL. In addition, AC_CHECK_TOOL
+ is also now used to find an appropriate version of LD.
+
+05/12/2002 mcs@astro.caltech.edu (based on patch by Pankaj Rathore)
+ getline.c libtecla.h libtecla.map man3/gl_get_line.3
+ The new gl_set_term_size() function provides a way
+ to tell gl_get_line() about changes in the size of
+ the terminal in cases where the values returned by
+ ioctl(TIOCGWINSZ) isn't correct.
+
+05/12/2002 mcs@astro.caltech.edu
+ getline.c
+ Rather than calling sprintf() to see how much space would
+ be needed to print a given number in octal, I wrote a
+ gl_octal_width() function, for use by
+ gl_displayed_char_width(). This makes the latter
+ function async signal safe.
+
+05/12/2002 mcs@astro.caltech.edu
+ chrqueue.c
+ Whenever the buffer is exhausted, and getting a new
+ buffer node would require a call to malloc(), attempt
+ to flush the buffer to the terminal. In blocking I/O
+ mode this means that the buffer never grows. In
+ non-blocking I/O mode, it just helps keep the buffer
+ size down.
+
+05/12/2002 mcs@astro.caltech.edu
+ freelist.h freelist.c
+ The new _idle_FreeListNodes() function queries the
+ number of nodes in the freelist which aren't currently
+ in use.
+
+05/12/2002 mcs@astro.caltech.edu
+ Makefile.stub
+ This now accepts all of the targets that the configured
+ makefile does, and after configuring the latter makefile,
+ it invokes it with the same options.
+
+03/12/2002 mcs@astro.caltech.edu
+ mans3/gl_io_mode.3
+ I completed the man page for all of the new functions
+ related to non-blocking I/O.
+
+01/12/2002 mcs@astro.caltech.edu
+ man3/gl_get_line.3
+ I wrote a long section on reliable signal handling,
+ explaining how gl_get_line() does this, how to make
+ use of this in a program, and how to handle signals
+ reliably when faced with other blocking functions.
+ This basically documents what I have learnt about
+ signal handling while working on this library.
+
+01/12/2002 mcs@astro.caltech.edu
+ getline.c man3/gl_get_line.3
+ In non-blocking server mode, the gl_replace_prompt()
+ function can now be used between calls to gl_get_line()
+ if the application wants to change the prompt of the
+ line that is being edited.
+
+01/12/2002 mcs@astro.caltech.edu
+ man3/gl_get_line.3
+ I documented the new gl_return_status() and
+ gl_error_message() functions.
+
+01/12/2002 mcs@astro.caltech.edu
+ getline.c man3/gl_get_line.3
+ Added SIGPOLL and SIGXFSZ to the list of signals that
+ are trapped by default. These are process termination
+ signals, so the terminal needs to be restored to a
+ usable state before they terminate the process.
+
+27/11/2002 mcs@astro.caltech.edu
+ getline.c libtecla.h
+ Completed the essential changes needed to support
+ non-blocking server-I/O mode.
+
+ The new gl_io_mode() function allows one to switch to
+ and from non-blocking server-I/O mode.
+
+ The new gl_raw_io() function is used in non-blocking
+ server-I/O mode to switch the terminal into non-blocking
+ raw I/O mode.
+
+ The new gl_normal_io() function is used in non-blocking
+ server-I/O mode to switch the restore the terminal to
+ a normal, blocking state. This is used to suspend line
+ input before suspending the process or writing messages
+ to the terminal.
+
+ The new gl_tty_signals() function installs specified
+ signals handlers for all signals that suspend, terminate
+ or resume processes, and also for signals that indicate
+ that the terminal has been resized. This not only saves
+ the application from having to keep its own ifdef'd list
+ of such signals, of which there are many, but it also
+ makes sure that these signal handlers are registered
+ correctly. This includes using the sa_mask member of each
+ sigaction structure to ensure that only one of these
+ handlers runs at a time. This is essential to avoid the
+ signal handlers all trying to simultaneously modify
+ shared global data.
+
+ The new gl_handle_signal() function is provided for
+ responding (from application level) to signals caught by
+ the application. It handles process suspension, process
+ termination and terminal resize signals.
+
+ The new gl_pending_io() function tells the application
+ what direction of I/O gl_get_line() is currently waiting
+ for.
+
+ In non-blocking server I/O mode, the new
+ gl_abandon_line() function can be called between calls to
+ gl_get_line() to discard an input line and force the next
+ call to gl_get_line() to start the input of a new line.
+
+ Also, in non-blocking server-I/O gl_get_line() doesn't
+ attempt to do anything but return when one of the signals
+ that it is configured to catch is caught. This is
+ necessary because when in this mode, the application is
+ required to handle these signals when gl_get_line() is
+ running, and the default configuration of most of these
+ signals in gl_get_line() is to restore the terminal then
+ call the application signal handlers. This would be a
+ case of too many cooks spoiling the broth, so in this
+ mode, gl_get_line() always defers to the application's
+ signal handlers.
+
+26/11/2002 mcs@astro.caltech.edu
+ getline.c libtecla.h
+ I implemented a couple of new functions to support
+ reliable signal handling, as now documented
+ (see above) in the gl_get_line(3) man page.
+
+ The new gl_catch_blocked() function tells gl_get_line()
+ to unblock all configured signals around calls to
+ long-running functions, not only those that aren't
+ blocked when gl_get_line() is called. This allows
+ the caller to implement reliable signal handling,
+ since the unblocking is only done from within code
+ protected by sigsetjmp(), which avoids race conditions.
+
+ The new gl_list_signals() function fills a provided
+ sigset_t with the set of signals that gl_get_line() is
+ currently configured to catch. This allows callers to
+ block said signals, such that they are only unblocked by
+ gl_get_line() when it is waiting for I/O. When used in
+ conjunction with the gl_catch_blocked() function, this
+ removes the potential for race conditions.
+
+ Also, when gl_get_line() installs its signal handler,
+ it uses the sa_mask member of the sigaction structure
+ to ensure that only one instance of this signal handler
+ will ever be executing at a time.
+
+25/11/2002 mcs@astro.caltech.edu (bug reported by Pankaj Rathore)
+ getline.c
+ When any history recall action was invoked when the
+ input line buffer was full, an error message would be
+ displayed complaining about the length of the string
+ in the line input buffer being inconsistent with the
+ specified allocated size. This was because instead of
+ sending the allocated size of the input line, I was
+ sending the length excluding the element that is
+ reserved for the '\0' terminator. Sending it the
+ correct size corrected the problem.
+
+24/11/2002 mcs@astro.caltech.edu
+ getline.c
+ All public functions which take GetLine objects as
+ arguments now block signals on entry and restore the
+ signal mask on return. This was an attempt to make it
+ safe to call getline functions from signal handlers, but
+ the fact is that the functions that I really wanted this
+ to apply to, potentially call malloc(), so this currently
+ isn't the case.
+
+23/11/2002 mcs@astro.caltech.edu
+ getline.c libtecla.h
+ The new gl_return_status() function returns an enumerated
+ return status which can be used to query what caused
+ gl_get_line() to return.
+
+22/11/2002 mcs@astro.caltech.edu
+ Most existing .c and .h files, plus errmsg.c errmsg.h
+ Makefile.rules
+ Until now, many library functions would report error
+ messages to stderr. This isn't appropriate for library
+ functions, so in place of this behavior, error messages
+ are now recorded in internal ErrMsg objects, and passed
+ between modules via new module-specific error querying
+ functions. In addition, errno is now set appropriately.
+ Thus when gl_get_line() and related functions return an
+ error, strerror() can be used to look up system errors,
+ and gl_error_message() can be used to recover a higher level
+ error message. Note that error messages that are
+ responses to user actions continue to be reported to the
+ terminal, as before.
+
+21/11/2002 mcs@astro.caltech.edu
+ getline.c keytab.h keytab.c Makefile.rules
+ I wrote a new version of _kt_lookup_binding() that didn't
+ require the caller to have access to the innards of a
+ KeyTab object. This then enabled me to move the definition
+ of KeyTab objects into keytab.c and make the typedef in
+ keytab.h opaque. Many nested includes were also moved from
+ keytab.h into keytab.c.
+
+05/11/2002 mcs@astro.caltech.edu
+ getline.c libtecla.map libtecla.h demo3.c
+ I split the old gl_resize_terminal() function into
+ two parts, gl_query_size() and gl_update_size(), with
+ the latter calling the former to get the new terminal
+ size.
+
+05/11/2002 mcs@astro.caltech.edu
+ getline.c
+ I fixed a long time bug in the terminal resizing code.
+ When the cursor wasn't on the last terminal line of the
+ input line, the resizing code would redisplay the
+ the line one or more lines above where it should be
+ restored. This was due to an error in the calculation of
+ the number of lines above the cursor position.
+
+04/11/2002 mcs@astro.caltech.edu
+ demo.c demo2.c demo3.c
+ I used the new gl_display_text() function to display
+ introductory text at the startup of each of the demo
+ programs. The text is enclosed within a box of asterixes,
+ drawn dynamically to fit within the confines of the
+ available terminal width.
+
+04/11/2002 mcs@astro.caltech.edu
+ libtecla.h getline.c ioutil.c ioutil.h Makefile.rules
+ libtecla.map man3/gl_get_line.3 man3/gl_display_text.3
+ Needing a way to display introductory text intelligently
+ in the demo programs, I wrote and documented the
+ gl_display_text() function. This justifies arbitrary
+ length text within the bounds of the terminal width,
+ with or without optional indentation, prefixes and
+ suffixes.
+
+03/11/2002 mcs@astro.caltech.edu
+ demo3.c Makefile.rules
+ I wrote a new demonstration program. This program acts
+ exactly like the main demonstration program, except that
+ it uses an external event loop instead of using the
+ gl_get_line() internal event loop. This is thus an example
+ of the new non-blocking server I/O facility.
+
+02/11/2002 mcs@astro.caltech.edu
+ getline.c keytab.c keytab.h libtecla.h man3/gl_get_line.3
+ man3/gl_completion_action.3
+ I added the ability to register additional word
+ completion actions via the new function
+ gl_completion_action(). All action functions now take a
+ new (void *data) argument, which is stored with the
+ function in the symbol table of actions. The new
+ gl_completion_action() function uses this feature to
+ record dynamically allocated objects containing the
+ specified completion function and callback data along
+ with either the gl_complete_word() action function, or
+ the gl_list_completions() action function. These two
+ actions continue to use the builtin completion functions
+ when their data pointer is NULL.
+
+20/10/2002 mcs@astro.caltech.edu
+ The following are changes merged from the non-blocking
+ gl_get_line() development branch.
+
+ getline.c
+ I wrote a gl_start_newline() function, to replace all of
+ the explicit calls to output \r\n to stdout.
+
+ Informational messages are now written to the terminal
+ using a new variadic function called gl_print_info().
+ This starts a newline, writes string arguments until a
+ special argument, GL_END_INFO, is seen, then starts
+ another newline.
+
+ Changed _output_ to _print_ in the following function
+ names gl_output_control_sequence(), gl_output_char(),
+ gl_output_string() and gl_output_raw_string().
+
+ gl_print_raw_string() now has a length argument, so that
+ strings that aren't terminated with '\0' can be printed.
+
+ The display of the initial contents of a new line to be
+ edited has been moved into a new function called
+ gl_present_line().
+
+ The gl_get_input_line() function now takes the prompt
+ string as an argument so that gl_replace_prompt() can be
+ called from within this function instead of from
+ gl_get_line().
+
+ Keyboard input is now buffered in a persistent buffer in
+ the parent GetLine object. gl_read_character() checks
+ this for unprocessed characters in preference to calling
+ gl_read_terminal() to append characters to it. A new
+ function, gl_discard_chars(), removes processed
+ characters from this buffer. This change is in
+ preparation for a non-blocking version of gl_get_line(),
+ where partially input key-sequences must be stored
+ between calls to gl_get_line().
+
+ getline.c getline.h history.c history.h cplmatch.c \
+ cplmatch.h expand.c expand.h
+ All terminal output from gl_get_line() is now routed
+ through a GL_WRITE_FN() callback function called
+ gl_write_fn. Internal functions in cplmatch.c,
+ expand.c and history.c have been created which take
+ such callbacks to write output. These are used both
+ by functions in getline.c, to display file completions,
+ expansions, history etc, and as the internals of existing
+ public functions in these files that print to stdio
+ streams. In the latter case an internal stdio
+ GL_WRITE_FN() callback is substituted, so that the
+ functions behave as before.
+
+ getline.c chrqueue.c chrqueue.h
+ The gl_write_fn() callback used by gl_get_line() now
+ writes to a queue, implemented in chrqueue.c. This queue
+ is implemented as a list of blocks of buffer segments,
+ the number of which shrink and grow as
+ needed. The contents of the queue are flushed to the
+ terminal via another GL_WRITE_FN() callback passed to the
+ queue object. Currently gl_get_line() passes an internal
+ function assigned to gl->flush_fn, called
+ gl_flush_terminal(), which writes the contents of the
+ queue to the terminal, and knows how to handle both
+ blocking and non-blocking I/O. The output queue is
+ designed to be flushed to the terminal incrementally, and
+ thereby also facilitates non-blocking I/O.
+
+ getline.c getline.h
+ gl_get_line() now reads all input via the GL_READ_FN()
+ callback, assigned to gl->read_fn. Currently this is
+ set to an internal function called gl_read_terminal(),
+ which knows how to handle both blocking and
+ non-blocking I/O.
+
+ getline.c libtecla.h
+ The new gl_set_nonblocking() function can be used to
+ enable or disable non-blocking I/O. The default is still
+ blocking I/O. In non-blocking mode, the terminal is told
+ not to wait when either reading or writing would block.
+ gl_get_line() then returns, with a return value of NULL,
+ but with the terminal left in raw mode, so that the
+ caller's event loop can detect key presses. The caller
+ should call gl_return_status() to check whether the NULL
+ return value was due to an error, lack of input, or
+ inability to write to the terminal without waiting. If
+ either reading or writing was said to have blocked, the
+ user then should check for I/O readiness in the specified
+ direction before calling gl_get_line() again to
+ incrementally build up the input line.
+
+05/08/2002 mcs@astro.caltech.edu
+ man3/gl_get_line.3 man3/gl_inactivity_timeout.3
+ I documented the new gl_inactivity_timeout() function.
+
+08/07/2002 mcs@astro.caltech.edu
+ libtecla.h getline.c libtecla.map
+ I added a new gl_inactivity_timeout() function. On
+ systems that have the select system call, this provides
+ the option of registering a function that is then called
+ whenever no I/O activity has been seen for more than a
+ specified period of time. Like the gl_watch_fd()
+ facility, timeout callbacks return a code which tells
+ gl_get_line() how to proceed after the timeout has been
+ handled.
+
+04/07/2002 mcs@astro.caltech.edu (based on a bug report from Michael MacFaden)
+ getline.c
+ The internal event handler wasn't responding to write
+ events on client file descriptors, due to a typo which
+ resulted in read events being checked for twice, and
+ writes not checked for at all.
+ pathutil.c
+ The amount of space to allocate for pathnames is supposed
+ to come from PATH_MAX in limits.h, but I had neglected to
+ include limits.h. This went unnoticed because on most
+ systems the equivalent number is deduced by calling
+ pathconf(). Apparently under NetBSD this function doesn't
+ work correctly over NFS mounts.
+
+30/05/2002 Version 1.4.1 released.
+
25/05/2002 mcs@astro.caltech.edu (based on suggestions by Paul Smith)
pathutil.c
Apparently, under QNX pathconf("/",_PC_PATH_MAX) returns
@@ -21,6 +1272,21 @@ The most recent modifications are listed first.
already doing futher up in the file, so I have just
removed the errant include line.
+07/05/2002 mcs@astro.caltech.edu (async development branch only)
+ getline.c
+ gl_read_character() now caches and reads unprocessed
+ characters from a key-press lookahead buffer. Whenever
+ gl_intepret_char() receives a new character which makes
+ an initially promising key-sequence no longer match the
+ prefix of any binding, it now simply discards the first
+ character from the key-press buffer and resets the buffer
+ pointer so that the next call to gl_read_character()
+ returns the character that followed it, from the buffer.
+ getline.c
+ The part of gl_get_input_line() which preloads, displays
+ and prepares to edit a new input line, has now been moved
+ into a function called gl_present_line().
+
12/02/2002 mcs@astro.caltech.edu
getline.c configure.in configure
Mac OS X doesn't have a term.h or termcap.h, but it does
diff --git a/libtecla-1.4.1/INSTALL b/libtecla-1.6.1/INSTALL
index 1a1b036..14fc62d 100644
--- a/libtecla-1.4.1/INSTALL
+++ b/libtecla-1.6.1/INSTALL
@@ -94,34 +94,79 @@ options may be of interest to you. At first glance, the use of a GNU
configure script by the tecla library, may appear to reduce your
options for controlling what gets made, and where it gets installed,
but this isn't the case, because many of the parameters configured by
-the configure script are assigned to make variables which can be
+the configure script are assigned to makefile variables which can be
overriden when you run make.
-For example, lets say that you have your own configuration script in
-the parent directory of the libtecla top-level directory. In your
-configuration script, you would first need to have the following line:
+Configure script options:
- (cd libtecla; ./configure)
+ If the users of your package won't benefit from having access to the
+ tecla man pages, you can shorten the length of time taken to run the
+ configure script by telling this script not to preprocess the man
+ pages. This is done as follows.
+
+ ./configure --without-man-pages
+
+ Note that this option also causes the makefile man-page installation
+ targets to do nothing.
+
+ Similarly, if you don't want your users to have access to the
+ filesystem while they are editing input lines using gl_get_line(),
+ then use the following configuration argument.
+
+ ./configure --without-file-actions
+
+ This will completely remove the "expand-filename", "read-from-file",
+ "read-init-files", and "list-glob" action functions. It will also
+ arrange that the default behavior of actions such as "complete-word"
+ and "list-or-eof" be changed to show no completions, instead of the
+ normal default of showing filename completions.
+
+ If you are using a system that doesn't have a file-system, such as an
+ embedded system, then libtecla can be built with all code that
+ accesses the filesystem removed. This will make the library a bit
+ smaller, and potentially avoid running into problems of missing system
+ functions related to file-system access. This is done with the
+ following configuration option.
+
+ ./configure --without-file-system
+
+ Beware that this not only prevents the user from accessing the
+ filesystem while editing an input line in gl_get_line(), but also
+ removes all public file-related functions, such as the pathname
+ expansion module. When using gl_get_line() in this configuration,
+ the functions that load and save history from and to files, are
+ stubs that report an error if called upon to read files. The
+ gl_configure_getline() function can still be called upon to
+ configure gl_get_line() via its app_string argument, but passing it
+ a filename in either the app_file or user_file arguments will result
+ in an error being reported.
+
+Now lets say that you have your own configuration script in the parent
+directory of the libtecla top-level directory, and that you don't want
+tecla's man pages to be generated. In your configuration script, you
+would first need to have a line similar to the following:
+
+ (cd libtecla; ./configure --without-man-pages)
Now, from your makefile or whatever script you use to build your
-application, you would need to make the library. Assuming that your
-makefile or build script is in the parent directory of the libtecla
-distribution, the following line tells make to just make the
-non-reentrant, static version of the tecla library, and to install it
-and the tecla include file in sub-directories called lib and include
-in your current directory.
+application, you would need to make the tecla library. Assuming that
+your makefile or build script is in the parent directory of the
+libtecla distribution, then the following line tells make to just
+build the non-reentrant, static version of the tecla library, and then
+to install it and the tecla include file in sub-directories called lib
+and include in your current directory.
(cd libtecla; make LIBDIR=../lib INCDIR=../include TARGETS=normal TARGET_LIBS="static" install_lib install_inc)
-First, the LIBDIR=../lib means that on installing the library, it
-should be placed in the directory libtecla/../lib. Similarly INCDIR
-tells make where to place the include files. The install_lib and
-install_inc targets tell make to install the libraries and the include
-file. Because the install_man and install_bin targets have been
-omitted in this example, the man pages and programs aren't installed.
-If you were to include these additional targets then you could use the
-MANDIR and BINDIR variables, respectively to control where they were
-installed.
+In this statement the LIBDIR=../lib component means that on installing
+the library, the make command should place the library in the
+directory libtecla/../lib. Similarly INCDIR tells make where to place
+the include files. The install_lib and install_inc targets tell make
+to install the libraries and the include file. Because the install_man
+and install_bin targets have been omitted in this example, the man
+pages and programs aren't installed. If you were to include these
+additional targets then you could use the MANDIR and BINDIR variables,
+respectively to control where they were installed.
The TARGETS variable is used to specify which of the normal and
reentrant versions of the library are compiled. This can contain one
diff --git a/libtecla-1.4.1/LICENSE.TERMS b/libtecla-1.6.1/LICENSE.TERMS
index 275eef5..e5d9454 100644
--- a/libtecla-1.4.1/LICENSE.TERMS
+++ b/libtecla-1.6.1/LICENSE.TERMS
@@ -1,4 +1,4 @@
-Copyright (c) 2000, 2001 by Martin C. Shepherd.
+Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
All rights reserved.
diff --git a/libtecla-1.6.1/Makefile b/libtecla-1.6.1/Makefile
new file mode 100644
index 0000000..cf89638
--- /dev/null
+++ b/libtecla-1.6.1/Makefile
@@ -0,0 +1,12 @@
+default:
+ ./configure
+ $(MAKE)
+
+distclean:
+ ./configure --without-man-pages
+ $(MAKE) $@
+
+normal reentrant demos demos_r clean install_lib install_bin install_inc \
+ install_man install:
+ ./configure
+ $(MAKE) $@
diff --git a/libtecla-1.4.1/Makefile.in b/libtecla-1.6.1/Makefile.in
index f691375..4b7c9c3 100644
--- a/libtecla-1.4.1/Makefile.in
+++ b/libtecla-1.6.1/Makefile.in
@@ -33,6 +33,14 @@ CC = @CC@
RANLIB = @RANLIB@
+# Optional flags to pass to the linker.
+
+LDFLAGS = @LDFLAGS@
+
+# Optional C pre-processor flags.
+
+CPPFLAGS = @CPPFLAGS@
+
# The following optional defines change the characteristics of the library.
#
# USE_TERMINFO
@@ -76,7 +84,7 @@ DEFINES = @DEFS@
# DEFINES_R = -D_POSIX_C_SOURCE=199506L
#
-DEFINES_R = -D_POSIX_C_SOURCE=199506L
+DEFINES_R = @DEFS_R@
#
# The compiler optimization flags. I like to keep this separate so
@@ -157,17 +165,17 @@ CFLAGS = $(OPT) $(WARNING_FLAGS) $(DEFINES) @CFLAGS@ @SHARED_CFLAGS@
default: $(TARGETS)
normal:
- @$(MAKE) -f $(srcdir)/Makefile.rules TARGETS="$(TARGET_LIBS)" SUFFIX="" CFLAGS="$(CFLAGS)" CC="$(CC)" OBJDIR=normal_obj LINK_SHARED='@LINK_SHARED@' SHARED_EXT='@SHARED_EXT@' SHARED_ALT='@SHARED_ALT@' LIBS='$(LIBS)' srcdir='$(srcdir)' LIBDIR='$(LIBDIR)' LN_S='@LN_S@' DEMOS="$(DEMOS)" PROGRAMS='$(PROGRAMS)' RANLIB='$(RANLIB)'
+ @$(MAKE) -f $(srcdir)/Makefile.rules TARGETS="$(TARGET_LIBS)" SUFFIX="" CFLAGS="$(CFLAGS)" CC="$(CC)" OBJDIR=normal_obj LINK_SHARED='@LINK_SHARED@' SHARED_EXT='@SHARED_EXT@' SHARED_ALT='@SHARED_ALT@' LIBS='$(LIBS)' srcdir='$(srcdir)' LIBDIR='$(LIBDIR)' LN_S='@LN_S@' DEMOS="$(DEMOS)" PROGRAMS='$(PROGRAMS)' RANLIB='$(RANLIB)' LDFLAGS=$(LDFLAGS) CPPFLAGS=$(CPPFLAGS)
reentrant:
- @$(MAKE) -f $(srcdir)/Makefile.rules TARGETS="$(TARGET_LIBS)" SUFFIX="_r" CFLAGS="$(CFLAGS) $(DEFINES_R)" CC="$(CC)" OBJDIR=reentrant_obj LINK_SHARED='@LINK_SHARED@' SHARED_EXT='@SHARED_EXT@' SHARED_ALT='@SHARED_ALT@' LIBS='$(LIBS)' srcdir='$(srcdir)' LIBDIR='$(LIBDIR)' LN_S='@LN_S@' DEMOS="$(DEMOS)" PROGRAMS='$(PROGRAMS_R)' RANLIB='$(RANLIB)'
+ @$(MAKE) -f $(srcdir)/Makefile.rules TARGETS="$(TARGET_LIBS)" SUFFIX="_r" CFLAGS="$(CFLAGS) $(DEFINES_R)" CC="$(CC)" OBJDIR=reentrant_obj LINK_SHARED='@LINK_SHARED@' SHARED_EXT='@SHARED_EXT@' SHARED_ALT='@SHARED_ALT@' LIBS='$(LIBS)' srcdir='$(srcdir)' LIBDIR='$(LIBDIR)' LN_S='@LN_S@' DEMOS="$(DEMOS)" PROGRAMS='$(PROGRAMS_R)' RANLIB='$(RANLIB)' LDFLAGS=$(LDFLAGS) CPPFLAGS=$(CPPFLAGS)
demos: normal
demos_r: reentrant
clean:
- rm -rf *.o normal_obj reentrant_obj libtecla*.a demo demo2 demo_r demo2_r enhance *~ man3/*~ html/*~ compile_reentrant compile_normal
+ rm -rf *.o normal_obj reentrant_obj libtecla*.a demo demo[0-9] demo_r demo[0-9]_r enhance *~ man/*~ man/*/*~ html/*~ compile_reentrant compile_normal `/bin/ls -1 man/*/*.in | sed 's/\.in$$//'`
@endings="@SHARED_EXT@ @SHARED_ALT@" ; \
for alt in $$endings ; do \
lib="libtecla*$$alt" ; \
@@ -175,7 +183,8 @@ clean:
done
distclean: clean
- rm -f config.cache config.status config.log Makefile libtecla.map.opt
+ rm -rf config.cache config.status config.log Makefile libtecla.map.opt \
+ autom*.cache
cp $(srcdir)/Makefile.stub Makefile
install_lib: $(TARGETS) $(LIBDIR)
@@ -206,20 +215,58 @@ install_inc: $(INCDIR)
echo "cp $(srcdir)/libtecla.h $(INCDIR)/ ; chmod ugo+r $(INCDIR)/libtecla.h"; \
fi
-install_man: $(MANDIR) $(MANDIR)/man3
- cd $(srcdir)/man3 && for page in *.3; do cp $$page $(MANDIR)/man3; chmod ugo+r $(MANDIR)/man3/$$page; done
+install_man: $(MANDIR) libr_man func_man prog_man misc_man file_man
+
+libr_man:
+ if test "@MAKE_MAN_PAGES@"_ = "yes"_; then \
+ for template in man/libr/*.in; do \
+ page=`basename "$$template" .in`; \
+ $(srcdir)/install-sh -c -m 644 man/libr/$$page ${MANDIR}/@LIBR_MANDIR@/$$page.@LIBR_MANEXT@; \
+ done ; \
+ fi
+
+func_man:
+ if test "@MAKE_MAN_PAGES@"_ = "yes"_; then \
+ for template in man/func/*.in; do \
+ page=`basename "$$template" .in`; \
+ $(srcdir)/install-sh -c -m 644 man/func/$$page ${MANDIR}/@FUNC_MANDIR@/$$page.@FUNC_MANEXT@; \
+ done ; \
+ fi
+
+prog_man:
+ if test "@MAKE_MAN_PAGES@"_ = "yes"_; then \
+ for template in man/prog/*.in; do \
+ page=`basename "$$template" .in`; \
+ $(srcdir)/install-sh -c -m 644 man/prog/$$page ${MANDIR}/@PROG_MANDIR@/$$page.@PROG_MANEXT@; \
+ done ; \
+ fi
+
+misc_man:
+ if test "@MAKE_MAN_PAGES@"_ = "yes"_; then \
+ for template in man/misc/*.in; do \
+ page=`basename "$$template" .in`; \
+ $(srcdir)/install-sh -c -m 644 man/misc/$$page ${MANDIR}/@MISC_MANDIR@/$$page.@MISC_MANEXT@; \
+ done ; \
+ fi
+
+file_man:
+ if test "@MAKE_MAN_PAGES@"_ = "yes"_; then \
+ for template in man/file/*.in; do \
+ page=`basename "$$template" .in`; \
+ $(srcdir)/install-sh -c -m 644 man/file/$$page ${MANDIR}/@FILE_MANDIR@/$$page.@FILE_MANEXT@; \
+ done ; \
+ fi
install_bin: $(BINDIR) $(PROGRAMS) $(PROGRAMS_R)
progs="$(PROGRAMS) $(PROGRAMS_R)"; \
for prog in $$progs; do \
- cp $$prog $(BINDIR)/; \
- chmod ugo+rx $(BINDIR)/$$prog; \
+ $(srcdir)/install-sh -c -m 755 -s $$prog $(BINDIR)/; \
done
install: install_lib install_inc install_man install_bin
# Make any missing installation directories.
-$(MANDIR) $(MANDIR)/man3 $(LIBDIR) $(INCDIR) $(BINDIR):
+$(MANDIR) $(LIBDIR) $(INCDIR) $(BINDIR):
$(srcdir)/install-sh -d $@
chmod ugo+rx $@
diff --git a/libtecla-1.4.1/Makefile.rules b/libtecla-1.6.1/Makefile.rules
index 6552057..22508bf 100644
--- a/libtecla-1.4.1/Makefile.rules
+++ b/libtecla-1.6.1/Makefile.rules
@@ -17,11 +17,16 @@ LIB_OBJECTS = $(OBJDIR)/getline.o $(OBJDIR)/keytab.o $(OBJDIR)/freelist.o \
$(OBJDIR)/strngmem.o $(OBJDIR)/hash.o $(OBJDIR)/history.o \
$(OBJDIR)/direader.o $(OBJDIR)/homedir.o $(OBJDIR)/pathutil.o \
$(OBJDIR)/expand.o $(OBJDIR)/stringrp.o $(OBJDIR)/cplfile.o \
- $(OBJDIR)/cplmatch.o $(OBJDIR)/pcache.o $(OBJDIR)/version.o
+ $(OBJDIR)/cplmatch.o $(OBJDIR)/pcache.o $(OBJDIR)/version.o \
+ $(OBJDIR)/chrqueue.o $(OBJDIR)/ioutil.o $(OBJDIR)/errmsg.o
+
+# List the available demonstration programs.
+
+DEMO_PROGS = demo$(SUFFIX) demo2$(SUFFIX) demo3$(SUFFIX)
# List all of the programs that this makefile can build.
-PROGS = demo$(SUFFIX) demo2$(SUFFIX) enhance$(SUFFIX)
+PROGS = $(DEMO_PROGS) enhance$(SUFFIX)
static: libtecla$(SUFFIX).a
@@ -46,7 +51,7 @@ libtecla$(SUFFIX)$(SHARED_EXT): $(LIB_OBJECTS) $(srcdir)/libtecla.map \
libtecla.map.opt: $(srcdir)/libtecla.map
sed -n 's/^[ ]*\([_a-zA-Z0-9]*\)[ ]*;.*/+e \1/p' $? >$@
-demos: demo$(SUFFIX) demo2$(SUFFIX)
+demos: $(DEMO_PROGS)
demo$(SUFFIX): $(OBJDIR)/demo.o
LD_RUN_PATH="$(LIBDIR):$$LD_RUN_PATH:`pwd`" $(CC) $(CFLAGS) -o $@ \
@@ -56,6 +61,10 @@ demo2$(SUFFIX): $(OBJDIR)/demo2.o
LD_RUN_PATH="$(LIBDIR):$$LD_RUN_PATH:`pwd`" $(CC) $(CFLAGS) -o $@ \
$(OBJDIR)/demo2.o -L. -ltecla$(SUFFIX) $(LIBS)
+demo3$(SUFFIX): $(OBJDIR)/demo3.o
+ LD_RUN_PATH="$(LIBDIR):$$LD_RUN_PATH:`pwd`" $(CC) $(CFLAGS) -o $@ \
+ $(OBJDIR)/demo3.o -L. -ltecla$(SUFFIX) $(LIBS)
+
enhance$(SUFFIX): $(OBJDIR)/enhance.o
LD_RUN_PATH="$(LIBDIR):$$LD_RUN_PATH:`pwd`" $(CC) $(CFLAGS) -o $@ \
$(OBJDIR)/enhance.o -L. -ltecla$(SUFFIX) $(LIBS)
@@ -66,11 +75,14 @@ enhance$(SUFFIX): $(OBJDIR)/enhance.o
$(OBJDIR)/getline.o: $(srcdir)/getline.c $(srcdir)/pathutil.h \
$(srcdir)/libtecla.h $(OBJDIR)/keytab.h $(srcdir)/history.h \
- $(srcdir)/freelist.h $(srcdir)/stringrp.h $(srcdir)/getline.h
+ $(srcdir)/freelist.h $(srcdir)/stringrp.h $(srcdir)/getline.h \
+ $(srcdir)/ioutil.h $(srcdir)/chrqueue.h $(srcdir)/cplmatch.h \
+ $(srcdir)/expand.h $(srcdir)/errmsg.h
$(COMPILE) $(srcdir)/getline.c
$(OBJDIR)/keytab.o: $(srcdir)/keytab.c $(OBJDIR)/keytab.h \
- $(srcdir)/strngmem.h $(srcdir)/getline.h
+ $(srcdir)/strngmem.h $(srcdir)/getline.h $(srcdir)/errmsg.h \
+ $(srcdir)/hash.h
$(COMPILE) $(srcdir)/keytab.c
$(OBJDIR)/strngmem.o: $(srcdir)/strngmem.c $(srcdir)/strngmem.h \
@@ -84,20 +96,22 @@ $(OBJDIR)/hash.o: $(srcdir)/hash.c $(srcdir)/hash.h $(srcdir)/strngmem.h \
$(srcdir)/freelist.h
$(COMPILE) $(srcdir)/hash.c
-$(OBJDIR)/history.o: $(srcdir)/history.c $(srcdir)/history.h \
- $(srcdir)/freelist.h
+$(OBJDIR)/history.o: $(srcdir)/history.c $(srcdir)/ioutil.h \
+ $(srcdir)/history.h $(srcdir)/freelist.h $(srcdir)/errmsg.h
$(COMPILE) $(srcdir)/history.c
$(OBJDIR)/expand.o: $(srcdir)/expand.c $(srcdir)/freelist.h \
$(srcdir)/direader.h $(srcdir)/pathutil.h $(srcdir)/homedir.h \
- $(srcdir)/stringrp.h $(srcdir)/libtecla.h
+ $(srcdir)/stringrp.h $(srcdir)/libtecla.h $(srcdir)/ioutil.h \
+ $(srcdir)/expand.h $(srcdir)/errmsg.h
$(COMPILE) $(srcdir)/expand.c
-$(OBJDIR)/direader.o: $(srcdir)/direader.c $(srcdir)/direader.h
+$(OBJDIR)/direader.o: $(srcdir)/direader.c $(srcdir)/direader.h \
+ $(srcdir)/errmsg.h
$(COMPILE) $(srcdir)/direader.c
$(OBJDIR)/homedir.o: $(srcdir)/homedir.c $(srcdir)/pathutil.h \
- $(srcdir)/homedir.h
+ $(srcdir)/homedir.h $(srcdir)/errmsg.h
$(COMPILE) $(srcdir)/homedir.c
$(OBJDIR)/pathutil.o: $(srcdir)/pathutil.c $(srcdir)/pathutil.h
@@ -109,16 +123,17 @@ $(OBJDIR)/stringrp.o: $(srcdir)/stringrp.c $(srcdir)/freelist.h \
$(OBJDIR)/cplfile.o: $(srcdir)/cplfile.c $(srcdir)/libtecla.h \
$(srcdir)/direader.h $(srcdir)/homedir.h $(srcdir)/pathutil.h \
- $(srcdir)/cplfile.h
+ $(srcdir)/cplfile.h $(srcdir)/errmsg.h
$(COMPILE) $(srcdir)/cplfile.c
$(OBJDIR)/cplmatch.o: $(srcdir)/cplmatch.c $(srcdir)/libtecla.h \
- $(srcdir)/stringrp.h $(srcdir)/pathutil.h $(srcdir)/cplfile.h
+ $(srcdir)/ioutil.h $(srcdir)/stringrp.h $(srcdir)/pathutil.h \
+ $(srcdir)/cplfile.h $(srcdir)/cplmatch.h $(srcdir)/errmsg.h
$(COMPILE) $(srcdir)/cplmatch.c
$(OBJDIR)/pcache.o: $(srcdir)/pcache.c $(srcdir)/libtecla.h \
$(srcdir)/pathutil.h $(srcdir)/homedir.h $(srcdir)/freelist.h \
- $(srcdir)/direader.h $(srcdir)/stringrp.h
+ $(srcdir)/direader.h $(srcdir)/stringrp.h $(errmsg.h)
$(COMPILE) $(srcdir)/pcache.c
$(OBJDIR)/demo.o: $(srcdir)/demo.c $(srcdir)/libtecla.h
@@ -127,16 +142,28 @@ $(OBJDIR)/demo.o: $(srcdir)/demo.c $(srcdir)/libtecla.h
$(OBJDIR)/demo2.o: $(srcdir)/demo2.c $(srcdir)/libtecla.h
$(COMPILE) $(srcdir)/demo2.c
+$(OBJDIR)/demo3.o: $(srcdir)/demo3.c $(srcdir)/libtecla.h
+ $(COMPILE) $(srcdir)/demo3.c
+
$(OBJDIR)/version.o: $(srcdir)/version.c $(srcdir)/libtecla.h
$(COMPILE) $(srcdir)/version.c
$(OBJDIR)/enhance.o: $(srcdir)/enhance.c $(srcdir)/libtecla.h
$(COMPILE) $(srcdir)/enhance.c
+$(OBJDIR)/chrqueue.o: $(srcdir)/chrqueue.c $(srcdir)/ioutil.h \
+ $(srcdir)/chrqueue.h $(srcdir)/freelist.h $(srcdir)/errmsg.h
+ $(COMPILE) $(srcdir)/chrqueue.c
+
+$(OBJDIR)/ioutil.o: $(srcdir)/ioutil.c $(srcdir)/ioutil.h
+ $(COMPILE) $(srcdir)/ioutil.c
+
+$(OBJDIR)/errmsg.o: $(srcdir)/errmsg.c $(srcdir)/errmsg.h
+ $(COMPILE) $(srcdir)/errmsg.c
+
#-----------------------------------------------------------------------
# Include file dependencies.
#-----------------------------------------------------------------------
-$(OBJDIR)/keytab.h: $(srcdir)/keytab.h $(srcdir)/libtecla.h \
- $(srcdir)/hash.h $(srcdir)/strngmem.h
+$(OBJDIR)/keytab.h: $(srcdir)/keytab.h $(srcdir)/libtecla.h
cp $(srcdir)/keytab.h $@
diff --git a/libtecla-1.6.1/Makefile.stub b/libtecla-1.6.1/Makefile.stub
new file mode 100644
index 0000000..cf89638
--- /dev/null
+++ b/libtecla-1.6.1/Makefile.stub
@@ -0,0 +1,12 @@
+default:
+ ./configure
+ $(MAKE)
+
+distclean:
+ ./configure --without-man-pages
+ $(MAKE) $@
+
+normal reentrant demos demos_r clean install_lib install_bin install_inc \
+ install_man install:
+ ./configure
+ $(MAKE) $@
diff --git a/libtecla-1.4.1/PORTING b/libtecla-1.6.1/PORTING
index db39818..db39818 100644
--- a/libtecla-1.4.1/PORTING
+++ b/libtecla-1.6.1/PORTING
diff --git a/libtecla-1.4.1/README b/libtecla-1.6.1/README
index 894819d..72541b3 100644
--- a/libtecla-1.4.1/README
+++ b/libtecla-1.6.1/README
@@ -1,4 +1,4 @@
-This is version 1.4.1 of the tecla command-line editing library.
+This is version 1.6.1 of the tecla command-line editing library.
For the current official release, please direct your browser to:
@@ -23,7 +23,7 @@ the INSTALL file, which should be in the same directory as this file.
Copyright and Disclaimer
------------------------
-Copyright (c) 2000, 2001 by Martin C. Shepherd.
+Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
All rights reserved.
diff --git a/libtecla-1.4.1/RELEASE.NOTES b/libtecla-1.6.1/RELEASE.NOTES
index 1b18a4a..64f941f 100644
--- a/libtecla-1.4.1/RELEASE.NOTES
+++ b/libtecla-1.6.1/RELEASE.NOTES
@@ -1,5 +1,235 @@
This file lists major changes which accompany each new release.
+Version 1.6.1:
+
+ This is primarily a minor bug-fix release.
+
+ One added feature is the ability to call gl_normal_io() from
+ callbacks registered by gl_watch_fd() and
+ gl_inactivity_timeout(). This allows these callbacks to cleanly
+ suspend line editing before either reading from the terminal, or
+ writing to the terminal; and then subsequently causes the input line
+ to be automatically redisplayed, and line-editing to be resumed by
+ gl_get_line(), as soon as the callback returns.
+
+ Another minor change is that if the terminal type specified in the
+ TERM environment variable is set to "dumb", gl_get_line() now treats
+ the terminal as though it were a non-interactive stream, rather than
+ treating it as a VT100-compatible terminal. This means that it
+ doesn't either prompt for input, or perform any command-line
+ editing, even when it really is interacting with a terminal. This is
+ aimed at the rare situation where a third-pary program that connects
+ to libtecla through an embedded pseudo-terminal, needs to be forced
+ to behave as though it weren't talking to a terminal, in order that
+ it be useable in non-interactive scripts.
+
+ Note that in the previous release, the optional configuration
+ function, gl_tty_signals(), was incorrectly swapping the suspend and
+ terminal signal handlers before installing them.
+
+ A configuration problem that prevented select() from being used
+ under MacOS X, has been fixed.
+
+ Although not documented in the man page, it was meant to be possible
+ to take the input line that one call to gl_get_line() returned, and
+ ask the next call to gl_get_line() to present it back to the user
+ for re-editing, simply by passing the pointer returned by one call
+ to gl_get_line() as the start_line argument of the next call to
+ gl_get_line(). This feature unfortunately stopped working in 1.6.0,
+ so this release restores it, and officially documents it in the man
+ page documentation of gl_get_line().
+
+ In the previous version of the library, calling gl_terminal_size()
+ on a system without SIGWINCH support, would crash the
+ application. This has been fixed.
+
+ Libtecla now apparently compiles cleanly under IRIX.
+
+Version 1.6.0:
+
+ This release is primarily a bug-fix release. However there are also
+ four new functions, so the minor version number has been
+ incremented to reflect this.
+
+ Two of the new functions are gl_automatic_history() and
+ gl_append_history(). The former of these functions allows the
+ application to tell gl_get_line() not to automatically archive
+ entered lines in the history list. The second of these functions
+ allows the application to explicitly append a line to the history
+ list. Thus together, these two functions allow the calling
+ application to take over control of what is placed in the history
+ list.
+
+ The third new function is gl_query_char(), which prompts the user
+ for a single character reply, which the user can then type without
+ having to hit return to enter it. Unless echoing is disabled, the
+ character that is entered is then displayed after the prompt,
+ and a newline is started.
+
+ Finally, the 4th new function is gl_read_char(), which also reads
+ a single character from the user, but doesn't prompt the user, write
+ anything to the terminal, or disturb any partially entered input
+ line. It is thus safe to call this function not only from between
+ calls to gl_get_line(), but also from application callback
+ functions, even if gl_normal_io() hasn't been called.
+
+ When using the history-search-backwards or history-search-forwards
+ actions, if the search prefix that the user typed, contains any of
+ the *,? or [ globbing characters, it is now treated as a glob
+ pattern to be matched against historical lines, instead of a simple
+ prefix.
+
+ I have added a --without-file-system option to the configure
+ script. This is intended for use in embedded systems that either
+ don't have filesystems, or where the file-system code in libtecla is
+ seen as unwanted bloat. See the INSTALL document for details.
+
+ Similarly, I also added a --without-file-actions option to the
+ configure script. This allows the application author/installer to
+ prevent users of gl_get_line() from accessing the filesystem with
+ the builtin actions of gl_get_line(). It does this by removing a
+ number of action functions, such as expand-filename, and list-glob,
+ and by changing the default behavior of other actions, such as
+ complete-word and list-or-eof, to show no completions.
+
+ Now to the bugs that have been fixed. Version 1.5.0 had a lot of big
+ internal changes, so there are a number of bugs that needed to be
+ fixed. There was a bug which caused a crash if gl_load_history()
+ was called multiple times. There was another bug which caused a
+ prompt not to be displayed on the next line after switching from
+ reading input from a file to reading from the terminal. Also, in
+ tecla configuration files, backslash escaped characters within
+ key-binding key-sequences weren't being escaped. Thus ^\\ got
+ interpretted as a control-\ followed by a \ character instead of as
+ a control-\. There was a bug in the history recall mechanism which
+ caused the search prefix to be forgotten in certain complicated
+ usage scenarios. There was a minor memory leak in the
+ gl_configure_getline() function. Finally, if gl_get_line() was
+ aborted by a signal, or any other abnormal event, the value of errno
+ which originally indicated what had happened, got zeroed by the
+ code that restored the terminal to a usable state. Thus the
+ application couldn't figure out what had caused the error, apart
+ from by looking at gl_return_status(). All of these bugs have been
+ fixed.
+
+ In the Makefile, there were a number of places where install-sh was
+ invoked without a path prefix. This has now been remedied.
+
+ A fully functional workaround for a bug in Solaris' terminal I/O
+ code has also been implemented. This bug, which only manifested
+ itself in libtecla's uncommonly used non-blocking server I/O mode,
+ caused characters entered while in normal I/O mode, between calls to
+ gl_get_line() to be invisible to the next call to gl_get_line(),
+ until the user typed at least one more key after raw terminal mode
+ was restored.
+
+ The Gnu autoconf config.guess and config.sub scripts have been
+ updated to their latest versions. Apparently the old versions that I
+ was previously using were too old to know about certain BSD ports.
+
+Version 1.5.0:
+
+ This release includes several major new features for those using
+ gl_get_line(), shared library support in Darwin, better cross
+ compilation support, and various minor bug fixes.
+
+ The biggest new feature is the option of a non-blocking I/O mode, in
+ which gl_get_line() can safely be called from an application's
+ external event-loop to incrementally read input lines from the user.
+ This feature is documented in the gl_io_mode(3) man page.
+
+ In addition, there is now support for the definition of additional
+ word-completion action functions, which can then be bound to
+ different keys. See the documentation of the gl_completion_action()
+ function in the gl_get_line(3) man page.
+
+ Externally defined action functions can also be defined, although
+ presently they don't have write access to the input line, so they
+ are restricted to operations that display information text to the
+ terminal, or modify the environment of the calling application in
+ some way. See the documentation of the gl_register_action() function
+ in the gl_get_line(3) man page.
+
+ Some of the non-blocking I/O support functions can also be used for
+ improved signal handling in the normal blocking mode. In particular,
+ the gl_list_signals() and gl_catch_blocked() functions make it
+ easier to write reliable signal handling around gl_get_line(). The
+ new "RELIABLE SIGNAL HANDLING" section of the gl_get_line(3) man
+ page is intended as an introduction to this subject.
+
+ Programs can now clear the terminal between calls to gl_get_line(),
+ by calling the new gl_erase_terminal() function.
+
+ The gl_display_text() function, now used in the demos to display
+ introductory banners, is provided for formatting text according to
+ the width of the terminal.
+
+ It is now possible to install inactivity timeout callbacks in
+ gl_get_line(), using the new gl_inactivity_timeout() function.
+
+ The new gl_set_term_size() function allows the application to
+ explicitly set the terminal size, for cases, such as when one is
+ using a terminal at the end of a serial lineq, where the terminal
+ driver doesn't send the process a SIGWINCH when the terminal size
+ changes.
+
+ The new gl_bind_keyseq() function provides a convenient
+ alternative to gl_configure_getline(), for binding or unbinding
+ one key-sequence at a time.
+
+ gl_get_line()s signal handling, file-descriptor event-handling,
+ inactivity-timeout handling and server-mode non-blocking I/O
+ features now not only work when input is coming from a terminal, but
+ now also work when input is coming from non-interactive streams,
+ such as files and pipes.
+
+ The history implementation has been re-written to make it more
+ efficient and easier to modify. The biggest user-level change is
+ that when recalling history lines using a search prefix, the same
+ line is no longer returned more than once in a row. Previously this
+ duplicate elimination only worked when one was recalling a line
+ without specifying a search prefix, and this was naively performed
+ by preventing neighboring duplicates from existing in the history
+ list, rather than by skipping duplicates at search time.
+
+ In previous versions of the library, when gl_get_line() and its
+ associated public functions detected invalid arguments, or couldn't
+ allocate memory, etc, error messages were written to stderr. This
+ isn't appropriate for library functions, so instead of writing such
+ messages to stderr, these messages are now recorded in buffers
+ within the affected GetLine object. The latest error message can
+ then subsequently be queried by calling gl_error_message(). The use
+ of errno has also been expanded, and a new function called
+ gl_return_status() has been provided to expand on the cause of the
+ last return from gl_get_line().
+
+ User level usage and configuration information has now been split
+ out of the gl_get_line(3) man page into a separate tecla(7) man
+ page. The enhance(3) man page has also been renamed to enhance(1).
+
+ When expanding "~/", gl_get_line() now checks for, and returns the
+ value of the HOME environment variable, if it exists, in preference
+ to looking up the directory of the current user in the password
+ file.
+
+ When the terminal was resized to a narrower width, previous versions
+ of gl_get_line() would redraw the line higher up the terminal. This
+ bug has been fixed. A bug in history recall has also been fixed, in
+ which an error message was being generated if one attempted to
+ recall a line while the cursor was at the end of the longest
+ possible input line. A more serious bug, in which callbacks
+ registered by gl_watch_fd() weren't being called for write-events,
+ has also been fixed. Finally, a few minor fixes have been made to
+ improve support under QNX and Mac OS X.
+
+ Beware that in this release, much of the underlying code has
+ undergone some radical re-work, so although backwards compatibility
+ of all documented features has been preserved, there may be some
+ lingering bugs that could break existing programs. So, if you plan
+ to use this version in production code, please test it as far as
+ possible within your application before releasing it to your
+ clients, and as always, please report any unexpected behavior.
+
Version 1.4.1:
This is a maintenance release. It includes minor changes to support
diff --git a/libtecla-1.6.1/chrqueue.c b/libtecla-1.6.1/chrqueue.c
new file mode 100644
index 0000000..346e8f6
--- /dev/null
+++ b/libtecla-1.6.1/chrqueue.c
@@ -0,0 +1,432 @@
+/*
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
+ *
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, and/or sell copies of the Software, and to permit persons
+ * to whom the Software is furnished to do so, provided that the above
+ * copyright notice(s) and this permission notice appear in all copies of
+ * the Software and that both the above copyright notice(s) and this
+ * permission notice appear in supporting documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+ * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
+ * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder
+ * shall not be used in advertising or otherwise to promote the sale, use
+ * or other dealings in this Software without prior written authorization
+ * of the copyright holder.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "ioutil.h"
+#include "chrqueue.h"
+#include "freelist.h"
+#include "errmsg.h"
+
+/*
+ * Set the number of bytes allocated to each node of the list of
+ * character buffers. This facility is designed principally as
+ * an expandible I/O output buffer, so use the stdio buffer size
+ * where available.
+ */
+#ifdef BUFSIZ
+#define GL_CQ_SIZE BUFSIZ
+#else
+#define GL_CQ_SIZE 512
+#endif
+
+/*
+ * The queue is contained in a list of fixed sized buffers. New nodes
+ * are appended to this list as needed to accomodate newly added bytes.
+ * Old nodes at the head of the list are removed as they are emptied.
+ */
+typedef struct CqCharBuff CqCharBuff;
+struct CqCharBuff {
+ CqCharBuff *next; /* The next node in the list of buffers */
+ char bytes[GL_CQ_SIZE]; /* The fixed size buffer of this node */
+};
+
+/*
+ * Define the structure that is used to contain a list of character
+ * buffers.
+ */
+struct GlCharQueue {
+ ErrMsg *err; /* A buffer in which to record error messages */
+ FreeList *bufmem; /* A free-list of CqCharBuff structures */
+ struct {
+ CqCharBuff *head; /* The head of the list of output buffers */
+ CqCharBuff *tail; /* The tail of the list of output buffers */
+ } buffers;
+ int nflush; /* The total number of characters that have been */
+ /* flushed from the start of the queue since */
+ /* _glq_empty_queue() was last called. */
+ int ntotal; /* The total number of characters that have been */
+ /* appended to the queue since _glq_empty_queue() */
+ /* was last called. */
+};
+
+/*.......................................................................
+ * Create a new GlCharQueue object.
+ *
+ * Output:
+ * return GlCharQueue * The new object, or NULL on error.
+ */
+GlCharQueue *_new_GlCharQueue(void)
+{
+ GlCharQueue *cq; /* The object to be returned */
+/*
+ * Allocate the container.
+ */
+ cq = malloc(sizeof(GlCharQueue));
+ if(!cq) {
+ errno = ENOMEM;
+ return NULL;
+ };
+/*
+ * Before attempting any operation that might fail, initialize the
+ * container at least up to the point at which it can safely be passed
+ * to del_GlCharQueue().
+ */
+ cq->err = NULL;
+ cq->bufmem = NULL;
+ cq->buffers.head = NULL;
+ cq->buffers.tail = NULL;
+ cq->nflush = cq->ntotal = 0;
+/*
+ * Allocate a place to record error messages.
+ */
+ cq->err = _new_ErrMsg();
+ if(!cq->err)
+ return _del_GlCharQueue(cq);
+/*
+ * Allocate the freelist of CqCharBuff structures.
+ */
+ cq->bufmem = _new_FreeList(sizeof(CqCharBuff), 1);
+ if(!cq->bufmem)
+ return _del_GlCharQueue(cq);
+ return cq;
+}
+
+/*.......................................................................
+ * Delete a GlCharQueue object.
+ *
+ * Input:
+ * cq GlCharQueue * The object to be deleted.
+ * Output:
+ * return GlCharQueue * The deleted object (always NULL).
+ */
+GlCharQueue *_del_GlCharQueue(GlCharQueue *cq)
+{
+ if(cq) {
+ cq->err = _del_ErrMsg(cq->err);
+ cq->bufmem = _del_FreeList(cq->bufmem, 1);
+ free(cq);
+ };
+ return NULL;
+}
+
+/*.......................................................................
+ * Append an array of n characters to a character queue.
+ *
+ * Input:
+ * cq GlCharQueue * The queue to append to.
+ * chars const char * The array of n characters to be appended.
+ * n int The number of characters in chars[].
+ * write_fn GL_WRITE_FN * The function to call to output characters,
+ * or 0 to simply discard the contents of the
+ * queue. This will be called whenever the
+ * buffer becomes full. If it fails to release
+ * any space, the buffer will be extended.
+ * data void * Anonymous data to pass to write_fn().
+ * Output:
+ * return int The number of characters successfully
+ * appended. This will only be < n on error.
+ */
+int _glq_append_chars(GlCharQueue *cq, const char *chars, int n,
+ GlWriteFn *write_fn, void *data)
+{
+ int ndone = 0; /* The number of characters appended so far */
+/*
+ * Check the arguments.
+ */
+ if(!cq || !chars) {
+ errno = EINVAL;
+ return 0;
+ };
+/*
+ * The appended characters may have to be split between multiple
+ * buffers, so loop for each buffer.
+ */
+ while(ndone < n) {
+ int ntodo; /* The number of characters remaining to be appended */
+ int nleft; /* The amount of space remaining in cq->buffers.tail */
+ int nnew; /* The number of characters to append to cq->buffers.tail */
+/*
+ * Compute the offset at which the next character should be written
+ * into the tail buffer segment.
+ */
+ int boff = cq->ntotal % GL_CQ_SIZE;
+/*
+ * Since we don't allocate a new buffer until we have at least one
+ * character to write into it, if boff is 0 at this point, it means
+ * that we hit the end of the tail buffer segment on the last append,
+ * so we need to allocate a new one.
+ *
+ * If allocating this new node will require a call to malloc(), as
+ * opposed to using a currently unused node in the freelist, first try
+ * flushing the current contents of the buffer to the terminal. When
+ * write_fn() uses blocking I/O, this stops the buffer size ever getting
+ * bigger than a single buffer node. When it is non-blocking, it helps
+ * to keep the amount of memory, but it isn't gauranteed to do so.
+ */
+ if(boff == 0 && _idle_FreeListNodes(cq->bufmem) == 0) {
+ switch(_glq_flush_queue(cq, write_fn, data)) {
+ case GLQ_FLUSH_DONE:
+ break;
+ case GLQ_FLUSH_AGAIN:
+ errno = 0; /* Don't confuse the caller */
+ break;
+ default:
+ return ndone; /* Error */
+ };
+ boff = cq->ntotal % GL_CQ_SIZE;
+ };
+/*
+ * Since we don't allocate a new buffer until we have at least one
+ * character to write into it, if boff is 0 at this point, it means
+ * that we hit the end of the tail buffer segment on the last append,
+ * so we need to allocate a new one.
+ */
+ if(boff == 0) {
+/*
+ * Allocate the new node.
+ */
+ CqCharBuff *node = (CqCharBuff *) _new_FreeListNode(cq->bufmem);
+ if(!node) {
+ _err_record_msg(cq->err, "Insufficient memory to buffer output.",
+ END_ERR_MSG);
+ return ndone;
+ };
+/*
+ * Initialize the node.
+ */
+ node->next = NULL;
+/*
+ * Append the new node to the tail of the list.
+ */
+ if(cq->buffers.tail)
+ cq->buffers.tail->next = node;
+ else
+ cq->buffers.head = node;
+ cq->buffers.tail = node;
+ };
+/*
+ * How much room is there for new characters in the current tail node?
+ */
+ nleft = GL_CQ_SIZE - boff;
+/*
+ * How many characters remain to be appended?
+ */
+ ntodo = n - ndone;
+/*
+ * How many characters should we append to the current tail node?
+ */
+ nnew = nleft < ntodo ? nleft : ntodo;
+/*
+ * Append the latest prefix of nnew characters.
+ */
+ memcpy(cq->buffers.tail->bytes + boff, chars + ndone, nnew);
+ cq->ntotal += nnew;
+ ndone += nnew;
+ };
+/*
+ * Return the count of the number of characters successfully appended.
+ */
+ return ndone;
+}
+
+/*.......................................................................
+ * Discard the contents of a queue of characters.
+ *
+ * Input:
+ * cq GlCharQueue * The queue to clear.
+ */
+void _glq_empty_queue(GlCharQueue *cq)
+{
+ if(cq) {
+/*
+ * Return all list nodes to their respective free-lists.
+ */
+ _rst_FreeList(cq->bufmem);
+/*
+ * Mark the lists as empty.
+ */
+ cq->buffers.head = cq->buffers.tail = NULL;
+ cq->nflush = cq->ntotal = 0;
+ };
+}
+
+/*.......................................................................
+ * Return a count of the number of characters currently in the queue.
+ *
+ * Input:
+ * cq GlCharQueue * The queue of interest.
+ * Output:
+ * return int The number of characters in the queue.
+ */
+int _glq_char_count(GlCharQueue *cq)
+{
+ return (cq && cq->buffers.head) ? (cq->ntotal - cq->nflush) : 0;
+}
+
+/*.......................................................................
+ * Write as many characters as possible from the start of a character
+ * queue via a given output callback function, removing those written
+ * from the queue.
+ *
+ * Input:
+ * cq GlCharQueue * The queue to write characters from.
+ * write_fn GL_WRITE_FN * The function to call to output characters,
+ * or 0 to simply discard the contents of the
+ * queue.
+ * data void * Anonymous data to pass to write_fn().
+ * Output:
+ * return GlFlushState The status of the flush operation:
+ * GLQ_FLUSH_DONE - The flush operation
+ * completed successfully.
+ * GLQ_FLUSH_AGAIN - The flush operation
+ * couldn't be completed
+ * on this call. Call this
+ * function again when the
+ * output channel can accept
+ * further output.
+ * GLQ_FLUSH_ERROR Unrecoverable error.
+ */
+GlqFlushState _glq_flush_queue(GlCharQueue *cq, GlWriteFn *write_fn,
+ void *data)
+{
+/*
+ * Check the arguments.
+ */
+ if(!cq) {
+ errno = EINVAL;
+ return GLQ_FLUSH_ERROR;
+ };
+/*
+ * If possible keep writing until all of the chained buffers have been
+ * emptied and removed from the list.
+ */
+ while(cq->buffers.head) {
+/*
+ * Are we looking at the only node in the list?
+ */
+ int is_tail = cq->buffers.head == cq->buffers.tail;
+/*
+ * How many characters more than an exact multiple of the buffer-segment
+ * size have been added to the buffer so far?
+ */
+ int nmodulo = cq->ntotal % GL_CQ_SIZE;
+/*
+ * How many characters of the buffer segment at the head of the list
+ * have been used? Note that this includes any characters that have
+ * already been flushed. Also note that if nmodulo==0, this means that
+ * the tail buffer segment is full. The reason for this is that we
+ * don't allocate new tail buffer segments until there is at least one
+ * character to be added to them.
+ */
+ int nhead = (!is_tail || nmodulo == 0) ? GL_CQ_SIZE : nmodulo;
+/*
+ * How many characters remain to be flushed from the buffer
+ * at the head of the list?
+ */
+ int nbuff = nhead - (cq->nflush % GL_CQ_SIZE);
+/*
+ * Attempt to write this number.
+ */
+ int nnew = write_fn(data, cq->buffers.head->bytes +
+ cq->nflush % GL_CQ_SIZE, nbuff);
+/*
+ * Was anything written?
+ */
+ if(nnew > 0) {
+/*
+ * Increment the count of the number of characters that have
+ * been flushed from the head of the queue.
+ */
+ cq->nflush += nnew;
+/*
+ * If we succeded in writing all of the contents of the current
+ * buffer segment, remove it from the queue.
+ */
+ if(nnew == nbuff) {
+/*
+ * If we just emptied the last node left in the list, then the queue is
+ * now empty and should be reset.
+ */
+ if(is_tail) {
+ _glq_empty_queue(cq);
+ } else {
+/*
+ * Get the node to be removed from the head of the list.
+ */
+ CqCharBuff *node = cq->buffers.head;
+/*
+ * Make the node that follows it the new head of the queue.
+ */
+ cq->buffers.head = node->next;
+/*
+ * Return it to the freelist.
+ */
+ node = (CqCharBuff *) _del_FreeListNode(cq->bufmem, node);
+ };
+ };
+/*
+ * If the write blocked, request that this function be called again
+ * when space to write next becomes available.
+ */
+ } else if(nnew==0) {
+ return GLQ_FLUSH_AGAIN;
+/*
+ * I/O error.
+ */
+ } else {
+ _err_record_msg(cq->err, "Error writing to terminal", END_ERR_MSG);
+ return GLQ_FLUSH_ERROR;
+ };
+ };
+/*
+ * To get here the queue must now be empty.
+ */
+ return GLQ_FLUSH_DONE;
+}
+
+/*.......................................................................
+ * Return extra information (ie. in addition to that provided by errno)
+ * about the last error to occur in any of the public functions of this
+ * module.
+ *
+ * Input:
+ * cq GlCharQueue * The container of the history list.
+ * Output:
+ * return const char * A pointer to the internal buffer in which
+ * the error message is temporarily stored.
+ */
+const char *_glq_last_error(GlCharQueue *cq)
+{
+ return cq ? _err_get_msg(cq->err) : "NULL GlCharQueue argument";
+}
diff --git a/libtecla-1.6.1/chrqueue.h b/libtecla-1.6.1/chrqueue.h
new file mode 100644
index 0000000..1aca8e0
--- /dev/null
+++ b/libtecla-1.6.1/chrqueue.h
@@ -0,0 +1,106 @@
+#ifndef chrqueue_h
+#define chrqueue_h
+
+/*
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
+ *
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, and/or sell copies of the Software, and to permit persons
+ * to whom the Software is furnished to do so, provided that the above
+ * copyright notice(s) and this permission notice appear in all copies of
+ * the Software and that both the above copyright notice(s) and this
+ * permission notice appear in supporting documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+ * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
+ * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder
+ * shall not be used in advertising or otherwise to promote the sale, use
+ * or other dealings in this Software without prior written authorization
+ * of the copyright holder.
+ */
+
+/*-----------------------------------------------------------------------
+ * This module implements a queue of characters to be processed in some
+ * way. It is used by gl_get_line() to maintain a queue of characters
+ * to be sent to a remote terminal. Characters are recorded in a
+ * dynamically extensible list of fixed sized buffers.
+ */
+
+typedef struct GlCharQueue GlCharQueue;
+
+/*
+ * Create a new character queue.
+ */
+GlCharQueue *_new_GlCharQueue(void);
+
+/*
+ * Delete a redundant character queue.
+ */
+GlCharQueue *_del_GlCharQueue(GlCharQueue *cq);
+
+/*
+ * Append an array of n characters to a character queue.
+ */
+int _glq_append_chars(GlCharQueue *cq, const char *chars, int n,
+ GlWriteFn *write_fn, void *data);
+
+/*
+ * Clear a character queue.
+ */
+void _glq_empty_queue(GlCharQueue *cq);
+
+/*
+ * Return a count of the number of characters in the queue.
+ */
+int _glq_char_count(GlCharQueue *cq);
+
+/*
+ * A structure of the following type is used by _glq_peek_chars() to
+ * return characters at the start of the queue.
+ */
+typedef struct {
+ const char *buff; /* A pointer to the first undeleted byte in the */
+ /* first buffer of the queue. */
+ int nbuff; /* The number of characters in buff[] */
+} GlCharQueueBuff;
+
+/*
+ * Enumerator values of the following type are returned by
+ * _glq_flush_queue() to indicate the status of the flush operation.
+ */
+typedef enum {
+ GLQ_FLUSH_DONE, /* The flush operation completed successfully */
+ GLQ_FLUSH_AGAIN, /* The flush operation couldn't be completed on this */
+ /* call. Call this function again when the output */
+ /* channel can accept further output. */
+ GLQ_FLUSH_ERROR /* Unrecoverable error. */
+} GlqFlushState;
+
+/*
+ * Transfer as much of the contents of a character queue to an output
+ * channel as possible, returning before the queue is empty if the
+ * write_fn() callback says that it can't currently write anymore.
+ */
+GlqFlushState _glq_flush_queue(GlCharQueue *cq, GlWriteFn *write_fn,
+ void *data);
+
+/*
+ * Provide information about the last error that occurred while calling
+ * any of the above functions.
+ */
+const char *_glq_last_error(GlCharQueue *cq);
+
+#endif
diff --git a/libtecla-1.4.1/config.guess b/libtecla-1.6.1/config.guess
index 0ce538b..500ee74 100644
--- a/libtecla-1.4.1/config.guess
+++ b/libtecla-1.6.1/config.guess
@@ -1,8 +1,10 @@
#! /bin/sh
# Attempt to guess a canonical system name.
-# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000
-# Free Software Foundation, Inc.
-#
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+
+timestamp='2003-10-03'
+
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
@@ -22,147 +24,268 @@
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
-# Written by Per Bothner <bothner@cygnus.com>.
-# Please send patches to <config-patches@gnu.org>.
+# Originally written by Per Bothner <per@bothner.com>.
+# Please send patches to <config-patches@gnu.org>. Submit a context
+# diff and a properly formatted ChangeLog entry.
#
# This script attempts to guess a canonical system name similar to
# config.sub. If it succeeds, it prints the system name on stdout, and
# exits with 0. Otherwise, it exits with 1.
#
# The plan is that this can be called by configure scripts if you
-# don't specify an explicit system type (host/target name).
-#
-# Only a few systems have been added to this list; please add others
-# (but try to keep the structure clean).
-#
+# don't specify an explicit build system type.
-# Use $HOST_CC if defined. $CC may point to a cross-compiler
-if test x"$CC_FOR_BUILD" = x; then
- if test x"$HOST_CC" != x; then
- CC_FOR_BUILD="$HOST_CC"
- else
- if test x"$CC" != x; then
- CC_FOR_BUILD="$CC"
- else
- CC_FOR_BUILD=cc
- fi
- fi
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit 0 ;;
+ --version | -v )
+ echo "$version" ; exit 0 ;;
+ --help | --h* | -h )
+ echo "$usage"; exit 0 ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help" >&2
+ exit 1 ;;
+ * )
+ break ;;
+ esac
+done
+
+if test $# != 0; then
+ echo "$me: too many arguments$help" >&2
+ exit 1
fi
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,) echo "int x;" > $dummy.c ;
+ for c in cc gcc c89 c99 ; do
+ if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+ CC_FOR_BUILD="$c"; break ;
+ fi ;
+ done ;
+ if test x"$CC_FOR_BUILD" = x ; then
+ CC_FOR_BUILD=no_compiler_found ;
+ fi
+ ;;
+ ,,*) CC_FOR_BUILD=$CC ;;
+ ,*,*) CC_FOR_BUILD=$HOST_CC ;;
+esac ;'
# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
-# (ghazi@noc.rutgers.edu 8/24/94.)
+# (ghazi@noc.rutgers.edu 1994-08-24)
if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
PATH=$PATH:/.attbin ; export PATH
fi
UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
-UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
-dummy=dummy-$$
-trap 'rm -f $dummy.c $dummy.o $dummy; exit 1' 1 2 15
-
# Note: order is significant - the case branches are not exclusive.
case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
*:NetBSD:*:*)
- # Netbsd (nbsd) targets should (where applicable) match one or
+ # NetBSD (nbsd) targets should (where applicable) match one or
# more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
# *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
# switched to ELF, *-*-netbsd* would select the old
# object file format. This provides both forward
# compatibility and a consistent mechanism for selecting the
# object file format.
- # Determine the machine/vendor (is the vendor relevant).
- case "${UNAME_MACHINE}" in
- amiga) machine=m68k-cbm ;;
- arm32) machine=arm-unknown ;;
- atari*) machine=m68k-atari ;;
- sun3*) machine=m68k-sun ;;
- mac68k) machine=m68k-apple ;;
- macppc) machine=powerpc-apple ;;
- hp3[0-9][05]) machine=m68k-hp ;;
- ibmrt|romp-ibm) machine=romp-ibm ;;
- *) machine=${UNAME_MACHINE}-unknown ;;
+ #
+ # Note: NetBSD doesn't particularly care about the vendor
+ # portion of the name. We always set it to "unknown".
+ sysctl="sysctl -n hw.machine_arch"
+ UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+ /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+ case "${UNAME_MACHINE_ARCH}" in
+ armeb) machine=armeb-unknown ;;
+ arm*) machine=arm-unknown ;;
+ sh3el) machine=shl-unknown ;;
+ sh3eb) machine=sh-unknown ;;
+ *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+ esac
+ # The Operating System including object format, if it has switched
+ # to ELF recently, or will in the future.
+ case "${UNAME_MACHINE_ARCH}" in
+ arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+ eval $set_cc_for_build
+ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep __ELF__ >/dev/null
+ then
+ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+ # Return netbsd for either. FIX?
+ os=netbsd
+ else
+ os=netbsdelf
+ fi
+ ;;
+ *)
+ os=netbsd
+ ;;
esac
- # The Operating System including object format.
- if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
- | grep __ELF__ >/dev/null
- then
- # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
- # Return netbsd for either. FIX?
- os=netbsd
- else
- os=netbsdelf
- fi
# The OS release
- release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ # Debian GNU/NetBSD machines have a different userland, and
+ # thus, need a distinct triplet. However, they do not need
+ # kernel version information, so it can be replaced with a
+ # suitable tag, in the style of linux-gnu.
+ case "${UNAME_VERSION}" in
+ Debian*)
+ release='-gnu'
+ ;;
+ *)
+ release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ ;;
+ esac
# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
# contains redundant information, the shorter form:
# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
echo "${machine}-${os}${release}"
exit 0 ;;
+ amiga:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ arc:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ hp300:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mac68k:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ macppc:OpenBSD:*:*)
+ echo powerpc-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvme68k:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvme88k:OpenBSD:*:*)
+ echo m88k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvmeppc:OpenBSD:*:*)
+ echo powerpc-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ pmax:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sgi:OpenBSD:*:*)
+ echo mipseb-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sun3:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ wgrisc:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ *:OpenBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
alpha:OSF1:*:*)
if test $UNAME_RELEASE = "V4.0"; then
UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
fi
+ # According to Compaq, /usr/sbin/psrinfo has been available on
+ # OSF/1 and Tru64 systems produced since 1995. I hope that
+ # covers most systems running today. This code pipes the CPU
+ # types through head -n 1, so we only detect the type of CPU 0.
+ ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+ case "$ALPHA_CPU_TYPE" in
+ "EV4 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "EV4.5 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "LCA4 (21066/21068)")
+ UNAME_MACHINE="alpha" ;;
+ "EV5 (21164)")
+ UNAME_MACHINE="alphaev5" ;;
+ "EV5.6 (21164A)")
+ UNAME_MACHINE="alphaev56" ;;
+ "EV5.6 (21164PC)")
+ UNAME_MACHINE="alphapca56" ;;
+ "EV5.7 (21164PC)")
+ UNAME_MACHINE="alphapca57" ;;
+ "EV6 (21264)")
+ UNAME_MACHINE="alphaev6" ;;
+ "EV6.7 (21264A)")
+ UNAME_MACHINE="alphaev67" ;;
+ "EV6.8CB (21264C)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8AL (21264B)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8CX (21264D)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.9A (21264/EV69A)")
+ UNAME_MACHINE="alphaev69" ;;
+ "EV7 (21364)")
+ UNAME_MACHINE="alphaev7" ;;
+ "EV7.9 (21364A)")
+ UNAME_MACHINE="alphaev79" ;;
+ esac
# A Vn.n version is a released version.
# A Tn.n version is a released field test version.
# A Xn.n version is an unreleased experimental baselevel.
# 1.2 uses "1.2" for uname -r.
- cat <<EOF >$dummy.s
- .data
-\$Lformat:
- .byte 37,100,45,37,120,10,0 # "%d-%x\n"
-
- .text
- .globl main
- .align 4
- .ent main
-main:
- .frame \$30,16,\$26,0
- ldgp \$29,0(\$27)
- .prologue 1
- .long 0x47e03d80 # implver \$0
- lda \$2,-1
- .long 0x47e20c21 # amask \$2,\$1
- lda \$16,\$Lformat
- mov \$0,\$17
- not \$1,\$18
- jsr \$26,printf
- ldgp \$29,0(\$26)
- mov 0,\$16
- jsr \$26,exit
- .end main
-EOF
- $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null
- if test "$?" = 0 ; then
- case `./$dummy` in
- 0-0)
- UNAME_MACHINE="alpha"
- ;;
- 1-0)
- UNAME_MACHINE="alphaev5"
- ;;
- 1-1)
- UNAME_MACHINE="alphaev56"
- ;;
- 1-101)
- UNAME_MACHINE="alphapca56"
- ;;
- 2-303)
- UNAME_MACHINE="alphaev6"
- ;;
- 2-307)
- UNAME_MACHINE="alphaev67"
- ;;
- esac
- fi
- rm -f $dummy.s $dummy
echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
exit 0 ;;
+ Alpha*:OpenVMS:*:*)
+ echo alpha-hp-vms
+ exit 0 ;;
Alpha\ *:Windows_NT*:*)
# How do we know it's Interix rather than the generic POSIX subsystem?
# Should we change UNAME_MACHINE based on the output of uname instead
@@ -173,31 +296,13 @@ EOF
echo alpha-dec-winnt3.5
exit 0 ;;
Amiga*:UNIX_System_V:4.0:*)
- echo m68k-cbm-sysv4
+ echo m68k-unknown-sysv4
exit 0;;
- amiga:OpenBSD:*:*)
- echo m68k-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
*:[Aa]miga[Oo][Ss]:*:*)
echo ${UNAME_MACHINE}-unknown-amigaos
exit 0 ;;
- arc64:OpenBSD:*:*)
- echo mips64el-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- arc:OpenBSD:*:*)
- echo mipsel-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- hkmips:OpenBSD:*:*)
- echo mips-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- pmax:OpenBSD:*:*)
- echo mipsel-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- sgi:OpenBSD:*:*)
- echo mips-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- wgrisc:OpenBSD:*:*)
- echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ *:[Mm]orph[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-morphos
exit 0 ;;
*:OS/390:*:*)
echo i370-ibm-openedition
@@ -205,7 +310,7 @@ EOF
arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
echo arm-acorn-riscix${UNAME_RELEASE}
exit 0;;
- SR2?01:HI-UX/MPP:*:*)
+ SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
echo hppa1.1-hitachi-hiuxmpp
exit 0;;
Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
@@ -219,6 +324,13 @@ EOF
NILE*:*:*:dcosx)
echo pyramid-pyramid-svr4
exit 0 ;;
+ DRS?6000:unix:4.0:6*)
+ echo sparc-icl-nx6
+ exit 0 ;;
+ DRS?6000:UNIX_SV:4.2*:7*)
+ case `/usr/bin/uname -p` in
+ sparc) echo sparc-icl-nx7 && exit 0 ;;
+ esac ;;
sun4H:SunOS:5.*:*)
echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
exit 0 ;;
@@ -247,7 +359,7 @@ EOF
echo m68k-sun-sunos${UNAME_RELEASE}
exit 0 ;;
sun*:*:4.2BSD:*)
- UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
case "`/bin/arch`" in
sun3)
@@ -261,9 +373,6 @@ EOF
aushp:SunOS:*:*)
echo sparc-auspex-sunos${UNAME_RELEASE}
exit 0 ;;
- atari*:OpenBSD:*:*)
- echo m68k-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
# The situation for MiNT is a little confusing. The machine name
# can be virtually everything (everything which is not
# "atarist" or "atariste" at least should have a processor
@@ -290,18 +399,6 @@ EOF
*:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
echo m68k-unknown-mint${UNAME_RELEASE}
exit 0 ;;
- sun3*:OpenBSD:*:*)
- echo m68k-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- mac68k:OpenBSD:*:*)
- echo m68k-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- mvme68k:OpenBSD:*:*)
- echo m68k-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- mvme88k:OpenBSD:*:*)
- echo m88k-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
powerpc:machten:*:*)
echo powerpc-apple-machten${UNAME_RELEASE}
exit 0 ;;
@@ -318,6 +415,7 @@ EOF
echo clipper-intergraph-clix${UNAME_RELEASE}
exit 0 ;;
mips:*:*:UMIPS | mips:*:*:RISCos)
+ eval $set_cc_for_build
sed 's/^ //' << EOF >$dummy.c
#ifdef __cplusplus
#include <stdio.h> /* for printf() prototype */
@@ -339,12 +437,20 @@ EOF
exit (-1);
}
EOF
- $CC_FOR_BUILD $dummy.c -o $dummy \
- && ./$dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
- && rm $dummy.c $dummy && exit 0
- rm -f $dummy.c $dummy
+ $CC_FOR_BUILD -o $dummy $dummy.c \
+ && $dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
+ && exit 0
echo mips-mips-riscos${UNAME_RELEASE}
exit 0 ;;
+ Motorola:PowerMAX_OS:*:*)
+ echo powerpc-motorola-powermax
+ exit 0 ;;
+ Motorola:*:4.3:PL8-*)
+ echo powerpc-harris-powermax
+ exit 0 ;;
+ Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+ echo powerpc-harris-powermax
+ exit 0 ;;
Night_Hawk:Power_UNIX:*:*)
echo powerpc-harris-powerunix
exit 0 ;;
@@ -392,11 +498,20 @@ EOF
????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX '
- i?86:AIX:*:*)
+ i*86:AIX:*:*)
echo i386-ibm-aix
exit 0 ;;
+ ia64:AIX:*:*)
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+ exit 0 ;;
*:AIX:2:3)
if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ eval $set_cc_for_build
sed 's/^ //' << EOF >$dummy.c
#include <sys/systemcfg.h>
@@ -408,8 +523,7 @@ EOF
exit(0);
}
EOF
- $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0
- rm -f $dummy.c $dummy
+ $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0
echo rs6000-ibm-aix3.2.5
elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
echo rs6000-ibm-aix3.2.4
@@ -417,9 +531,9 @@ EOF
echo rs6000-ibm-aix3.2
fi
exit 0 ;;
- *:AIX:*:4)
- IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'`
- if /usr/sbin/lsattr -EHl ${IBM_CPU_ID} | grep POWER >/dev/null 2>&1; then
+ *:AIX:*:[45])
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
IBM_ARCH=rs6000
else
IBM_ARCH=powerpc
@@ -427,7 +541,7 @@ EOF
if [ -x /usr/bin/oslevel ] ; then
IBM_REV=`/usr/bin/oslevel`
else
- IBM_REV=4.${UNAME_RELEASE}
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
fi
echo ${IBM_ARCH}-ibm-aix${IBM_REV}
exit 0 ;;
@@ -453,11 +567,28 @@ EOF
echo m68k-hp-bsd4.4
exit 0 ;;
9000/[34678]??:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
case "${UNAME_MACHINE}" in
9000/31? ) HP_ARCH=m68000 ;;
9000/[34]?? ) HP_ARCH=m68k ;;
9000/[678][0-9][0-9])
- sed 's/^ //' << EOF >$dummy.c
+ if [ -x /usr/bin/getconf ]; then
+ sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+ case "${sc_cpu_version}" in
+ 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+ 532) # CPU_PA_RISC2_0
+ case "${sc_kernel_bits}" in
+ 32) HP_ARCH="hppa2.0n" ;;
+ 64) HP_ARCH="hppa2.0w" ;;
+ '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
+ esac ;;
+ esac
+ fi
+ if [ "${HP_ARCH}" = "" ]; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
#define _HPUX_SOURCE
#include <stdlib.h>
@@ -490,13 +621,29 @@ EOF
exit (0);
}
EOF
- (CCOPTS= $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null ) && HP_ARCH=`./$dummy`
- rm -f $dummy.c $dummy
+ (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+ test -z "$HP_ARCH" && HP_ARCH=hppa
+ fi ;;
esac
- HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ if [ ${HP_ARCH} = "hppa2.0w" ]
+ then
+ # avoid double evaluation of $set_cc_for_build
+ test -n "$CC_FOR_BUILD" || eval $set_cc_for_build
+ if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E -) | grep __LP64__ >/dev/null
+ then
+ HP_ARCH="hppa2.0w"
+ else
+ HP_ARCH="hppa64"
+ fi
+ fi
echo ${HP_ARCH}-hp-hpux${HPUX_REV}
exit 0 ;;
+ ia64:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ia64-hp-hpux${HPUX_REV}
+ exit 0 ;;
3050*:HI-UX:*:*)
+ eval $set_cc_for_build
sed 's/^ //' << EOF >$dummy.c
#include <unistd.h>
int
@@ -522,8 +669,7 @@ EOF
exit (0);
}
EOF
- $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0
- rm -f $dummy.c $dummy
+ $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0
echo unknown-hitachi-hiuxwe2
exit 0 ;;
9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
@@ -532,7 +678,7 @@ EOF
9000/8??:4.3bsd:*:*)
echo hppa1.0-hp-bsd
exit 0 ;;
- *9??*:MPE/iX:*:*)
+ *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
echo hppa1.0-hp-mpeix
exit 0 ;;
hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
@@ -541,7 +687,7 @@ EOF
hp8??:OSF1:*:*)
echo hppa1.0-hp-osf
exit 0 ;;
- i?86:OSF1:*:*)
+ i*86:OSF1:*:*)
if [ -x /usr/sbin/sysversion ] ; then
echo ${UNAME_MACHINE}-unknown-osf1mk
else
@@ -551,9 +697,6 @@ EOF
parisc*:Lites*:*:*)
echo hppa1.1-hp-lites
exit 0 ;;
- hppa*:OpenBSD:*:*)
- echo hppa-unknown-openbsd
- exit 0 ;;
C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
echo c1-convex-bsd
exit 0 ;;
@@ -572,41 +715,34 @@ EOF
C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
echo c4-convex-bsd
exit 0 ;;
- CRAY*X-MP:*:*:*)
- echo xmp-cray-unicos
- exit 0 ;;
CRAY*Y-MP:*:*:*)
- echo ymp-cray-unicos${UNAME_RELEASE}
+ echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
exit 0 ;;
CRAY*[A-Z]90:*:*:*)
echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
- -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+ -e 's/\.[^.]*$/.X/'
exit 0 ;;
CRAY*TS:*:*:*)
echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
exit 0 ;;
CRAY*T3E:*:*:*)
- echo alpha-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
exit 0 ;;
CRAY*SV1:*:*:*)
echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
exit 0 ;;
- CRAY-2:*:*:*)
- echo cray2-cray-unicos
- exit 0 ;;
- F300:UNIX_System_V:*:*)
+ *:UNICOS/mp:*:*)
+ echo nv1-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+ FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
- echo "f300-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
exit 0 ;;
- F301:UNIX_System_V:*:*)
- echo f301-fujitsu-uxpv`echo $UNAME_RELEASE | sed 's/ .*//'`
- exit 0 ;;
- hp300:OpenBSD:*:*)
- echo m68k-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- i?86:BSD/386:*:* | i?86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
exit 0 ;;
sparc*:BSD/OS:*:*)
@@ -615,11 +751,22 @@ EOF
*:BSD/OS:*:*)
echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
exit 0 ;;
- *:FreeBSD:*:*)
- echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
- exit 0 ;;
- *:OpenBSD:*:*)
- echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ *:FreeBSD:*:*|*:GNU/FreeBSD:*:*)
+ # Determine whether the default compiler uses glibc.
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <features.h>
+ #if __GLIBC__ >= 2
+ LIBC=gnu
+ #else
+ LIBC=
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
+ # GNU/FreeBSD systems have a "k" prefix to indicate we are using
+ # FreeBSD's kernel, but not the complete OS.
+ case ${LIBC} in gnu) kernel_only='k' ;; esac
+ echo ${UNAME_MACHINE}-unknown-${kernel_only}freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`${LIBC:+-$LIBC}
exit 0 ;;
i*:CYGWIN*:*)
echo ${UNAME_MACHINE}-pc-cygwin
@@ -627,11 +774,20 @@ EOF
i*:MINGW*:*)
echo ${UNAME_MACHINE}-pc-mingw32
exit 0 ;;
+ i*:PW*:*)
+ echo ${UNAME_MACHINE}-pc-pw32
+ exit 0 ;;
+ x86:Interix*:[34]*)
+ echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//'
+ exit 0 ;;
+ [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+ echo i${UNAME_MACHINE}-pc-mks
+ exit 0 ;;
i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
# How do we know it's Interix rather than the generic POSIX subsystem?
# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
# UNAME_MACHINE based on the output of uname instead of i386?
- echo i386-pc-interix
+ echo i586-pc-interix
exit 0 ;;
i*:UWIN*:*)
echo ${UNAME_MACHINE}-pc-uwin
@@ -645,219 +801,168 @@ EOF
*:GNU:*:*)
echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
exit 0 ;;
- *:Linux:*:*)
-
+ i*86:Minix:*:*)
+ echo ${UNAME_MACHINE}-pc-minix
+ exit 0 ;;
+ arm*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ cris:Linux:*:*)
+ echo cris-axis-linux-gnu
+ exit 0 ;;
+ ia64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ m68*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ mips:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef mips
+ #undef mipsel
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=mipsel
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=mips
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=`
+ test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0
+ ;;
+ mips64:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef mips64
+ #undef mips64el
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=mips64el
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=mips64
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=`
+ test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0
+ ;;
+ ppc:Linux:*:*)
+ echo powerpc-unknown-linux-gnu
+ exit 0 ;;
+ ppc64:Linux:*:*)
+ echo powerpc64-unknown-linux-gnu
+ exit 0 ;;
+ alpha:Linux:*:*)
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+ EV5) UNAME_MACHINE=alphaev5 ;;
+ EV56) UNAME_MACHINE=alphaev56 ;;
+ PCA56) UNAME_MACHINE=alphapca56 ;;
+ PCA57) UNAME_MACHINE=alphapca56 ;;
+ EV6) UNAME_MACHINE=alphaev6 ;;
+ EV67) UNAME_MACHINE=alphaev67 ;;
+ EV68*) UNAME_MACHINE=alphaev68 ;;
+ esac
+ objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
+ if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+ echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+ exit 0 ;;
+ parisc:Linux:*:* | hppa:Linux:*:*)
+ # Look for CPU level
+ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+ PA7*) echo hppa1.1-unknown-linux-gnu ;;
+ PA8*) echo hppa2.0-unknown-linux-gnu ;;
+ *) echo hppa-unknown-linux-gnu ;;
+ esac
+ exit 0 ;;
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ echo hppa64-unknown-linux-gnu
+ exit 0 ;;
+ s390:Linux:*:* | s390x:Linux:*:*)
+ echo ${UNAME_MACHINE}-ibm-linux
+ exit 0 ;;
+ sh64*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ sh*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ sparc:Linux:*:* | sparc64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ x86_64:Linux:*:*)
+ echo x86_64-unknown-linux-gnu
+ exit 0 ;;
+ i*86:Linux:*:*)
# The BFD linker knows what the default object file format is, so
# first see if it will tell us. cd to the root directory to prevent
# problems with other programs or directories called `ld' in the path.
- ld_help_string=`cd /; ld --help 2>&1`
- ld_supported_emulations=`echo $ld_help_string \
- | sed -ne '/supported emulations:/!d
+ # Set LC_ALL=C to ensure ld outputs messages in English.
+ ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
+ | sed -ne '/supported targets:/!d
s/[ ][ ]*/ /g
- s/.*supported emulations: *//
+ s/.*supported targets: *//
s/ .*//
p'`
- case "$ld_supported_emulations" in
- *ia64)
- echo "${UNAME_MACHINE}-unknown-linux"
- exit 0
+ case "$ld_supported_targets" in
+ elf32-i386)
+ TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
;;
- i?86linux)
+ a.out-i386-linux)
echo "${UNAME_MACHINE}-pc-linux-gnuaout"
- exit 0
- ;;
- elf_i?86)
- echo "${UNAME_MACHINE}-pc-linux"
- exit 0
- ;;
- i?86coff)
+ exit 0 ;;
+ coff-i386)
echo "${UNAME_MACHINE}-pc-linux-gnucoff"
- exit 0
- ;;
- sparclinux)
- echo "${UNAME_MACHINE}-unknown-linux-gnuaout"
- exit 0
- ;;
- armlinux)
- echo "${UNAME_MACHINE}-unknown-linux-gnuaout"
- exit 0
- ;;
- elf32arm*)
- echo "${UNAME_MACHINE}-unknown-linux-gnuoldld"
- exit 0
- ;;
- armelf_linux*)
- echo "${UNAME_MACHINE}-unknown-linux-gnu"
- exit 0
- ;;
- m68klinux)
- echo "${UNAME_MACHINE}-unknown-linux-gnuaout"
- exit 0
- ;;
- elf32ppc | elf32ppclinux)
- # Determine Lib Version
- cat >$dummy.c <<EOF
-#include <features.h>
-#if defined(__GLIBC__)
-extern char __libc_version[];
-extern char __libc_release[];
-#endif
-main(argc, argv)
- int argc;
- char *argv[];
-{
-#if defined(__GLIBC__)
- printf("%s %s\n", __libc_version, __libc_release);
-#else
- printf("unkown\n");
-#endif
- return 0;
-}
-EOF
- LIBC=""
- $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null
- if test "$?" = 0 ; then
- ./$dummy | grep 1\.99 > /dev/null
- if test "$?" = 0 ; then
- LIBC="libc1"
- fi
- fi
- rm -f $dummy.c $dummy
- echo powerpc-unknown-linux-gnu${LIBC}
- exit 0
- ;;
+ exit 0 ;;
+ "")
+ # Either a pre-BFD a.out linker (linux-gnuoldld) or
+ # one that does not give us useful --help.
+ echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
+ exit 0 ;;
esac
-
- if test "${UNAME_MACHINE}" = "alpha" ; then
- cat <<EOF >$dummy.s
- .data
- \$Lformat:
- .byte 37,100,45,37,120,10,0 # "%d-%x\n"
-
- .text
- .globl main
- .align 4
- .ent main
- main:
- .frame \$30,16,\$26,0
- ldgp \$29,0(\$27)
- .prologue 1
- .long 0x47e03d80 # implver \$0
- lda \$2,-1
- .long 0x47e20c21 # amask \$2,\$1
- lda \$16,\$Lformat
- mov \$0,\$17
- not \$1,\$18
- jsr \$26,printf
- ldgp \$29,0(\$26)
- mov 0,\$16
- jsr \$26,exit
- .end main
-EOF
- LIBC=""
- $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null
- if test "$?" = 0 ; then
- case `./$dummy` in
- 0-0)
- UNAME_MACHINE="alpha"
- ;;
- 1-0)
- UNAME_MACHINE="alphaev5"
- ;;
- 1-1)
- UNAME_MACHINE="alphaev56"
- ;;
- 1-101)
- UNAME_MACHINE="alphapca56"
- ;;
- 2-303)
- UNAME_MACHINE="alphaev6"
- ;;
- 2-307)
- UNAME_MACHINE="alphaev67"
- ;;
- esac
-
- objdump --private-headers $dummy | \
- grep ld.so.1 > /dev/null
- if test "$?" = 0 ; then
- LIBC="libc1"
- fi
- fi
- rm -f $dummy.s $dummy
- echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} ; exit 0
- elif test "${UNAME_MACHINE}" = "mips" ; then
- cat >$dummy.c <<EOF
-#ifdef __cplusplus
-#include <stdio.h> /* for printf() prototype */
- int main (int argc, char *argv[]) {
-#else
- int main (argc, argv) int argc; char *argv[]; {
-#endif
-#ifdef __MIPSEB__
- printf ("%s-unknown-linux-gnu\n", argv[1]);
-#endif
-#ifdef __MIPSEL__
- printf ("%sel-unknown-linux-gnu\n", argv[1]);
-#endif
- return 0;
-}
-EOF
- $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0
- rm -f $dummy.c $dummy
- elif test "${UNAME_MACHINE}" = "s390"; then
- echo s390-ibm-linux && exit 0
- else
- # Either a pre-BFD a.out linker (linux-gnuoldld)
- # or one that does not give us useful --help.
- # GCC wants to distinguish between linux-gnuoldld and linux-gnuaout.
- # If ld does not provide *any* "supported emulations:"
- # that means it is gnuoldld.
- echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations:"
- test $? != 0 && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0
-
- case "${UNAME_MACHINE}" in
- i?86)
- VENDOR=pc;
- ;;
- *)
- VENDOR=unknown;
- ;;
- esac
- # Determine whether the default compiler is a.out or elf
- cat >$dummy.c <<EOF
-#include <features.h>
-#ifdef __cplusplus
-#include <stdio.h> /* for printf() prototype */
- int main (int argc, char *argv[]) {
-#else
- int main (argc, argv) int argc; char *argv[]; {
-#endif
-#ifdef __ELF__
-# ifdef __GLIBC__
-# if __GLIBC__ >= 2
- printf ("%s-${VENDOR}-linux-gnu\n", argv[1]);
-# else
- printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
-# endif
-# else
- printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
-# endif
-#else
- printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]);
-#endif
- return 0;
-}
+ # Determine whether the default compiler is a.out or elf
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <features.h>
+ #ifdef __ELF__
+ # ifdef __GLIBC__
+ # if __GLIBC__ >= 2
+ LIBC=gnu
+ # else
+ LIBC=gnulibc1
+ # endif
+ # else
+ LIBC=gnulibc1
+ # endif
+ #else
+ #ifdef __INTEL_COMPILER
+ LIBC=gnu
+ #else
+ LIBC=gnuaout
+ #endif
+ #endif
+ #ifdef __dietlibc__
+ LIBC=dietlibc
+ #endif
EOF
- $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0
- rm -f $dummy.c $dummy
- fi ;;
-# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. earlier versions
-# are messed up and put the nodename in both sysname and nodename.
- i?86:DYNIX/ptx:4*:*)
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
+ test x"${LIBC}" != x && echo "${UNAME_MACHINE}-pc-linux-${LIBC}" && exit 0
+ test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0
+ ;;
+ i*86:DYNIX/ptx:4*:*)
+ # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+ # earlier versions are messed up and put the nodename in both
+ # sysname and nodename.
echo i386-sequent-sysv4
exit 0 ;;
- i?86:UNIX_SV:4.2MP:2.*)
+ i*86:UNIX_SV:4.2MP:2.*)
# Unixware is an offshoot of SVR4, but it has its own version
# number series starting with 2...
# I am not positive that other SVR4 systems won't match this,
@@ -865,7 +970,24 @@ EOF
# Use sysv4.2uw... so that sysv4* matches it.
echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
exit 0 ;;
- i?86:*:4.*:* | i?86:SYSTEM_V:4.*:*)
+ i*86:OS/2:*:*)
+ # If we were able to find `uname', then EMX Unix compatibility
+ # is probably installed.
+ echo ${UNAME_MACHINE}-pc-os2-emx
+ exit 0 ;;
+ i*86:XTS-300:*:STOP)
+ echo ${UNAME_MACHINE}-unknown-stop
+ exit 0 ;;
+ i*86:atheos:*:*)
+ echo ${UNAME_MACHINE}-unknown-atheos
+ exit 0 ;;
+ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+ echo i386-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ i*86:*DOS:*:*)
+ echo ${UNAME_MACHINE}-pc-msdosdjgpp
+ exit 0 ;;
+ i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
@@ -873,36 +995,32 @@ EOF
echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
fi
exit 0 ;;
- i?86:*:5:7*)
- # Fixed at (any) Pentium or better
- UNAME_MACHINE=i586
- if [ ${UNAME_SYSTEM} = "UnixWare" ] ; then
- echo ${UNAME_MACHINE}-sco-sysv${UNAME_RELEASE}uw${UNAME_VERSION}
- else
- echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE}
- fi
+ i*86:*:5:[78]*)
+ case `/bin/uname -X | grep "^Machine"` in
+ *486*) UNAME_MACHINE=i486 ;;
+ *Pentium) UNAME_MACHINE=i586 ;;
+ *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+ esac
+ echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
exit 0 ;;
- i?86:*:3.2:*)
+ i*86:*:3.2:*)
if test -f /usr/options/cb.name; then
UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
elif /bin/uname -X 2>/dev/null >/dev/null ; then
- UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
- (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
- (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
+ UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
&& UNAME_MACHINE=i586
- (/bin/uname -X|egrep '^Machine.*Pent ?II' >/dev/null) \
+ (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
&& UNAME_MACHINE=i686
- (/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) \
+ (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
&& UNAME_MACHINE=i686
echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
else
echo ${UNAME_MACHINE}-pc-sysv32
fi
exit 0 ;;
- i?86:*DOS:*:*)
- echo ${UNAME_MACHINE}-pc-msdosdjgpp
- exit 0 ;;
pc:*:*:*)
# Left here for compatibility:
# uname -m prints for DJGPP always 'pc', but it prints nothing about
@@ -926,9 +1044,15 @@ EOF
# "miniframe"
echo m68010-convergent-sysv
exit 0 ;;
+ mc68k:UNIX:SYSTEM5:3.51m)
+ echo m68k-convergent-sysv
+ exit 0 ;;
+ M680?0:D-NIX:5.3:*)
+ echo m68k-diab-dnix
+ exit 0 ;;
M68*:*:R3V[567]*:*)
test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
- 3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0)
+ 3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0)
OS_REL=''
test -r /etc/.relid \
&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
@@ -939,21 +1063,21 @@ EOF
3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
&& echo i486-ncr-sysv4 && exit 0 ;;
- m68*:LynxOS:2.*:*)
+ m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
echo m68k-unknown-lynxos${UNAME_RELEASE}
exit 0 ;;
mc68030:UNIX_System_V:4.*:*)
echo m68k-atari-sysv4
exit 0 ;;
- i?86:LynxOS:2.*:* | i?86:LynxOS:3.[01]*:*)
- echo i386-unknown-lynxos${UNAME_RELEASE}
- exit 0 ;;
TSUNAMI:LynxOS:2.*:*)
echo sparc-unknown-lynxos${UNAME_RELEASE}
exit 0 ;;
- rs6000:LynxOS:2.*:* | PowerPC:LynxOS:2.*:*)
+ rs6000:LynxOS:2.*:*)
echo rs6000-unknown-lynxos${UNAME_RELEASE}
exit 0 ;;
+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+ echo powerpc-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
SM[BE]S:UNIX_SV:*:*)
echo mips-dde-sysv${UNAME_RELEASE}
exit 0 ;;
@@ -971,8 +1095,8 @@ EOF
echo ns32k-sni-sysv
fi
exit 0 ;;
- PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
- # says <Richard.M.Bartel@ccMail.Census.GOV>
+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
echo i586-unisys-sysv4
exit 0 ;;
*:UNIX_System_V:4*:FTX*)
@@ -984,10 +1108,14 @@ EOF
# From seanf@swdc.stratus.com.
echo i860-stratus-sysv4
exit 0 ;;
+ *:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo hppa1.1-stratus-vos
+ exit 0 ;;
mc68*:A/UX:*:*)
echo m68k-apple-aux${UNAME_RELEASE}
exit 0 ;;
- news*:NEWS-OS:*:6*)
+ news*:NEWS-OS:6*:*)
echo mips-sony-newsos6
exit 0 ;;
R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
@@ -1012,6 +1140,9 @@ EOF
SX-5:SUPER-UX:*:*)
echo sx5-nec-superux${UNAME_RELEASE}
exit 0 ;;
+ SX-6:SUPER-UX:*:*)
+ echo sx6-nec-superux${UNAME_RELEASE}
+ exit 0 ;;
Power*:Rhapsody:*:*)
echo powerpc-apple-rhapsody${UNAME_RELEASE}
exit 0 ;;
@@ -1019,31 +1150,73 @@ EOF
echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
exit 0 ;;
*:Darwin:*:*)
- echo `uname -p`-apple-darwin${UNAME_RELEASE}
+ case `uname -p` in
+ *86) UNAME_PROCESSOR=i686 ;;
+ powerpc) UNAME_PROCESSOR=powerpc ;;
+ esac
+ echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
exit 0 ;;
*:procnto*:*:* | *:QNX:[0123456789]*:*)
- if test "${UNAME_MACHINE}" = "x86pc"; then
+ UNAME_PROCESSOR=`uname -p`
+ if test "$UNAME_PROCESSOR" = "x86"; then
+ UNAME_PROCESSOR=i386
UNAME_MACHINE=pc
fi
- echo `uname -p`-${UNAME_MACHINE}-nto-qnx
+ echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
exit 0 ;;
*:QNX:*:4*)
echo i386-pc-qnx
exit 0 ;;
- NSR-W:NONSTOP_KERNEL:*:*)
+ NSR-[DGKLNPTVWY]:NONSTOP_KERNEL:*:*)
echo nsr-tandem-nsk${UNAME_RELEASE}
exit 0 ;;
+ *:NonStop-UX:*:*)
+ echo mips-compaq-nonstopux
+ exit 0 ;;
BS2000:POSIX*:*:*)
echo bs2000-siemens-sysv
exit 0 ;;
DS/*:UNIX_System_V:*:*)
echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
exit 0 ;;
+ *:Plan9:*:*)
+ # "uname -m" is not consistent, so use $cputype instead. 386
+ # is converted to i386 for consistency with other x86
+ # operating systems.
+ if test "$cputype" = "386"; then
+ UNAME_MACHINE=i386
+ else
+ UNAME_MACHINE="$cputype"
+ fi
+ echo ${UNAME_MACHINE}-unknown-plan9
+ exit 0 ;;
+ *:TOPS-10:*:*)
+ echo pdp10-unknown-tops10
+ exit 0 ;;
+ *:TENEX:*:*)
+ echo pdp10-unknown-tenex
+ exit 0 ;;
+ KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+ echo pdp10-dec-tops20
+ exit 0 ;;
+ XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+ echo pdp10-xkl-tops20
+ exit 0 ;;
+ *:TOPS-20:*:*)
+ echo pdp10-unknown-tops20
+ exit 0 ;;
+ *:ITS:*:*)
+ echo pdp10-unknown-its
+ exit 0 ;;
+ SEI:*:*:SEIUX)
+ echo mips-sei-seiux${UNAME_RELEASE}
+ exit 0 ;;
esac
#echo '(No uname command or uname output not recognized.)' 1>&2
#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+eval $set_cc_for_build
cat >$dummy.c <<EOF
#ifdef _SEQUENT_
# include <sys/types.h>
@@ -1130,11 +1303,24 @@ main ()
#endif
#if defined (vax)
-#if !defined (ultrix)
- printf ("vax-dec-bsd\n"); exit (0);
-#else
- printf ("vax-dec-ultrix\n"); exit (0);
-#endif
+# if !defined (ultrix)
+# include <sys/param.h>
+# if defined (BSD)
+# if BSD == 43
+ printf ("vax-dec-bsd4.3\n"); exit (0);
+# else
+# if BSD == 199006
+ printf ("vax-dec-bsd4.3reno\n"); exit (0);
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# endif
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# else
+ printf ("vax-dec-ultrix\n"); exit (0);
+# endif
#endif
#if defined (alliant) && defined (i860)
@@ -1145,8 +1331,7 @@ main ()
}
EOF
-$CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm $dummy.c $dummy && exit 0
-rm -f $dummy.c $dummy
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && $dummy && exit 0
# Apollos put the system type in the environment.
@@ -1178,6 +1363,48 @@ then
esac
fi
-#echo '(Unable to guess system type)' 1>&2
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+ ftp://ftp.gnu.org/pub/gnu/config/
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo = `(hostinfo) 2>/dev/null`
+/bin/universe = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/libtecla-1.4.1/config.sub b/libtecla-1.6.1/config.sub
index c8e7785..1f31816 100644
--- a/libtecla-1.4.1/config.sub
+++ b/libtecla-1.6.1/config.sub
@@ -1,8 +1,10 @@
#! /bin/sh
-# Configuration validation subroutine script, version 1.1.
-# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000
-# Free Software Foundation, Inc.
-#
+# Configuration validation subroutine script.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+
+timestamp='2003-08-18'
+
# This file is (in principle) common to ALL GNU software.
# The presence of a machine in this file suggests that SOME GNU software
# can handle that machine. It does not imply ALL GNU software can.
@@ -27,8 +29,8 @@
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
-# Written by Per Bothner <bothner@cygnus.com>.
-# Please send patches to <config-patches@gnu.org>.
+# Please send patches to <config-patches@gnu.org>. Submit a context
+# diff and a properly formatted ChangeLog entry.
#
# Configuration subroutine to validate and canonicalize a configuration type.
# Supply the specified configuration type as an argument.
@@ -50,30 +52,73 @@
# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
# It is wrong to echo any other type of specification.
-if [ x$1 = x ]
-then
- echo Configuration name missing. 1>&2
- echo "Usage: $0 CPU-MFR-OPSYS" 1>&2
- echo "or $0 ALIAS" 1>&2
- echo where ALIAS is a recognized configuration type. 1>&2
- exit 1
-fi
+me=`echo "$0" | sed -e 's,.*/,,'`
-# First pass through any local machine types.
-case $1 in
- *local*)
- echo $1
- exit 0
- ;;
- *)
- ;;
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+ $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit 0 ;;
+ --version | -v )
+ echo "$version" ; exit 0 ;;
+ --help | --h* | -h )
+ echo "$usage"; exit 0 ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help"
+ exit 1 ;;
+
+ *local*)
+ # First pass through any local machine types.
+ echo $1
+ exit 0;;
+
+ * )
+ break ;;
+ esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+ exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+ exit 1;;
esac
# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
# Here we must recognize all the valid KERNEL-OS combinations.
maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
case $maybe_os in
- nto-qnx* | linux-gnu*)
+ nto-qnx* | linux-gnu* | linux-dietlibc | kfreebsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*)
os=-$maybe_os
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
;;
@@ -99,7 +144,7 @@ case $os in
-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
- -apple)
+ -apple | -axis)
os=
basic_machine=$1
;;
@@ -113,6 +158,14 @@ case $os in
os=-vxworks
basic_machine=$1
;;
+ -chorusos*)
+ os=-chorusos
+ basic_machine=$1
+ ;;
+ -chorusrdb)
+ os=-chorusrdb
+ basic_machine=$1
+ ;;
-hiux*)
os=-hiuxwe2
;;
@@ -171,30 +224,64 @@ esac
case $basic_machine in
# Recognize the basic CPU types without company name.
# Some are omitted here because they have special meanings below.
- tahoe | i860 | ia64 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \
- | arme[lb] | pyramid | mn10200 | mn10300 | tron | a29k \
- | 580 | i960 | h8300 \
- | x86 | ppcbe | mipsbe | mipsle | shbe | shle | armbe | armle \
- | hppa | hppa1.0 | hppa1.1 | hppa2.0 | hppa2.0w | hppa2.0n \
- | hppa64 \
- | alpha | alphaev[4-8] | alphaev56 | alphapca5[67] \
- | alphaev6[78] \
- | we32k | ns16k | clipper | i370 | sh | powerpc | powerpcle \
- | 1750a | dsp16xx | pdp11 | mips16 | mips64 | mipsel | mips64el \
- | mips64orion | mips64orionel | mipstx39 | mipstx39el \
- | mips64vr4300 | mips64vr4300el | mips64vr4100 | mips64vr4100el \
- | mips64vr5000 | miprs64vr5000el | mcore \
- | sparc | sparclet | sparclite | sparc64 | sparcv9 | v850 | c4x \
- | thumb | d10v | fr30 | avr)
+ 1750a | 580 \
+ | a29k \
+ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+ | am33_2.0 \
+ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
+ | c4x | clipper \
+ | d10v | d30v | dlx | dsp16xx \
+ | fr30 | frv \
+ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | i370 | i860 | i960 | ia64 \
+ | ip2k | iq2000 \
+ | m32r | m68000 | m68k | m88k | mcore \
+ | mips | mipsbe | mipseb | mipsel | mipsle \
+ | mips16 \
+ | mips64 | mips64el \
+ | mips64vr | mips64vrel \
+ | mips64orion | mips64orionel \
+ | mips64vr4100 | mips64vr4100el \
+ | mips64vr4300 | mips64vr4300el \
+ | mips64vr5000 | mips64vr5000el \
+ | mipsisa32 | mipsisa32el \
+ | mipsisa32r2 | mipsisa32r2el \
+ | mipsisa64 | mipsisa64el \
+ | mipsisa64r2 | mipsisa64r2el \
+ | mipsisa64sb1 | mipsisa64sb1el \
+ | mipsisa64sr71k | mipsisa64sr71kel \
+ | mipstx39 | mipstx39el \
+ | mn10200 | mn10300 \
+ | msp430 \
+ | ns16k | ns32k \
+ | openrisc | or32 \
+ | pdp10 | pdp11 | pj | pjl \
+ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+ | pyramid \
+ | sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \
+ | sh64 | sh64le \
+ | sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \
+ | strongarm \
+ | tahoe | thumb | tic4x | tic80 | tron \
+ | v850 | v850e \
+ | we32k \
+ | x86 | xscale | xstormy16 | xtensa \
+ | z8k)
basic_machine=$basic_machine-unknown
;;
- m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | z8k | v70 | h8500 | w65 | pj | pjl)
+ m6811 | m68hc11 | m6812 | m68hc12)
+ # Motorola 68HC11/12.
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
;;
# We use `pc' rather than `unknown'
# because (1) that's what they normally are, and
# (2) the word "unknown" tends to confuse beginning users.
- i[34567]86)
+ i*86 | x86_64)
basic_machine=$basic_machine-pc
;;
# Object if more than one company name word.
@@ -203,28 +290,61 @@ case $basic_machine in
exit 1
;;
# Recognize the basic CPU types with company name.
- # FIXME: clean up the formatting here.
- vax-* | tahoe-* | i[34567]86-* | i860-* | ia64-* | m32r-* | m68k-* | m68000-* \
- | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \
- | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \
- | power-* | none-* | 580-* | cray2-* | h8300-* | h8500-* | i960-* \
- | xmp-* | ymp-* \
- | x86-* | ppcbe-* | mipsbe-* | mipsle-* | shbe-* | shle-* | armbe-* | armle-* \
- | hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* | hppa2.0w-* \
- | hppa2.0n-* | hppa64-* \
- | alpha-* | alphaev[4-8]-* | alphaev56-* | alphapca5[67]-* \
- | alphaev6[78]-* \
- | we32k-* | cydra-* | ns16k-* | pn-* | np1-* | xps100-* \
- | clipper-* | orion-* \
- | sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \
- | sparc64-* | sparcv9-* | sparc86x-* | mips16-* | mips64-* | mipsel-* \
- | mips64el-* | mips64orion-* | mips64orionel-* \
- | mips64vr4100-* | mips64vr4100el-* | mips64vr4300-* | mips64vr4300el-* \
- | mipstx39-* | mipstx39el-* | mcore-* \
- | f301-* | armv*-* | s390-* | sv1-* | t3e-* \
- | m88110-* | m680[01234]0-* | m683?2-* | m68360-* | z8k-* | d10v-* \
- | thumb-* | v850-* | d30v-* | tic30-* | c30-* | fr30-* \
- | bs2000-*)
+ 580-* \
+ | a29k-* \
+ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \
+ | avr-* \
+ | bs2000-* \
+ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+ | clipper-* | cydra-* \
+ | d10v-* | d30v-* | dlx-* \
+ | elxsi-* \
+ | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \
+ | h8300-* | h8500-* \
+ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+ | i*86-* | i860-* | i960-* | ia64-* \
+ | ip2k-* | iq2000-* \
+ | m32r-* \
+ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+ | m88110-* | m88k-* | mcore-* \
+ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+ | mips16-* \
+ | mips64-* | mips64el-* \
+ | mips64vr-* | mips64vrel-* \
+ | mips64orion-* | mips64orionel-* \
+ | mips64vr4100-* | mips64vr4100el-* \
+ | mips64vr4300-* | mips64vr4300el-* \
+ | mips64vr5000-* | mips64vr5000el-* \
+ | mipsisa32-* | mipsisa32el-* \
+ | mipsisa32r2-* | mipsisa32r2el-* \
+ | mipsisa64-* | mipsisa64el-* \
+ | mipsisa64r2-* | mipsisa64r2el-* \
+ | mipsisa64sb1-* | mipsisa64sb1el-* \
+ | mipsisa64sr71k-* | mipsisa64sr71kel-* \
+ | mipstx39-* | mipstx39el-* \
+ | msp430-* \
+ | none-* | np1-* | nv1-* | ns16k-* | ns32k-* \
+ | orion-* \
+ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+ | pyramid-* \
+ | romp-* | rs6000-* \
+ | sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \
+ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+ | sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \
+ | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \
+ | tahoe-* | thumb-* \
+ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+ | tron-* \
+ | v850-* | v850e-* | vax-* \
+ | we32k-* \
+ | x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \
+ | xtensa-* \
+ | ymp-* \
+ | z8k-*)
;;
# Recognize the various machine names and aliases which stand
# for a CPU type and a company and sometimes even an OS.
@@ -256,19 +376,22 @@ case $basic_machine in
basic_machine=a29k-none
os=-bsd
;;
+ amd64)
+ basic_machine=x86_64-pc
+ ;;
amdahl)
basic_machine=580-amdahl
os=-sysv
;;
amiga | amiga-*)
- basic_machine=m68k-cbm
+ basic_machine=m68k-unknown
;;
amigaos | amigados)
- basic_machine=m68k-cbm
+ basic_machine=m68k-unknown
os=-amigaos
;;
amigaunix | amix)
- basic_machine=m68k-cbm
+ basic_machine=m68k-unknown
os=-sysv4
;;
apollo68)
@@ -287,6 +410,10 @@ case $basic_machine in
basic_machine=ns32k-sequent
os=-dynix
;;
+ c90)
+ basic_machine=c90-cray
+ os=-unicos
+ ;;
convex-c1)
basic_machine=c1-convex
os=-bsd
@@ -307,27 +434,30 @@ case $basic_machine in
basic_machine=c38-convex
os=-bsd
;;
- cray | ymp)
- basic_machine=ymp-cray
- os=-unicos
- ;;
- cray2)
- basic_machine=cray2-cray
- os=-unicos
- ;;
- [ctj]90-cray)
- basic_machine=c90-cray
+ cray | j90)
+ basic_machine=j90-cray
os=-unicos
;;
crds | unos)
basic_machine=m68k-crds
;;
+ cris | cris-* | etrax*)
+ basic_machine=cris-axis
+ ;;
da30 | da30-*)
basic_machine=m68k-da30
;;
decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
basic_machine=mips-dec
;;
+ decsystem10* | dec10*)
+ basic_machine=pdp10-dec
+ os=-tops10
+ ;;
+ decsystem20* | dec20*)
+ basic_machine=pdp10-dec
+ os=-tops20
+ ;;
delta | 3300 | motorola-3300 | motorola-delta \
| 3300-motorola | delta-motorola)
basic_machine=m68k-motorola
@@ -369,6 +499,10 @@ case $basic_machine in
basic_machine=tron-gmicro
os=-sysv
;;
+ go32)
+ basic_machine=i386-pc
+ os=-go32
+ ;;
h3050r* | hiux*)
basic_machine=hppa1.1-hitachi
os=-hiuxwe2
@@ -444,19 +578,19 @@ case $basic_machine in
basic_machine=i370-ibm
;;
# I'm not sure what "Sysv32" means. Should this be sysv3.2?
- i[34567]86v32)
+ i*86v32)
basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
os=-sysv32
;;
- i[34567]86v4*)
+ i*86v4*)
basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
os=-sysv4
;;
- i[34567]86v)
+ i*86v)
basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
os=-sysv
;;
- i[34567]86sol2)
+ i*86sol2)
basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
os=-solaris2
;;
@@ -468,14 +602,6 @@ case $basic_machine in
basic_machine=i386-unknown
os=-vsta
;;
- i386-go32 | go32)
- basic_machine=i386-unknown
- os=-go32
- ;;
- i386-mingw32 | mingw32)
- basic_machine=i386-unknown
- os=-mingw32
- ;;
iris | iris4d)
basic_machine=mips-sgi
case $os in
@@ -501,6 +627,10 @@ case $basic_machine in
basic_machine=ns32k-utek
os=-sysv
;;
+ mingw32)
+ basic_machine=i386-pc
+ os=-mingw32
+ ;;
miniframe)
basic_machine=m68000-convergent
;;
@@ -508,14 +638,6 @@ case $basic_machine in
basic_machine=m68k-atari
os=-mint
;;
- mipsel*-linux*)
- basic_machine=mipsel-unknown
- os=-linux-gnu
- ;;
- mips*-linux*)
- basic_machine=mips-unknown
- os=-linux-gnu
- ;;
mips3*-*)
basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
;;
@@ -530,8 +652,12 @@ case $basic_machine in
basic_machine=m68k-rom68k
os=-coff
;;
+ morphos)
+ basic_machine=powerpc-unknown
+ os=-morphos
+ ;;
msdos)
- basic_machine=i386-unknown
+ basic_machine=i386-pc
os=-msdos
;;
mvs)
@@ -595,9 +721,17 @@ case $basic_machine in
basic_machine=i960-intel
os=-mon960
;;
+ nonstopux)
+ basic_machine=mips-compaq
+ os=-nonstopux
+ ;;
np1)
basic_machine=np1-gould
;;
+ nv1)
+ basic_machine=nv1-cray
+ os=-unicosmp
+ ;;
nsr-tandem)
basic_machine=nsr-tandem
;;
@@ -605,6 +739,10 @@ case $basic_machine in
basic_machine=hppa1.1-oki
os=-proelf
;;
+ or32 | or32-*)
+ basic_machine=or32-unknown
+ os=-coff
+ ;;
OSE68000 | ose68000)
basic_machine=m68000-ericsson
os=-ose
@@ -627,45 +765,65 @@ case $basic_machine in
pbb)
basic_machine=m68k-tti
;;
- pc532 | pc532-*)
+ pc532 | pc532-*)
basic_machine=ns32k-pc532
;;
- pentium | p5 | k5 | k6 | nexen)
+ pentium | p5 | k5 | k6 | nexgen | viac3)
basic_machine=i586-pc
;;
- pentiumpro | p6 | 6x86)
+ pentiumpro | p6 | 6x86 | athlon | athlon_*)
+ basic_machine=i686-pc
+ ;;
+ pentiumii | pentium2 | pentiumiii | pentium3)
basic_machine=i686-pc
;;
- pentiumii | pentium2)
+ pentium4)
basic_machine=i786-pc
;;
- pentium-* | p5-* | k5-* | k6-* | nexen-*)
+ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
- pentiumpro-* | p6-* | 6x86-*)
+ pentiumpro-* | p6-* | 6x86-* | athlon-*)
basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
- pentiumii-* | pentium2-*)
+ pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium4-*)
basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
pn)
basic_machine=pn-gould
;;
- power) basic_machine=rs6000-ibm
+ power) basic_machine=power-ibm
;;
ppc) basic_machine=powerpc-unknown
- ;;
+ ;;
ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
ppcle | powerpclittle | ppc-le | powerpc-little)
basic_machine=powerpcle-unknown
- ;;
+ ;;
ppcle-* | powerpclittle-*)
basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
+ ppc64) basic_machine=powerpc64-unknown
+ ;;
+ ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+ basic_machine=powerpc64le-unknown
+ ;;
+ ppc64le-* | powerpc64little-*)
+ basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
ps2)
basic_machine=i386-ibm
;;
+ pw32)
+ basic_machine=i586-unknown
+ os=-pw32
+ ;;
rom68k)
basic_machine=m68k-rom68k
os=-coff
@@ -676,10 +834,26 @@ case $basic_machine in
rtpc | rtpc-*)
basic_machine=romp-ibm
;;
+ s390 | s390-*)
+ basic_machine=s390-ibm
+ ;;
+ s390x | s390x-*)
+ basic_machine=s390x-ibm
+ ;;
sa29200)
basic_machine=a29k-amd
os=-udi
;;
+ sb1)
+ basic_machine=mipsisa64sb1-unknown
+ ;;
+ sb1el)
+ basic_machine=mipsisa64sb1el-unknown
+ ;;
+ sei)
+ basic_machine=mips-sei
+ os=-seiux
+ ;;
sequent)
basic_machine=i386-sequent
;;
@@ -687,7 +861,10 @@ case $basic_machine in
basic_machine=sh-hitachi
os=-hms
;;
- sparclite-wrs)
+ sh64)
+ basic_machine=sh64-unknown
+ ;;
+ sparclite-wrs | simso-wrs)
basic_machine=sparclite-wrs
os=-vxworks
;;
@@ -754,15 +931,35 @@ case $basic_machine in
os=-dynix
;;
t3e)
- basic_machine=t3e-cray
+ basic_machine=alphaev5-cray
os=-unicos
;;
+ t90)
+ basic_machine=t90-cray
+ os=-unicos
+ ;;
+ tic54x | c54x*)
+ basic_machine=tic54x-unknown
+ os=-coff
+ ;;
+ tic55x | c55x*)
+ basic_machine=tic55x-unknown
+ os=-coff
+ ;;
+ tic6x | c6x*)
+ basic_machine=tic6x-unknown
+ os=-coff
+ ;;
tx39)
basic_machine=mipstx39-unknown
;;
tx39el)
basic_machine=mipstx39el-unknown
;;
+ toad1)
+ basic_machine=pdp10-xkl
+ os=-tops20
+ ;;
tower | tower-32)
basic_machine=m68k-ncr
;;
@@ -787,8 +984,8 @@ case $basic_machine in
os=-vms
;;
vpp*|vx|vx-*)
- basic_machine=f301-fujitsu
- ;;
+ basic_machine=f301-fujitsu
+ ;;
vxworks960)
basic_machine=i960-wrs
os=-vxworks
@@ -809,13 +1006,13 @@ case $basic_machine in
basic_machine=hppa1.1-winbond
os=-proelf
;;
- xmp)
- basic_machine=xmp-cray
- os=-unicos
- ;;
- xps | xps100)
+ xps | xps100)
basic_machine=xps100-honeywell
;;
+ ymp)
+ basic_machine=ymp-cray
+ os=-unicos
+ ;;
z8k-*-coff)
basic_machine=z8k-unknown
os=-sim
@@ -836,13 +1033,6 @@ case $basic_machine in
op60c)
basic_machine=hppa1.1-oki
;;
- mips)
- if [ x$os = x-linux-gnu ]; then
- basic_machine=mips-unknown
- else
- basic_machine=mips-mips
- fi
- ;;
romp)
basic_machine=romp-ibm
;;
@@ -852,16 +1042,26 @@ case $basic_machine in
vax)
basic_machine=vax-dec
;;
+ pdp10)
+ # there are many clones, so DEC is not a safe bet
+ basic_machine=pdp10-unknown
+ ;;
pdp11)
basic_machine=pdp11-dec
;;
we32k)
basic_machine=we32k-att
;;
- sparc | sparcv9)
+ sh3 | sh4 | sh[34]eb | sh[1234]le | sh[23]ele)
+ basic_machine=sh-unknown
+ ;;
+ sh64)
+ basic_machine=sh64-unknown
+ ;;
+ sparc | sparcv9 | sparcv9b)
basic_machine=sparc-sun
;;
- cydra)
+ cydra)
basic_machine=cydra-cydrome
;;
orion)
@@ -876,9 +1076,8 @@ case $basic_machine in
pmac | pmac-mpw)
basic_machine=powerpc-apple
;;
- c4x*)
- basic_machine=c4x-none
- os=-coff
+ *-unknown)
+ # Make sure to match an already-canonicalized machine name.
;;
*)
echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
@@ -932,27 +1131,34 @@ case $os in
| -aos* \
| -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
| -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
- | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
+ | -hiux* | -386bsd* | -netbsd* | -openbsd* | -kfreebsd* | -freebsd* | -riscix* \
| -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
| -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+ | -chorusos* | -chorusrdb* \
| -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
| -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \
- | -interix* | -uwin* | -rhapsody* | -darwin* | -opened* \
- | -openstep* | -oskit*)
+ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+ | -powermax* | -dnix* | -nx6 | -nx7 | -sei*)
# Remember, each alternative MUST END IN *, to match a version number.
;;
-qnx*)
case $basic_machine in
- x86-* | i[34567]86-*)
+ x86-* | i*86-*)
;;
*)
os=-nto$os
;;
esac
;;
+ -nto-qnx*)
+ ;;
-nto*)
- os=-nto-qnx
+ os=`echo $os | sed -e 's|nto|nto-qnx|'`
;;
-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
| -windows* | -osx | -abug | -netware* | -os9* | -beos* \
@@ -961,6 +1167,9 @@ case $os in
-mac*)
os=`echo $os | sed -e 's|mac|macos|'`
;;
+ -linux-dietlibc)
+ os=-linux-dietlibc
+ ;;
-linux*)
os=`echo $os | sed -e 's|linux|linux-gnu|'`
;;
@@ -991,16 +1200,22 @@ case $os in
-acis*)
os=-aos
;;
+ -atheos*)
+ os=-atheos
+ ;;
-386bsd)
os=-bsd
;;
-ctix* | -uts*)
os=-sysv
;;
+ -nova*)
+ os=-rtmk-nova
+ ;;
-ns2 )
- os=-nextstep2
+ os=-nextstep2
;;
- -nsk)
+ -nsk*)
os=-nsk
;;
# Preserve the version number of sinix5.
@@ -1037,8 +1252,14 @@ case $os in
-xenix)
os=-xenix
;;
- -*mint | -*MiNT)
- os=-mint
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ os=-mint
+ ;;
+ -aros*)
+ os=-aros
+ ;;
+ -kaos*)
+ os=-kaos
;;
-none)
;;
@@ -1071,7 +1292,14 @@ case $basic_machine in
arm*-semi)
os=-aout
;;
- pdp11-*)
+ c4x-* | tic4x-*)
+ os=-coff
+ ;;
+ # This must come before the *-dec entry.
+ pdp10-*)
+ os=-tops20
+ ;;
+ pdp11-*)
os=-none
;;
*-dec | vax-*)
@@ -1098,6 +1326,9 @@ case $basic_machine in
mips*-*)
os=-elf
;;
+ or32-*)
+ os=-coff
+ ;;
*-tti) # must be before sparc entry or we get the wrong os.
os=-sysv3
;;
@@ -1161,25 +1392,25 @@ case $basic_machine in
*-next)
os=-nextstep3
;;
- *-gould)
+ *-gould)
os=-sysv
;;
- *-highlevel)
+ *-highlevel)
os=-bsd
;;
*-encore)
os=-bsd
;;
- *-sgi)
+ *-sgi)
os=-irix
;;
- *-siemens)
+ *-siemens)
os=-sysv4
;;
*-masscomp)
os=-rtu
;;
- f301-fujitsu)
+ f30[01]-fujitsu | f700-fujitsu)
os=-uxpv
;;
*-rom68k)
@@ -1245,7 +1476,7 @@ case $basic_machine in
-ptx*)
vendor=sequent
;;
- -vxsim* | -vxworks*)
+ -vxsim* | -vxworks* | -windiss*)
vendor=wrs
;;
-aux*)
@@ -1257,12 +1488,23 @@ case $basic_machine in
-mpw* | -macos*)
vendor=apple
;;
- -*mint | -*MiNT)
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
vendor=atari
;;
+ -vos*)
+ vendor=stratus
+ ;;
esac
basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
;;
esac
echo $basic_machine$os
+exit 0
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/libtecla-1.6.1/configure b/libtecla-1.6.1/configure
new file mode 100755
index 0000000..62f49e0
--- /dev/null
+++ b/libtecla-1.6.1/configure
@@ -0,0 +1,5208 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.57.
+#
+# Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002
+# Free Software Foundation, Inc.
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## --------------------- ##
+## M4sh Initialization. ##
+## --------------------- ##
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+ set -o posix
+fi
+
+# Support unset when possible.
+if (FOO=FOO; unset FOO) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
+
+
+# Work around bugs in pre-3.0 UWIN ksh.
+$as_unset ENV MAIL MAILPATH
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+ LC_TELEPHONE LC_TIME
+do
+ if (set +x; test -n "`(eval $as_var=C; export $as_var) 2>&1`"); then
+ eval $as_var=C; export $as_var
+ else
+ $as_unset $as_var
+ fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)$' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
+ /^X\/\(\/\/\)$/{ s//\1/; q; }
+ /^X\/\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+
+
+# PATH needs CR, and LINENO needs CR and PATH.
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conf$$.sh
+ echo "exit 0" >>conf$$.sh
+ chmod +x conf$$.sh
+ if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conf$$.sh
+fi
+
+
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" || {
+ # Find who we are. Look in the path if we contain no path at all
+ # relative or not.
+ case $0 in
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+
+ ;;
+ esac
+ # We did not find ourselves, most probably we were run as `sh COMMAND'
+ # in which case we are not to be found in the path.
+ if test "x$as_myself" = x; then
+ as_myself=$0
+ fi
+ if test ! -f "$as_myself"; then
+ { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2
+ { (exit 1); exit 1; }; }
+ fi
+ case $CONFIG_SHELL in
+ '')
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for as_base in sh bash ksh sh5; do
+ case $as_dir in
+ /*)
+ if ("$as_dir/$as_base" -c '
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then
+ $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; }
+ $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; }
+ CONFIG_SHELL=$as_dir/$as_base
+ export CONFIG_SHELL
+ exec "$CONFIG_SHELL" "$0" ${1+"$@"}
+ fi;;
+ esac
+ done
+done
+;;
+ esac
+
+ # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+ # uniformly replaced by the line number. The first 'sed' inserts a
+ # line-number line before each line; the second 'sed' does the real
+ # work. The second script uses 'N' to pair each line-number line
+ # with the numbered line, and appends trailing '-' during
+ # substitution so that $LINENO is not a special case at line end.
+ # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+ # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-)
+ sed '=' <$as_myself |
+ sed '
+ N
+ s,$,-,
+ : loop
+ s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
+ t loop
+ s,-$,,
+ s,^['$as_cr_digits']*\n,,
+ ' >$as_me.lineno &&
+ chmod +x $as_me.lineno ||
+ { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+ { (exit 1); exit 1; }; }
+
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensible to this).
+ . ./$as_me.lineno
+ # Exit status is that of the last command.
+ exit
+}
+
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+ *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T=' ' ;;
+ *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+ *) ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+ # We could just check for DJGPP; but this test a) works b) is more generic
+ # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+ if test -f conf$$.exe; then
+ # Don't use ln at all; we don't have any links
+ as_ln_s='cp -p'
+ else
+ as_ln_s='ln -s'
+ fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.file
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p=:
+else
+ as_mkdir_p=false
+fi
+
+as_executable_p="test -f"
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="sed y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="sed y%*+%pp%;s%[^_$as_cr_alnum]%_%g"
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" $as_nl"
+
+# CDPATH.
+$as_unset CDPATH
+
+
+# Name of the host.
+# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+exec 6>&1
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_config_libobj_dir=.
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# Maximum number of lines to put in a shell here document.
+# This variable seems obsolete. It should probably be removed, and
+# only ac_max_sed_lines should be used.
+: ${ac_max_here_lines=38}
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+
+ac_unique_file="getline.c"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# if HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#if HAVE_STRING_H
+# if !STDC_HEADERS && HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+# include <stdint.h>
+# endif
+#endif
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS MAJOR_VER MINOR_VER MICRO_VER CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT SET_MAKE LN_S AWK RANLIB ac_ct_RANLIB LD ac_ct_LD build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os CPP EGREP TARGETS SHARED_EXT SHARED_ALT SHARED_CFLAGS LINK_SHARED DEFS_R LIBR_MANDIR LIBR_MANEXT FUNC_MANDIR FUNC_MANEXT PROG_MANDIR PROG_MANEXT MISC_MANDIR MISC_MANEXT FILE_MANDIR FILE_MANEXT TARGET_LIBS MAKE_MAN_PAGES LIBOBJS LTLIBOBJS'
+ac_subst_files=''
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+ac_prev=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'`
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_option in
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+ { (exit 1); exit 1; }; }
+ ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+ eval "enable_$ac_feature=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+ { (exit 1); exit 1; }; }
+ ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+ case $ac_option in
+ *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_$ac_feature='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid package name: $ac_package" >&2
+ { (exit 1); exit 1; }; }
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case $ac_option in
+ *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_$ac_package='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid package name: $ac_package" >&2
+ { (exit 1); exit 1; }; }
+ ac_package=`echo $ac_package | sed 's/-/_/g'`
+ eval "with_$ac_package=no" ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) { echo "$as_me: error: unrecognized option: $ac_option
+Try \`$0 --help' for more information." >&2
+ { (exit 1); exit 1; }; }
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid variable name: $ac_envvar" >&2
+ { (exit 1); exit 1; }; }
+ ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`
+ eval "$ac_envvar='$ac_optarg'"
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ { echo "$as_me: error: missing argument to $ac_option" >&2
+ { (exit 1); exit 1; }; }
+fi
+
+# Be sure to have absolute paths.
+for ac_var in exec_prefix prefix
+do
+ eval ac_val=$`echo $ac_var`
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* | NONE | '' ) ;;
+ *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# Be sure to have absolute paths.
+for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \
+ localstatedir libdir includedir oldincludedir infodir mandir
+do
+ eval ac_val=$`echo $ac_var`
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) ;;
+ *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
+ If a cross compiler is detected then cross compile mode will be used." >&2
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then its parent.
+ ac_confdir=`(dirname "$0") 2>/dev/null ||
+$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$0" : 'X\(//\)[^/]' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$0" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2
+ { (exit 1); exit 1; }; }
+ else
+ { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2
+ { (exit 1); exit 1; }; }
+ fi
+fi
+(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null ||
+ { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2
+ { (exit 1); exit 1; }; }
+srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'`
+ac_env_build_alias_set=${build_alias+set}
+ac_env_build_alias_value=$build_alias
+ac_cv_env_build_alias_set=${build_alias+set}
+ac_cv_env_build_alias_value=$build_alias
+ac_env_host_alias_set=${host_alias+set}
+ac_env_host_alias_value=$host_alias
+ac_cv_env_host_alias_set=${host_alias+set}
+ac_cv_env_host_alias_value=$host_alias
+ac_env_target_alias_set=${target_alias+set}
+ac_env_target_alias_value=$target_alias
+ac_cv_env_target_alias_set=${target_alias+set}
+ac_cv_env_target_alias_value=$target_alias
+ac_env_CC_set=${CC+set}
+ac_env_CC_value=$CC
+ac_cv_env_CC_set=${CC+set}
+ac_cv_env_CC_value=$CC
+ac_env_CFLAGS_set=${CFLAGS+set}
+ac_env_CFLAGS_value=$CFLAGS
+ac_cv_env_CFLAGS_set=${CFLAGS+set}
+ac_cv_env_CFLAGS_value=$CFLAGS
+ac_env_LDFLAGS_set=${LDFLAGS+set}
+ac_env_LDFLAGS_value=$LDFLAGS
+ac_cv_env_LDFLAGS_set=${LDFLAGS+set}
+ac_cv_env_LDFLAGS_value=$LDFLAGS
+ac_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_env_CPPFLAGS_value=$CPPFLAGS
+ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_cv_env_CPPFLAGS_value=$CPPFLAGS
+ac_env_CPP_set=${CPP+set}
+ac_env_CPP_value=$CPP
+ac_cv_env_CPP_set=${CPP+set}
+ac_cv_env_CPP_value=$CPP
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+_ACEOF
+
+ cat <<_ACEOF
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --infodir=DIR info documentation [PREFIX/info]
+ --mandir=DIR man documentation [PREFIX/man]
+_ACEOF
+
+ cat <<\_ACEOF
+
+System types:
+ --build=BUILD configure for building on BUILD [guessed]
+ --host=HOST cross-compile to build programs to run on HOST [BUILD]
+ --target=TARGET configure for building compilers for TARGET [HOST]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --with-file-actions Should users of gl_get_line() have access to the
+ filesystem (default=yes)
+ --with-file-system Does the target have a filesystem (default=yes)
+ --with-man-pages Are man pages desired (default=yes)
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ CPPFLAGS C/C++ preprocessor flags, e.g. -I<include dir> if you have
+ headers in a nonstandard directory <include dir>
+ CPP C preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+_ACEOF
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ ac_popdir=`pwd`
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d $ac_dir || continue
+ ac_builddir=.
+
+if test "$ac_dir" != .; then
+ ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+ ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+ .) # No --srcdir option. We are building in place.
+ ac_srcdir=.
+ if test -z "$ac_top_builddir"; then
+ ac_top_srcdir=.
+ else
+ ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+ fi ;;
+ [\\/]* | ?:[\\/]* ) # Absolute path.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir ;;
+ *) # Relative path.
+ ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+# Don't blindly perform a `cd "$ac_dir"/$ac_foo && pwd` since $ac_foo can be
+# absolute.
+ac_abs_builddir=`cd "$ac_dir" && cd $ac_builddir && pwd`
+ac_abs_top_builddir=`cd "$ac_dir" && cd ${ac_top_builddir}. && pwd`
+ac_abs_srcdir=`cd "$ac_dir" && cd $ac_srcdir && pwd`
+ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd`
+
+ cd $ac_dir
+ # Check for guested configure; otherwise get Cygnus style configure.
+ if test -f $ac_srcdir/configure.gnu; then
+ echo
+ $SHELL $ac_srcdir/configure.gnu --help=recursive
+ elif test -f $ac_srcdir/configure; then
+ echo
+ $SHELL $ac_srcdir/configure --help=recursive
+ elif test -f $ac_srcdir/configure.ac ||
+ test -f $ac_srcdir/configure.in; then
+ echo
+ $ac_configure --help
+ else
+ echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi
+ cd $ac_popdir
+ done
+fi
+
+test -n "$ac_init_help" && exit 0
+if $ac_init_version; then
+ cat <<\_ACEOF
+
+Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002
+Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit 0
+fi
+exec 5>config.log
+cat >&5 <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.57. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+hostinfo = `(hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ echo "PATH: $as_dir"
+done
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_sep=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+ ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;;
+ 2)
+ ac_configure_args1="$ac_configure_args1 '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'"
+ # Get rid of the leading space.
+ ac_sep=" "
+ ;;
+ esac
+ done
+done
+$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; }
+$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; }
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Be sure not to use single quotes in there, as some shells,
+# such as our DU 5.0 friend, will then `close' the trap.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ cat <<\_ASBOX
+## ---------------- ##
+## Cache variables. ##
+## ---------------- ##
+_ASBOX
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+{
+ (set) 2>&1 |
+ case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ sed -n \
+ "s/'"'"'/'"'"'\\\\'"'"''"'"'/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p"
+ ;;
+ *)
+ sed -n \
+ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+ ;;
+ esac;
+}
+ echo
+
+ cat <<\_ASBOX
+## ----------------- ##
+## Output variables. ##
+## ----------------- ##
+_ASBOX
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=$`echo $ac_var`
+ echo "$ac_var='"'"'$ac_val'"'"'"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ cat <<\_ASBOX
+## ------------- ##
+## Output files. ##
+## ------------- ##
+_ASBOX
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=$`echo $ac_var`
+ echo "$ac_var='"'"'$ac_val'"'"'"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ cat <<\_ASBOX
+## ----------- ##
+## confdefs.h. ##
+## ----------- ##
+_ASBOX
+ echo
+ sed "/^$/d" confdefs.h | sort
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ echo "$as_me: caught signal $ac_signal"
+ echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core core.* *.core &&
+ rm -rf conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+ ' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo >confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5
+echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special
+ # files actually), so we avoid doing that.
+ if test -f "$cache_file"; then
+ { echo "$as_me:$LINENO: loading cache $cache_file" >&5
+echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . $cache_file;;
+ *) . ./$cache_file;;
+ esac
+ fi
+else
+ { echo "$as_me:$LINENO: creating cache $cache_file" >&5
+echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in `(set) 2>&1 |
+ sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val="\$ac_cv_env_${ac_var}_value"
+ eval ac_new_val="\$ac_env_${ac_var}_value"
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5
+echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ { echo "$as_me:$LINENO: former value: $ac_old_val" >&5
+echo "$as_me: former value: $ac_old_val" >&2;}
+ { echo "$as_me:$LINENO: current value: $ac_new_val" >&5
+echo "$as_me: current value: $ac_new_val" >&2;}
+ ac_cache_corrupted=:
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+ ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5
+echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
+echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+MAJOR_VER="1"
+
+
+
+MINOR_VER="6"
+
+
+
+MICRO_VER="1"
+
+
+CFLAGS="$CFLAGS"
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ CC=$ac_ct_CC
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ CC=$ac_ct_CC
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$ac_ct_CC" && break
+done
+
+ CC=$ac_ct_CC
+fi
+
+fi
+
+
+test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&5
+echo "$as_me: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+
+# Provide some information about the compiler.
+echo "$as_me:$LINENO:" \
+ "checking for C compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
+ (eval $ac_compiler --version </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v </dev/null >&5\"") >&5
+ (eval $ac_compiler -v </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V </dev/null >&5\"") >&5
+ (eval $ac_compiler -V </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+echo "$as_me:$LINENO: checking for C compiler default output" >&5
+echo $ECHO_N "checking for C compiler default output... $ECHO_C" >&6
+ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5
+ (eval $ac_link_default) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # Find the output, starting from the most likely. This scheme is
+# not robust to junk in `.', hence go to wildcards (a.*) only as a last
+# resort.
+
+# Be careful to initialize this variable, since it used to be cached.
+# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile.
+ac_cv_exeext=
+# b.out is created by i960 compilers.
+for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj )
+ ;;
+ conftest.$ac_ext )
+ # This is the source file.
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ # FIXME: I believe we export ac_cv_exeext for Libtool,
+ # but it would be cool to find out if it's true. Does anybody
+ # maintain Libtool? --akim.
+ export ac_cv_exeext
+ break;;
+ * )
+ break;;
+ esac
+done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: C compiler cannot create executables
+See \`config.log' for more details." >&5
+echo "$as_me: error: C compiler cannot create executables
+See \`config.log' for more details." >&2;}
+ { (exit 77); exit 77; }; }
+fi
+
+ac_exeext=$ac_cv_exeext
+echo "$as_me:$LINENO: result: $ac_file" >&5
+echo "${ECHO_T}$ac_file" >&6
+
+# Check the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:$LINENO: checking whether the C compiler works" >&5
+echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6
+# FIXME: These cross compiler hacks should be removed for Autoconf 3.0
+# If not cross compiling, check that we can run a simple program.
+if test "$cross_compiling" != yes; then
+ if { ac_try='./$ac_file'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { echo "$as_me:$LINENO: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ fi
+fi
+echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+
+rm -f a.out a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+# Check the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:$LINENO: checking whether we are cross compiling" >&5
+echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6
+echo "$as_me:$LINENO: result: $cross_compiling" >&5
+echo "${ECHO_T}$cross_compiling" >&6
+
+echo "$as_me:$LINENO: checking for suffix of executables" >&5
+echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ export ac_cv_exeext
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest$ac_cv_exeext
+echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5
+echo "${ECHO_T}$ac_cv_exeext" >&6
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+echo "$as_me:$LINENO: checking for suffix of object files" >&5
+echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6
+if test "${ac_cv_objext+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_objext" >&5
+echo "${ECHO_T}$ac_cv_objext" >&6
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6
+if test "${ac_cv_c_compiler_gnu+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_compiler_gnu=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_compiler_gnu=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6
+GCC=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+CFLAGS="-g"
+echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_g+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_prog_cc_g=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_prog_cc_g=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_g" >&6
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5
+echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_stdc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_prog_cc_stdc=no
+ac_save_CC=$CC
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX -qlanglvl=ansi
+# Ultrix and OSF/1 -std1
+# HP-UX 10.20 and later -Ae
+# HP-UX older versions -Aa -D_HPUX_SOURCE
+# SVR4 -Xc -D__EXTENSIONS__
+for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_prog_cc_stdc=$ac_arg
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.$ac_objext
+done
+rm -f conftest.$ac_ext conftest.$ac_objext
+CC=$ac_save_CC
+
+fi
+
+case "x$ac_cv_prog_cc_stdc" in
+ x|xno)
+ echo "$as_me:$LINENO: result: none needed" >&5
+echo "${ECHO_T}none needed" >&6 ;;
+ *)
+ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6
+ CC="$CC $ac_cv_prog_cc_stdc" ;;
+esac
+
+# Some people use a C++ compiler to compile C. Since we use `exit',
+# in C++ we need to declare it. In case someone uses the same compiler
+# for both compiling C and C++ we need to have the C++ compiler decide
+# the declaration of exit, since it's the most demanding environment.
+cat >conftest.$ac_ext <<_ACEOF
+#ifndef __cplusplus
+ choke me
+#endif
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ for ac_declaration in \
+ ''\
+ '#include <stdlib.h>' \
+ 'extern "C" void std::exit (int) throw (); using std::exit;' \
+ 'extern "C" void std::exit (int); using std::exit;' \
+ 'extern "C" void exit (int) throw ();' \
+ 'extern "C" void exit (int);' \
+ 'void exit (int);'
+do
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+$ac_declaration
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+continue
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_declaration
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+done
+rm -f conftest*
+if test -n "$ac_declaration"; then
+ echo '#ifdef __cplusplus' >>confdefs.h
+ echo $ac_declaration >>confdefs.h
+ echo '#endif' >>confdefs.h
+fi
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,./+-,__p_,'`
+if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.make <<\_ACEOF
+all:
+ @echo 'ac_maketemp="$(MAKE)"'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+ eval ac_cv_prog_make_${ac_make}_set=yes
+else
+ eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftest.make
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ SET_MAKE=
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+
+
+echo "$as_me:$LINENO: checking whether ln -s works" >&5
+echo $ECHO_N "checking whether ln -s works... $ECHO_C" >&6
+LN_S=$as_ln_s
+if test "$LN_S" = "ln -s"; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+else
+ echo "$as_me:$LINENO: result: no, using $LN_S" >&5
+echo "${ECHO_T}no, using $LN_S" >&6
+fi
+
+
+
+for ac_prog in gawk mawk nawk awk
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_AWK+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$AWK"; then
+ ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_AWK="$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+ echo "$as_me:$LINENO: result: $AWK" >&5
+echo "${ECHO_T}$AWK" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$AWK" && break
+done
+
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_RANLIB+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+ echo "$as_me:$LINENO: result: $RANLIB" >&5
+echo "${ECHO_T}$RANLIB" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+ ac_ct_RANLIB=$RANLIB
+ # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_RANLIB"; then
+ ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_RANLIB="ranlib"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+ echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5
+echo "${ECHO_T}$ac_ct_RANLIB" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ RANLIB=$ac_ct_RANLIB
+else
+ RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ld", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ld; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_LD+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$LD"; then
+ ac_cv_prog_LD="$LD" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_LD="${ac_tool_prefix}ld"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+LD=$ac_cv_prog_LD
+if test -n "$LD"; then
+ echo "$as_me:$LINENO: result: $LD" >&5
+echo "${ECHO_T}$LD" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_LD"; then
+ ac_ct_LD=$LD
+ # Extract the first word of "ld", so it can be a program name with args.
+set dummy ld; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_LD+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_LD"; then
+ ac_cv_prog_ac_ct_LD="$ac_ct_LD" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_LD="ld"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_LD=$ac_cv_prog_ac_ct_LD
+if test -n "$ac_ct_LD"; then
+ echo "$as_me:$LINENO: result: $ac_ct_LD" >&5
+echo "${ECHO_T}$ac_ct_LD" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ LD=$ac_ct_LD
+else
+ LD="$ac_cv_prog_LD"
+fi
+
+
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+ if test -f $ac_dir/install-sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f $ac_dir/install.sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ elif test -f $ac_dir/shtool; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/shtool install -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5
+echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"
+ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure.
+
+# Make sure we can run config.sub.
+$ac_config_sub sun4 >/dev/null 2>&1 ||
+ { { echo "$as_me:$LINENO: error: cannot run $ac_config_sub" >&5
+echo "$as_me: error: cannot run $ac_config_sub" >&2;}
+ { (exit 1); exit 1; }; }
+
+echo "$as_me:$LINENO: checking build system type" >&5
+echo $ECHO_N "checking build system type... $ECHO_C" >&6
+if test "${ac_cv_build+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_build_alias=$build_alias
+test -z "$ac_cv_build_alias" &&
+ ac_cv_build_alias=`$ac_config_guess`
+test -z "$ac_cv_build_alias" &&
+ { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5
+echo "$as_me: error: cannot guess build type; you must specify one" >&2;}
+ { (exit 1); exit 1; }; }
+ac_cv_build=`$ac_config_sub $ac_cv_build_alias` ||
+ { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_build_alias failed" >&5
+echo "$as_me: error: $ac_config_sub $ac_cv_build_alias failed" >&2;}
+ { (exit 1); exit 1; }; }
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_build" >&5
+echo "${ECHO_T}$ac_cv_build" >&6
+build=$ac_cv_build
+build_cpu=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+build_vendor=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+build_os=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+
+echo "$as_me:$LINENO: checking host system type" >&5
+echo $ECHO_N "checking host system type... $ECHO_C" >&6
+if test "${ac_cv_host+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_host_alias=$host_alias
+test -z "$ac_cv_host_alias" &&
+ ac_cv_host_alias=$ac_cv_build_alias
+ac_cv_host=`$ac_config_sub $ac_cv_host_alias` ||
+ { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_host_alias failed" >&5
+echo "$as_me: error: $ac_config_sub $ac_cv_host_alias failed" >&2;}
+ { (exit 1); exit 1; }; }
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_host" >&5
+echo "${ECHO_T}$ac_cv_host" >&6
+host=$ac_cv_host
+host_cpu=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+host_vendor=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+host_os=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+
+echo "$as_me:$LINENO: checking target system type" >&5
+echo $ECHO_N "checking target system type... $ECHO_C" >&6
+if test "${ac_cv_target+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_target_alias=$target_alias
+test "x$ac_cv_target_alias" = "x" &&
+ ac_cv_target_alias=$ac_cv_host_alias
+ac_cv_target=`$ac_config_sub $ac_cv_target_alias` ||
+ { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_target_alias failed" >&5
+echo "$as_me: error: $ac_config_sub $ac_cv_target_alias failed" >&2;}
+ { (exit 1); exit 1; }; }
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_target" >&5
+echo "${ECHO_T}$ac_cv_target" >&6
+target=$ac_cv_target
+target_cpu=`echo $ac_cv_target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+target_vendor=`echo $ac_cv_target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+target_os=`echo $ac_cv_target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+
+# The aliases save the names the user supplied, while $host etc.
+# will get canonicalized.
+test -n "$target_alias" &&
+ test "$program_prefix$program_suffix$program_transform_name" = \
+ NONENONEs,x,x, &&
+ program_prefix=${target_alias}-
+
+
+case $target_os in
+solaris2.[0-6]|solaris2.[0-6].*)
+ LIBS="$LIBS -L/usr/ccs/lib"
+ ;;
+esac
+
+
+if test "$GCC"_ = "yes"_; then
+ touch foo.c
+ fix=`$CC -E -Wp,-v foo.c 2>&1 | $AWK '
+ /^#include <...> search starts here:/ {in_list=1;ndir=0}
+ / *\// && in_list {path[ndir++] = $1}
+ /^End of search list/ {in_list=0}
+ END {
+ if(path[0] ~ /\/usr\/local\/include/) {
+ for(dir=1; dir<ndir; dir++) {
+ printf(" -isystem %s", path[dir])
+ }
+ printf("\n");
+ }
+ }'`
+ rm -f foo.c
+ CFLAGS="$CFLAGS$fix"
+fi
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5
+echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+ if test "${ac_cv_prog_CPP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ # Double quotes because CPP needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether non-existent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ # Broken: success on invalid input.
+continue
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ break
+fi
+
+ done
+ ac_cv_prog_CPP=$CPP
+
+fi
+ CPP=$ac_cv_prog_CPP
+else
+ ac_cv_prog_CPP=$CPP
+fi
+echo "$as_me:$LINENO: result: $CPP" >&5
+echo "${ECHO_T}$CPP" >&6
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether non-existent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ # Broken: success on invalid input.
+continue
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ :
+else
+ { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&5
+echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+echo "$as_me:$LINENO: checking for egrep" >&5
+echo $ECHO_N "checking for egrep... $ECHO_C" >&6
+if test "${ac_cv_prog_egrep+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if echo a | (grep -E '(a|b)') >/dev/null 2>&1
+ then ac_cv_prog_egrep='grep -E'
+ else ac_cv_prog_egrep='egrep'
+ fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5
+echo "${ECHO_T}$ac_cv_prog_egrep" >&6
+ EGREP=$ac_cv_prog_egrep
+
+
+echo "$as_me:$LINENO: checking for ANSI C header files" >&5
+echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6
+if test "${ac_cv_header_stdc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_header_stdc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_header_stdc=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "memchr" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "free" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then
+ :
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ctype.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+ (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ exit(2);
+ exit (0);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_header_stdc=no
+fi
+rm -f core core.* *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
+echo "${ECHO_T}$ac_cv_header_stdc" >&6
+if test $ac_cv_header_stdc = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define STDC_HEADERS 1
+_ACEOF
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+
+
+
+
+
+
+
+
+
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+ inttypes.h stdint.h unistd.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_Header=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_Header=no"
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+echo "$as_me:$LINENO: checking for tigetstr in -lcurses" >&5
+echo $ECHO_N "checking for tigetstr in -lcurses... $ECHO_C" >&6
+if test "${ac_cv_lib_curses_tigetstr+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcurses $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char tigetstr ();
+int
+main ()
+{
+tigetstr ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_curses_tigetstr=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_curses_tigetstr=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_curses_tigetstr" >&5
+echo "${ECHO_T}$ac_cv_lib_curses_tigetstr" >&6
+if test $ac_cv_lib_curses_tigetstr = yes; then
+
+ cat >>confdefs.h <<\_ACEOF
+#define USE_TERMINFO 1
+_ACEOF
+
+ LIBS="$LIBS -lcurses"
+
+else
+ echo "$as_me:$LINENO: checking for tigetstr in -lncurses" >&5
+echo $ECHO_N "checking for tigetstr in -lncurses... $ECHO_C" >&6
+if test "${ac_cv_lib_ncurses_tigetstr+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lncurses $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char tigetstr ();
+int
+main ()
+{
+tigetstr ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_ncurses_tigetstr=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_ncurses_tigetstr=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_ncurses_tigetstr" >&5
+echo "${ECHO_T}$ac_cv_lib_ncurses_tigetstr" >&6
+if test $ac_cv_lib_ncurses_tigetstr = yes; then
+
+ cat >>confdefs.h <<\_ACEOF
+#define USE_TERMINFO 1
+_ACEOF
+
+ LIBS="$LIBS -lncurses"
+
+else
+ echo "$as_me:$LINENO: checking for tgetstr in -lcurses" >&5
+echo $ECHO_N "checking for tgetstr in -lcurses... $ECHO_C" >&6
+if test "${ac_cv_lib_curses_tgetstr+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcurses $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char tgetstr ();
+int
+main ()
+{
+tgetstr ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_curses_tgetstr=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_curses_tgetstr=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_curses_tgetstr" >&5
+echo "${ECHO_T}$ac_cv_lib_curses_tgetstr" >&6
+if test $ac_cv_lib_curses_tgetstr = yes; then
+
+ cat >>confdefs.h <<\_ACEOF
+#define USE_TERMCAP 1
+_ACEOF
+
+ LIBS="$LIBS -lcurses"
+ if test "${ac_cv_header_termcap_h+set}" = set; then
+ echo "$as_me:$LINENO: checking for termcap.h" >&5
+echo $ECHO_N "checking for termcap.h... $ECHO_C" >&6
+if test "${ac_cv_header_termcap_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_termcap_h" >&5
+echo "${ECHO_T}$ac_cv_header_termcap_h" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking termcap.h usability" >&5
+echo $ECHO_N "checking termcap.h usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <termcap.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking termcap.h presence" >&5
+echo $ECHO_N "checking termcap.h presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <termcap.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc in
+ yes:no )
+ { echo "$as_me:$LINENO: WARNING: termcap.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: termcap.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: termcap.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: termcap.h: proceeding with the preprocessor's result" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to bug-autoconf@gnu.org. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+ no:yes )
+ { echo "$as_me:$LINENO: WARNING: termcap.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: termcap.h: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: termcap.h: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: termcap.h: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: termcap.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: termcap.h: proceeding with the preprocessor's result" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to bug-autoconf@gnu.org. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for termcap.h" >&5
+echo $ECHO_N "checking for termcap.h... $ECHO_C" >&6
+if test "${ac_cv_header_termcap_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_header_termcap_h=$ac_header_preproc
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_termcap_h" >&5
+echo "${ECHO_T}$ac_cv_header_termcap_h" >&6
+
+fi
+if test $ac_cv_header_termcap_h = yes; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_TERMCAP_H 1
+_ACEOF
+
+fi
+
+
+
+fi
+
+fi
+
+fi
+
+
+
+
+for ac_header in curses.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc in
+ yes:no )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to bug-autoconf@gnu.org. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+ no:yes )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to bug-autoconf@gnu.org. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+for ac_header in term.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <curses.h>
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_Header=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_Header=no"
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+else
+
+for ac_header in ncurses/curses.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc in
+ yes:no )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to bug-autoconf@gnu.org. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+ no:yes )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to bug-autoconf@gnu.org. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+for ac_header in ncurses/term.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ncurses/curses.h>
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_Header=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_Header=no"
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+fi
+
+done
+
+fi
+
+done
+
+
+
+
+TARGETS="normal reentrant"
+
+
+echo "$as_me:$LINENO: checking for reentrant functions" >&5
+echo $ECHO_N "checking for reentrant functions... $ECHO_C" >&6
+if test "${tecla_cv_reentrant+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ KEPT_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -D_POSIX_C_SOURCE=199506L"
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <pwd.h>
+
+int
+main ()
+{
+
+ (void) readdir_r(NULL, NULL, NULL);
+ (void) getpwuid_r(geteuid(), NULL, NULL, 0, NULL);
+ (void) getpwnam_r(NULL, NULL, NULL, 0, NULL);
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ tecla_cv_reentrant=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+tecla_cv_reentrant=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+ CFLAGS="$KEPT_CFLAGS"
+
+fi
+echo "$as_me:$LINENO: result: $tecla_cv_reentrant" >&5
+echo "${ECHO_T}$tecla_cv_reentrant" >&6
+
+
+if test $tecla_cv_reentrant = no; then
+ TARGETS="normal"
+fi
+
+
+if test "${ac_cv_header_sys_select_h+set}" = set; then
+ echo "$as_me:$LINENO: checking for sys/select.h" >&5
+echo $ECHO_N "checking for sys/select.h... $ECHO_C" >&6
+if test "${ac_cv_header_sys_select_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_sys_select_h" >&5
+echo "${ECHO_T}$ac_cv_header_sys_select_h" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking sys/select.h usability" >&5
+echo $ECHO_N "checking sys/select.h usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <sys/select.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking sys/select.h presence" >&5
+echo $ECHO_N "checking sys/select.h presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/select.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc in
+ yes:no )
+ { echo "$as_me:$LINENO: WARNING: sys/select.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: sys/select.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: sys/select.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: sys/select.h: proceeding with the preprocessor's result" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to bug-autoconf@gnu.org. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+ no:yes )
+ { echo "$as_me:$LINENO: WARNING: sys/select.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: sys/select.h: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: sys/select.h: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: sys/select.h: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: sys/select.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: sys/select.h: proceeding with the preprocessor's result" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to bug-autoconf@gnu.org. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for sys/select.h" >&5
+echo $ECHO_N "checking for sys/select.h... $ECHO_C" >&6
+if test "${ac_cv_header_sys_select_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_header_sys_select_h=$ac_header_preproc
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_sys_select_h" >&5
+echo "${ECHO_T}$ac_cv_header_sys_select_h" >&6
+
+fi
+if test $ac_cv_header_sys_select_h = yes; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_SYS_SELECT_H 1
+_ACEOF
+
+fi
+
+
+
+
+echo "$as_me:$LINENO: checking for select system call" >&5
+echo $ECHO_N "checking for select system call... $ECHO_C" >&6
+if test "${tecla_cv_select+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+int
+main ()
+{
+
+ fd_set fds;
+ int nready;
+ FD_ZERO(&fds);
+ FD_SET(1, &fds);
+ nready = select(2, &fds, &fds, &fds, NULL);
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ tecla_cv_select=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+tecla_cv_select=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+
+fi
+echo "$as_me:$LINENO: result: $tecla_cv_select" >&5
+echo "${ECHO_T}$tecla_cv_select" >&6
+
+
+if test $tecla_cv_select = yes; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_SELECT 1
+_ACEOF
+
+fi
+
+
+echo "$as_me:$LINENO: checking for SysV pseudo-terminals" >&5
+echo $ECHO_N "checking for SysV pseudo-terminals... $ECHO_C" >&6
+if test "${tecla_cv_sysv_pty+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stropts.h>
+
+int
+main ()
+{
+
+ char *name = ptsname(0);
+ int i1 = grantpt(0);
+ int i2 = unlockpt(0);
+ int i3 = ioctl(0, I_PUSH, "ptem");
+ return 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ tecla_cv_sysv_pty=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+tecla_cv_sysv_pty=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+
+fi
+echo "$as_me:$LINENO: result: $tecla_cv_sysv_pty" >&5
+echo "${ECHO_T}$tecla_cv_sysv_pty" >&6
+
+
+if test $tecla_cv_sysv_pty = yes; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_SYSV_PTY 1
+_ACEOF
+
+fi
+
+
+
+SHARED_EXT=""
+
+
+
+SHARED_ALT=""
+
+
+
+SHARED_CFLAGS=""
+
+
+
+LINK_SHARED=""
+
+
+
+DEFS_R="-D_POSIX_C_SOURCE=199506L -DPREFER_REENTRANT"
+
+
+
+
+LIBR_MANDIR="man3"
+LIBR_MANEXT="3"
+
+
+
+
+FUNC_MANDIR="man3"
+FUNC_MANEXT="3"
+
+
+
+
+PROG_MANDIR="man1"
+PROG_MANEXT="1"
+
+
+
+
+MISC_MANDIR="man7"
+MISC_MANEXT="7"
+
+
+
+
+FILE_MANDIR="man5"
+FILE_MANEXT="5"
+
+
+
+# Check whether --with-file-actions or --without-file-actions was given.
+if test "${with_file_actions+set}" = set; then
+ withval="$with_file_actions"
+ cat >>confdefs.h <<\_ACEOF
+#define HIDE_FILE_SYSTEM 1
+_ACEOF
+
+fi;
+
+
+
+# Check whether --with-file-system or --without-file-system was given.
+if test "${with_file_system+set}" = set; then
+ withval="$with_file_system"
+ cat >>confdefs.h <<\_ACEOF
+#define WITHOUT_FILE_SYSTEM 1
+_ACEOF
+
+fi;
+
+
+case $target in
+*solaris*)
+ cat >>confdefs.h <<\_ACEOF
+#define __EXTENSIONS__ 1
+_ACEOF
+
+ SHARED_EXT=".so.${MAJOR_VER}"
+ SHARED_ALT=".so"
+ LINK_SHARED="$LD"' -G -M $$(srcdir)/libtecla.map -o $$@ -h $$(@F) -z defs -i $$(LIB_OBJECTS) $$(LIBS) -lc'
+ SHARED_CFLAGS="-Kpic"
+ case $CC in
+ */cc|cc) SHARED_CFLAGS="$SHARED_CFLAGS -xstrconst" ;;
+ esac
+ case $target_cpu in
+ sparc) SHARED_CFLAGS="$SHARED_CFLAGS -xregs=no%appl"
+ esac
+ case $target_os in
+ solaris2.[89]*|solaris2.1[0-9]*)
+ LIBR_MANEXT=3lib
+ FUNC_MANEXT=3tecla
+ LIBR_MANDIR=man$LIBR_MANEXT
+ FUNC_MANDIR=man$FUNC_MANEXT
+ esac
+ MISC_MANDIR="man5"
+ MISC_MANEXT="5"
+ FILE_MANDIR="man4"
+ FILE_MANEXT="4"
+ ;;
+*linux*)
+ SHARED_EXT=".so.${MAJOR_VER}.${MINOR_VER}.${MICRO_VER}"
+ SHARED_ALT=".so .so.${MAJOR_VER}"
+
+
+ echo "$as_me:$LINENO: checking for --version-script in GNU ld" >&5
+echo $ECHO_N "checking for --version-script in GNU ld... $ECHO_C" >&6
+if test "${tecla_cv_gnu_ld_script+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ if (echo 'void dummy(void) {return;}' > dummy.c; $CC -c -fpic dummy.c; \
+ $LD -o dummy.so dummy.o -shared --version-script=$srcdir/libtecla.map) 1>&2 2>/dev/null; then
+ tecla_cv_gnu_ld_script=yes
+ else
+ tecla_cv_gnu_ld_script=no
+ fi
+ rm -f dummy.c dummy.o dummy.so
+
+fi
+echo "$as_me:$LINENO: result: $tecla_cv_gnu_ld_script" >&5
+echo "${ECHO_T}$tecla_cv_gnu_ld_script" >&6
+ if test $tecla_cv_gnu_ld_script = yes; then
+ VERSION_OPT='--version-script=$$(srcdir)/libtecla.map'
+ else
+ VERSION_OPT=''
+ fi
+
+ LINK_SHARED="$LD"' -o $$@ -soname libtecla$$(SUFFIX).so.'${MAJOR_VER}' -shared '$VERSION_OPT' $$(LIB_OBJECTS) $$(LIBS) -lc'
+ SHARED_CFLAGS="-fpic"
+
+
+ CFLAGS="-D_SVID_SOURCE -D_BSD_SOURCE $CFLAGS"
+ ;;
+*hpux*)
+ SHARED_EXT=".${MAJOR_VER}"
+ SHARED_ALT=".sl"
+ LINK_SHARED="$LD"' -b +h $$(@F) +k +vshlibunsats -o $$@ -c libtecla.map.opt $$(LIB_OBJECTS) $$(LIBS) -lc'
+ SHARED_CFLAGS="+z"
+ MISC_MANEXT=5
+ FILE_MANEXT=4
+ MISC_MANDIR=man$MISC_MANEXT
+ FILE_MANDIR=man$FILE_MANEXT
+ ;;
+*darwin*)
+ SHARED_EXT=".${MAJOR_VER}.${MINOR_VER}.${MICRO_VER}.dylib"
+ SHARED_ALT=".dylib .${MAJOR_VER}.dylib"
+ LINK_SHARED='$(CC) -o $$@ -dynamiclib -flat_namespace -undefined suppress -compatibility_version '${MAJOR_VER}.${MINOR_VER}' -current_version '${MAJOR_VER}.${MINOR_VER}.${MICRO_VER}' -install_name '${libdir}'/$$@ $$(LIB_OBJECTS)'
+ SHARED_CFLAGS=""
+ ;;
+*dec-osf*)
+ cat >>confdefs.h <<\_ACEOF
+#define _OSF_SOURCE 1
+_ACEOF
+
+ ;;
+*freebsd*)
+ SHARED_EXT=".so.${MAJOR_VER}"
+ SHARED_ALT=".so"
+ VERSION_OPT='--version-script=$$(srcdir)/libtecla.map'
+ LINK_SHARED='ld -o $$@ -soname libtecla$$(SUFFIX).so.'${MAJOR_VER}' -shared '$VERSION_OPT' $$(LIB_OBJECTS) $$(LIBS) -lc'
+ SHARED_CFLAGS="-fpic"
+ ;;
+mips-sgi-irix*)
+ DEFS_R="$DEFS_R -D_XOPEN_SOURCE=500"
+ if test "$RANLIB"_ = "_"; then
+ RANLIB=":"
+ fi
+ ;;
+esac
+
+
+if test "$GCC"_ = "yes"_ && test "$LINK_SHARED"_ != "_" ; then
+ SHARED_CFLAGS="-fpic"
+ case $target in
+ sparc-*-solaris*)
+ SHARED_CFLAGS="$SHARED_CFLAGS -mno-app-regs"
+ ;;
+ *darwin*)
+ SHARED_CFLAGS=""
+ ;;
+ esac
+ LINK_SHARED="$LINK_SHARED `gcc -print-libgcc-file-name`"
+fi
+
+
+
+
+
+if test "$LINK_SHARED"_ != "_"; then
+ TARGET_LIBS="static shared"
+else
+ TARGET_LIBS="static"
+ LINK_SHARED="@:"
+fi
+
+
+
+
+# Check whether --with-man-pages or --without-man-pages was given.
+if test "${with_man_pages+set}" = set; then
+ withval="$with_man_pages"
+ MAKE_MAN_PAGES="$withval"
+else
+ MAKE_MAN_PAGES="yes"
+fi;
+
+
+OUTPUT_FILES="Makefile"
+rm -rf man/man*
+if test "$MAKE_MAN_PAGES"_ = "yes"_; then
+ for area in libr func misc prog file; do
+ for page in man/$area/*.in; do
+ OUTPUT_FILES="$OUTPUT_FILES `echo $page | sed 's/\.in$//'`"
+ done
+ done
+fi
+
+
+ ac_config_files="$ac_config_files $OUTPUT_FILES"
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+{
+ (set) 2>&1 |
+ case `(ac_space=' '; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;;
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n \
+ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+ ;;
+ esac;
+} |
+ sed '
+ t clear
+ : clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ : end' >>confcache
+if diff $cache_file confcache >/dev/null 2>&1; then :; else
+ if test -w $cache_file; then
+ test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file"
+ cat confcache >$cache_file
+ else
+ echo "not updating unwritable cache $cache_file"
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# VPATH may cause trouble with some makes, so we remove $(srcdir),
+# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=/{
+s/:*\$(srcdir):*/:/;
+s/:*\${srcdir}:*/:/;
+s/:*@srcdir@:*/:/;
+s/^\([^=]*=[ ]*\):*/\1/;
+s/:*$//;
+s/^[^=]*=[ ]*$//;
+}'
+fi
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then we branch to the quote section. Otherwise,
+# look for a macro that doesn't take arguments.
+cat >confdef2opt.sed <<\_ACEOF
+t clear
+: clear
+s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\),-D\1=\2,g
+t quote
+s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\),-D\1=\2,g
+t quote
+d
+: quote
+s,[ `~#$^&*(){}\\|;'"<>?],\\&,g
+s,\[,\\&,g
+s,\],\\&,g
+s,\$,$$,g
+p
+_ACEOF
+# We use echo to avoid assuming a particular line-breaking character.
+# The extra dot is to prevent the shell from consuming trailing
+# line-breaks from the sub-command output. A line-break within
+# single-quotes doesn't work because, if this script is created in a
+# platform that uses two characters for line-breaks (e.g., DOS), tr
+# would break.
+ac_LF_and_DOT=`echo; echo .`
+DEFS=`sed -n -f confdef2opt.sed confdefs.h | tr "$ac_LF_and_DOT" ' .'`
+rm -f confdef2opt.sed
+
+
+ac_libobjs=
+ac_ltlibobjs=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_i=`echo "$ac_i" |
+ sed 's/\$U\././;s/\.o$//;s/\.obj$//'`
+ # 2. Add them.
+ ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext"
+ ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: ${CONFIG_STATUS=./config.status}
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5
+echo "$as_me: creating $CONFIG_STATUS" >&6;}
+cat >$CONFIG_STATUS <<_ACEOF
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+SHELL=\${CONFIG_SHELL-$SHELL}
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+## --------------------- ##
+## M4sh Initialization. ##
+## --------------------- ##
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+ set -o posix
+fi
+
+# Support unset when possible.
+if (FOO=FOO; unset FOO) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
+
+
+# Work around bugs in pre-3.0 UWIN ksh.
+$as_unset ENV MAIL MAILPATH
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+ LC_TELEPHONE LC_TIME
+do
+ if (set +x; test -n "`(eval $as_var=C; export $as_var) 2>&1`"); then
+ eval $as_var=C; export $as_var
+ else
+ $as_unset $as_var
+ fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)$' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
+ /^X\/\(\/\/\)$/{ s//\1/; q; }
+ /^X\/\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+
+
+# PATH needs CR, and LINENO needs CR and PATH.
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conf$$.sh
+ echo "exit 0" >>conf$$.sh
+ chmod +x conf$$.sh
+ if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conf$$.sh
+fi
+
+
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" || {
+ # Find who we are. Look in the path if we contain no path at all
+ # relative or not.
+ case $0 in
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+
+ ;;
+ esac
+ # We did not find ourselves, most probably we were run as `sh COMMAND'
+ # in which case we are not to be found in the path.
+ if test "x$as_myself" = x; then
+ as_myself=$0
+ fi
+ if test ! -f "$as_myself"; then
+ { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5
+echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ case $CONFIG_SHELL in
+ '')
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for as_base in sh bash ksh sh5; do
+ case $as_dir in
+ /*)
+ if ("$as_dir/$as_base" -c '
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then
+ $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; }
+ $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; }
+ CONFIG_SHELL=$as_dir/$as_base
+ export CONFIG_SHELL
+ exec "$CONFIG_SHELL" "$0" ${1+"$@"}
+ fi;;
+ esac
+ done
+done
+;;
+ esac
+
+ # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+ # uniformly replaced by the line number. The first 'sed' inserts a
+ # line-number line before each line; the second 'sed' does the real
+ # work. The second script uses 'N' to pair each line-number line
+ # with the numbered line, and appends trailing '-' during
+ # substitution so that $LINENO is not a special case at line end.
+ # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+ # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-)
+ sed '=' <$as_myself |
+ sed '
+ N
+ s,$,-,
+ : loop
+ s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
+ t loop
+ s,-$,,
+ s,^['$as_cr_digits']*\n,,
+ ' >$as_me.lineno &&
+ chmod +x $as_me.lineno ||
+ { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5
+echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;}
+ { (exit 1); exit 1; }; }
+
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensible to this).
+ . ./$as_me.lineno
+ # Exit status is that of the last command.
+ exit
+}
+
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+ *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T=' ' ;;
+ *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+ *) ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+ # We could just check for DJGPP; but this test a) works b) is more generic
+ # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+ if test -f conf$$.exe; then
+ # Don't use ln at all; we don't have any links
+ as_ln_s='cp -p'
+ else
+ as_ln_s='ln -s'
+ fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.file
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p=:
+else
+ as_mkdir_p=false
+fi
+
+as_executable_p="test -f"
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="sed y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="sed y%*+%pp%;s%[^_$as_cr_alnum]%_%g"
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" $as_nl"
+
+# CDPATH.
+$as_unset CDPATH
+
+exec 6>&1
+
+# Open the log real soon, to keep \$[0] and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling. Logging --version etc. is OK.
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+} >&5
+cat >&5 <<_CSEOF
+
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.57. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+_CSEOF
+echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5
+echo >&5
+_ACEOF
+
+# Files that config.status was made for.
+if test -n "$ac_config_files"; then
+ echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_headers"; then
+ echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_links"; then
+ echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_commands"; then
+ echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+ac_cs_usage="\
+\`$as_me' instantiates files from templates according to the
+current configuration.
+
+Usage: $0 [OPTIONS] [FILE]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number, then exit
+ -q, --quiet do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to <bug-autoconf@gnu.org>."
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.57,
+ with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
+
+Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+srcdir=$srcdir
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+# If no file are specified by the user, then we need to provide default
+# value. By we need to know if files were specified by the user.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=*)
+ ac_option=`expr "x$1" : 'x\([^=]*\)='`
+ ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ -*)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ *) # This is not an option, so the user has probably given explicit
+ # arguments.
+ ac_option=$1
+ ac_need_defaults=false;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --vers* | -V )
+ echo "$ac_cs_version"; exit 0 ;;
+ --he | --h)
+ # Conflict between --help and --header
+ { { echo "$as_me:$LINENO: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&2;}
+ { (exit 1); exit 1; }; };;
+ --help | --hel | -h )
+ echo "$ac_cs_usage"; exit 0 ;;
+ --debug | --d* | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ CONFIG_FILES="$CONFIG_FILES $ac_optarg"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg"
+ ac_need_defaults=false;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&2;}
+ { (exit 1); exit 1; }; } ;;
+
+ *) ac_config_targets="$ac_config_targets $1" ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+if \$ac_cs_recheck; then
+ echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6
+ exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+fi
+
+_ACEOF
+
+
+
+
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+for ac_config_target in $ac_config_targets
+do
+ case "$ac_config_target" in
+ # Handling of arguments.
+ "$OUTPUT_FILES" ) CONFIG_FILES="$CONFIG_FILES $OUTPUT_FILES" ;;
+ *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
+echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason to put it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Create a temporary directory, and hook for its removal unless debugging.
+$debug ||
+{
+ trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0
+ trap '{ (exit 1); exit 1; }' 1 2 13 15
+}
+
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` &&
+ test -n "$tmp" && test -d "$tmp"
+} ||
+{
+ tmp=./confstat$$-$RANDOM
+ (umask 077 && mkdir $tmp)
+} ||
+{
+ echo "$me: cannot create a temporary directory in ." >&2
+ { (exit 1); exit 1; }
+}
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+
+#
+# CONFIG_FILES section.
+#
+
+# No need to generate the scripts if there are no CONFIG_FILES.
+# This happens for instance when ./config.status config.h
+if test -n "\$CONFIG_FILES"; then
+ # Protect against being on the right side of a sed subst in config.status.
+ sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g;
+ s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF
+s,@SHELL@,$SHELL,;t t
+s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t
+s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t
+s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t
+s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t
+s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t
+s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t
+s,@exec_prefix@,$exec_prefix,;t t
+s,@prefix@,$prefix,;t t
+s,@program_transform_name@,$program_transform_name,;t t
+s,@bindir@,$bindir,;t t
+s,@sbindir@,$sbindir,;t t
+s,@libexecdir@,$libexecdir,;t t
+s,@datadir@,$datadir,;t t
+s,@sysconfdir@,$sysconfdir,;t t
+s,@sharedstatedir@,$sharedstatedir,;t t
+s,@localstatedir@,$localstatedir,;t t
+s,@libdir@,$libdir,;t t
+s,@includedir@,$includedir,;t t
+s,@oldincludedir@,$oldincludedir,;t t
+s,@infodir@,$infodir,;t t
+s,@mandir@,$mandir,;t t
+s,@build_alias@,$build_alias,;t t
+s,@host_alias@,$host_alias,;t t
+s,@target_alias@,$target_alias,;t t
+s,@DEFS@,$DEFS,;t t
+s,@ECHO_C@,$ECHO_C,;t t
+s,@ECHO_N@,$ECHO_N,;t t
+s,@ECHO_T@,$ECHO_T,;t t
+s,@LIBS@,$LIBS,;t t
+s,@MAJOR_VER@,$MAJOR_VER,;t t
+s,@MINOR_VER@,$MINOR_VER,;t t
+s,@MICRO_VER@,$MICRO_VER,;t t
+s,@CC@,$CC,;t t
+s,@CFLAGS@,$CFLAGS,;t t
+s,@LDFLAGS@,$LDFLAGS,;t t
+s,@CPPFLAGS@,$CPPFLAGS,;t t
+s,@ac_ct_CC@,$ac_ct_CC,;t t
+s,@EXEEXT@,$EXEEXT,;t t
+s,@OBJEXT@,$OBJEXT,;t t
+s,@SET_MAKE@,$SET_MAKE,;t t
+s,@LN_S@,$LN_S,;t t
+s,@AWK@,$AWK,;t t
+s,@RANLIB@,$RANLIB,;t t
+s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t
+s,@LD@,$LD,;t t
+s,@ac_ct_LD@,$ac_ct_LD,;t t
+s,@build@,$build,;t t
+s,@build_cpu@,$build_cpu,;t t
+s,@build_vendor@,$build_vendor,;t t
+s,@build_os@,$build_os,;t t
+s,@host@,$host,;t t
+s,@host_cpu@,$host_cpu,;t t
+s,@host_vendor@,$host_vendor,;t t
+s,@host_os@,$host_os,;t t
+s,@target@,$target,;t t
+s,@target_cpu@,$target_cpu,;t t
+s,@target_vendor@,$target_vendor,;t t
+s,@target_os@,$target_os,;t t
+s,@CPP@,$CPP,;t t
+s,@EGREP@,$EGREP,;t t
+s,@TARGETS@,$TARGETS,;t t
+s,@SHARED_EXT@,$SHARED_EXT,;t t
+s,@SHARED_ALT@,$SHARED_ALT,;t t
+s,@SHARED_CFLAGS@,$SHARED_CFLAGS,;t t
+s,@LINK_SHARED@,$LINK_SHARED,;t t
+s,@DEFS_R@,$DEFS_R,;t t
+s,@LIBR_MANDIR@,$LIBR_MANDIR,;t t
+s,@LIBR_MANEXT@,$LIBR_MANEXT,;t t
+s,@FUNC_MANDIR@,$FUNC_MANDIR,;t t
+s,@FUNC_MANEXT@,$FUNC_MANEXT,;t t
+s,@PROG_MANDIR@,$PROG_MANDIR,;t t
+s,@PROG_MANEXT@,$PROG_MANEXT,;t t
+s,@MISC_MANDIR@,$MISC_MANDIR,;t t
+s,@MISC_MANEXT@,$MISC_MANEXT,;t t
+s,@FILE_MANDIR@,$FILE_MANDIR,;t t
+s,@FILE_MANEXT@,$FILE_MANEXT,;t t
+s,@TARGET_LIBS@,$TARGET_LIBS,;t t
+s,@MAKE_MAN_PAGES@,$MAKE_MAN_PAGES,;t t
+s,@LIBOBJS@,$LIBOBJS,;t t
+s,@LTLIBOBJS@,$LTLIBOBJS,;t t
+CEOF
+
+_ACEOF
+
+ cat >>$CONFIG_STATUS <<\_ACEOF
+ # Split the substitutions into bite-sized pieces for seds with
+ # small command number limits, like on Digital OSF/1 and HP-UX.
+ ac_max_sed_lines=48
+ ac_sed_frag=1 # Number of current file.
+ ac_beg=1 # First line for current file.
+ ac_end=$ac_max_sed_lines # Line after last line for current file.
+ ac_more_lines=:
+ ac_sed_cmds=
+ while $ac_more_lines; do
+ if test $ac_beg -gt 1; then
+ sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+ else
+ sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+ fi
+ if test ! -s $tmp/subs.frag; then
+ ac_more_lines=false
+ else
+ # The purpose of the label and of the branching condition is to
+ # speed up the sed processing (if there are no `@' at all, there
+ # is no need to browse any of the substitutions).
+ # These are the two extra sed commands mentioned above.
+ (echo ':t
+ /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed"
+ fi
+ ac_sed_frag=`expr $ac_sed_frag + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_lines`
+ fi
+ done
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
+ fi
+fi # test -n "$CONFIG_FILES"
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case $ac_file in
+ - | *:- | *:-:* ) # input from stdin
+ cat >$tmp/stdin
+ ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ * ) ac_file_in=$ac_file.in ;;
+ esac
+
+ # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories.
+ ac_dir=`(dirname "$ac_file") 2>/dev/null ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ { if $as_mkdir_p; then
+ mkdir -p "$ac_dir"
+ else
+ as_dir="$ac_dir"
+ as_dirs=
+ while test ! -d "$as_dir"; do
+ as_dirs="$as_dir $as_dirs"
+ as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ done
+ test ! -n "$as_dirs" || mkdir $as_dirs
+ fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5
+echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;}
+ { (exit 1); exit 1; }; }; }
+
+ ac_builddir=.
+
+if test "$ac_dir" != .; then
+ ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+ ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+ .) # No --srcdir option. We are building in place.
+ ac_srcdir=.
+ if test -z "$ac_top_builddir"; then
+ ac_top_srcdir=.
+ else
+ ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+ fi ;;
+ [\\/]* | ?:[\\/]* ) # Absolute path.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir ;;
+ *) # Relative path.
+ ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+# Don't blindly perform a `cd "$ac_dir"/$ac_foo && pwd` since $ac_foo can be
+# absolute.
+ac_abs_builddir=`cd "$ac_dir" && cd $ac_builddir && pwd`
+ac_abs_top_builddir=`cd "$ac_dir" && cd ${ac_top_builddir}. && pwd`
+ac_abs_srcdir=`cd "$ac_dir" && cd $ac_srcdir && pwd`
+ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd`
+
+
+
+ if test x"$ac_file" != x-; then
+ { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+ rm -f "$ac_file"
+ fi
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ if test x"$ac_file" = x-; then
+ configure_input=
+ else
+ configure_input="$ac_file. "
+ fi
+ configure_input=$configure_input"Generated from `echo $ac_file_in |
+ sed 's,.*/,,'` by configure."
+
+ # First look for the input files in the build tree, otherwise in the
+ # src tree.
+ ac_file_inputs=`IFS=:
+ for f in $ac_file_in; do
+ case $f in
+ -) echo $tmp/stdin ;;
+ [\\/$]*)
+ # Absolute (can't be DOS-style, as IFS=:)
+ test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ echo $f;;
+ *) # Relative
+ if test -f "$f"; then
+ # Build tree
+ echo $f
+ elif test -f "$srcdir/$f"; then
+ # Source tree
+ echo $srcdir/$f
+ else
+ # /dev/null tree
+ { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ fi;;
+ esac
+ done` || { (exit 1); exit 1; }
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+ sed "$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s,@configure_input@,$configure_input,;t t
+s,@srcdir@,$ac_srcdir,;t t
+s,@abs_srcdir@,$ac_abs_srcdir,;t t
+s,@top_srcdir@,$ac_top_srcdir,;t t
+s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t
+s,@builddir@,$ac_builddir,;t t
+s,@abs_builddir@,$ac_abs_builddir,;t t
+s,@top_builddir@,$ac_top_builddir,;t t
+s,@abs_top_builddir@,$ac_abs_top_builddir,;t t
+" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out
+ rm -f $tmp/stdin
+ if test x"$ac_file" != x-; then
+ mv $tmp/out $ac_file
+ else
+ cat $tmp/out
+ rm -f $tmp/out
+ fi
+
+done
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+{ (exit 0); exit 0; }
+_ACEOF
+chmod +x $CONFIG_STATUS
+ac_clean_files=$ac_clean_files_save
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || { (exit 1); exit 1; }
+fi
+
diff --git a/libtecla-1.4.1/configure.in b/libtecla-1.6.1/configure.in
index 3b083b9..78e7170 100644
--- a/libtecla-1.4.1/configure.in
+++ b/libtecla-1.6.1/configure.in
@@ -32,7 +32,7 @@ dnl small integer number, which should be reset to 0 whenever the
dnl major version number is incremented.
AC_SUBST(MINOR_VER)
-MINOR_VER="4"
+MINOR_VER="6"
dnl Set the micro version number of the tecla library. This is
dnl incremented whenever modifications to the library are made which
@@ -78,8 +78,14 @@ AC_PROG_AWK
dnl If ranlib is needed on the target system, the RANLIB make variable
dnl is set to ranlib. Otherwise it is set to :, which is the do-nothing
dnl command of the bourne shell.
+dnl Note that we do not use AC_PROG_RANLIB because (at least in
+dnl autoconf 2.53) this does not check for cross-compilation.
-AC_PROG_RANLIB
+AC_CHECK_TOOL(RANLIB, ranlib)
+
+dnl Set LD as appropriate, especially when cross-compiling
+
+AC_CHECK_TOOL(LD, ld)
dnl The following directive tells autoconf to figure out the target
dnl system type and assign a canonical name for this to the $target
@@ -97,12 +103,36 @@ dnl outermost quotes when it processes this file, we have to double
dnl them up here to get [0-6] to appear in the output configure
dnl script.
-case $target in
-*-sun-solaris2.[[0-6]]|*-sun-solaris2.[[0-6]].*)
+case $target_os in
+solaris2.[[0-6]]|solaris2.[[0-6]].*)
LIBS="$LIBS -L/usr/ccs/lib"
;;
esac
+dnl Recent versions of gcc place /usr/local/include at the head of the
+dnl system include-file search path. This causes problems when include
+dnl files that have the same name as standard system include files are
+dnl placed in this directory by third-party packages. To avoid this,
+dnl move /usr/local/include to the end of the search path.
+
+if test "$GCC"_ = "yes"_; then
+ touch foo.c
+ fix=`$CC -E -Wp,-v foo.c 2>&1 | $AWK '
+ /^#include <...> search starts here:/ {in_list=1;ndir=0}
+ / *\// && in_list {path[[ndir++]] = $1}
+ /^End of search list/ {in_list=0}
+ END {
+ if(path[[0]] ~ /\/usr\/local\/include/) {
+ for(dir=1; dir<ndir; dir++) {
+ printf(" -isystem %s", path[[dir]])
+ }
+ printf("\n");
+ }
+ }'`
+ rm -f foo.c
+ CFLAGS="$CFLAGS$fix"
+fi
+
dnl The following lines look for terminfo functions in the normal
dnl curses library. If not found, they are searched for in the GNU
dnl ncurses library. If the terminfo functions still aren't found,
@@ -124,24 +154,16 @@ AC_CHECK_LIB(curses, tigetstr, [
AC_CHECK_HEADER(termcap.h, AC_DEFINE(HAVE_TERMCAP_H))
])])])
-dnl Some systems don't have term.h, some systems squirrel it away
-dnl in an ncurses sub-directory of the system include directory.
-dnl If term.h exists in the normal location, arrange for HAVE_TERM_H
-dnl to be added to CFLAGS in the Makefile, by appending it to the
-dnl DEFINES shell variable. Otherwise, if it exists under an ncurses
-dnl sub-directory, arrange for HAVE_NCURSES_TERM_H to be set instead.
-dnl If it isn't found in either of these places, neither of these
-dnl variables is set, so term.h just doesn't get included.
-
-AC_CHECK_HEADER(term.h, AC_DEFINE(HAVE_TERM_H), [
- AC_CHECK_HEADER(ncurses/term.h, AC_DEFINE(HAVE_NCURSES_TERM_H))
-])
-
-dnl Do the same search for curses.h.
+dnl Search for the curses.h and term.h header files, first in the
+dnl standard system-include directories, and then if not found there,
+dnl in any ncurses subdirectories of these directories. If found, have
+dnl CFLAGS define C macros such as HAVE_TERM_H or HAVE_NCURSES_TERM_H.
+dnl Note that on some systems trying to compile term.h without first
+dnl including curses.h causes complaints, so when checking for term.h
+dnl we tell AC_CHECK_HEADERS() to include curses.h in the test file
+dnl that it attempts to compile.
-AC_CHECK_HEADER(curses.h, AC_DEFINE(HAVE_CURSES_H), [
- AC_CHECK_HEADER(ncurses/curses.h, AC_DEFINE(HAVE_NCURSES_CURSES_H))
-])
+AC_CHECK_HEADERS(curses.h, [AC_CHECK_HEADERS(term.h,[],[],[#include <curses.h>])], [AC_CHECK_HEADERS(ncurses/curses.h, [AC_CHECK_HEADERS(ncurses/term.h,[],[],[#include <ncurses/curses.h>])])])
dnl The following variable lists the targets that will be created if
dnl the user runs make without any arguments. Initially we assume
@@ -189,6 +211,11 @@ if test $tecla_cv_reentrant = no; then
TARGETS="normal"
fi
+dnl If sys/select.h exists, arrange for the HAVE_SYS_SELECT_H C-macro to
+dnl be defined when compiling the library.
+
+AC_CHECK_HEADER(sys/select.h, AC_DEFINE(HAVE_SYS_SELECT_H))
+
dnl Check for the select system call with the normal arguments,
dnl by attempting to compile and link a temporary program which
dnl calls it, being sure to include the appropriate headers.
@@ -203,12 +230,12 @@ dnl writes "yes" or "no" to the terminal.
AC_CACHE_CHECK(for select system call, tecla_cv_select, [
AC_TRY_LINK([
-#ifdef HAVE_SELECT_H
-#include <select.h>
-#endif
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
], [
fd_set fds;
int nready;
@@ -299,6 +326,84 @@ dnl file.
AC_SUBST(LINK_SHARED)
LINK_SHARED=""
+dnl When compiling the reentrant version of the library, the following
+dnl compiler flags are presented to the compiler, in addition to those
+dnl that are used when compiling the non-reentrant version of the
+dnl library. The PREFER_REENTRANT macro is an internal libtecla macro
+dnl whose presence reports when the reentrant version of the library
+dnl is being compiled. This allows the code to determine when to
+dnl disable features that can't portably be implemented reentrantly,
+dnl such as username completion. The existence of the _POSIX_C_SOURCE
+dnl macro can't be reliably used for this purpose, since some systems
+dnl define it by default for all code.
+
+AC_SUBST(DEFS_R)
+DEFS_R="-D_POSIX_C_SOURCE=199506L -DPREFER_REENTRANT"
+
+dnl For man pages relating to library features, the following two
+dnl variables determine in which sub-directory of the top-level man
+dnl directory the man pages should go, and what file-name extensions
+dnl these files should have. On systems where the following defaults
+dnl are not valid, the default values should be overriden in the
+dnl target-specific case statement later in this file.
+
+AC_SUBST(LIBR_MANDIR)
+AC_SUBST(LIBR_MANEXT)
+LIBR_MANDIR="man3"
+LIBR_MANEXT="3"
+
+dnl For man pages relating to library functions, the following two
+dnl variables serve the same purpose as the previously described
+dnl LIBR_MANDIR and LIBR_MANEXT variables.
+
+AC_SUBST(FUNC_MANDIR)
+AC_SUBST(FUNC_MANEXT)
+FUNC_MANDIR="man3"
+FUNC_MANEXT="3"
+
+dnl For man pages relating to programs, the following two variables
+dnl serve the same purpose as the previously described LIBR_MANDIR
+dnl and LIBR_MANEXT variables.
+
+AC_SUBST(PROG_MANDIR)
+AC_SUBST(PROG_MANEXT)
+PROG_MANDIR="man1"
+PROG_MANEXT="1"
+
+dnl For man pages on miscellaneous topics, the following two variables
+dnl serve the same purpose as the previously described LIBR_MANDIR
+dnl and LIBR_MANEXT variables.
+
+AC_SUBST(MISC_MANDIR)
+AC_SUBST(MISC_MANEXT)
+MISC_MANDIR="man7"
+MISC_MANEXT="7"
+
+dnl For man pages relating to configuration files, the following two
+dnl variables serve the same purpose as the previously described
+dnl LIBR_MANDIR and LIBR_MANEXT variables.
+
+AC_SUBST(FILE_MANDIR)
+AC_SUBST(FILE_MANEXT)
+FILE_MANDIR="man5"
+FILE_MANEXT="5"
+
+dnl If the application doesn't want the user to have access to the
+dnl filesystem, it can remove all action functions that list, read or
+dnl write files, by including the configuration argument
+dnl --without-file-actions.
+
+AC_ARG_WITH(file-actions, AC_HELP_STRING([--with-file-actions], [Should users of gl_get_line() have access to the filesystem (default=yes)]),
+ AC_DEFINE(HIDE_FILE_SYSTEM), )
+
+dnl If the target system either has no file-system, or file-system access
+dnl isn't needed, libtecla can be made smaller by excluding all file and
+dnl directory access code. This is done by adding the configuration
+dnl argument --without-file-system.
+
+AC_ARG_WITH(file-system, AC_HELP_STRING([--with-file-system], [Does the target have a filesystem (default=yes)]),
+ AC_DEFINE(WITHOUT_FILE_SYSTEM), )
+
dnl The following bourne shell case statement is where system
dnl dependencies can be added. In particular, if your system supports
dnl shared library creation, the following switch is the place to
@@ -322,15 +427,25 @@ case $target in
AC_DEFINE(__EXTENSIONS__)
SHARED_EXT=".so.${MAJOR_VER}"
SHARED_ALT=".so"
- LINK_SHARED='ld -G -M $$(srcdir)/libtecla.map -o $$@ -h $$(@F) -z defs -i $$(LIB_OBJECTS) $$(LIBS) -lc'
+ LINK_SHARED="$LD"' -G -M $$(srcdir)/libtecla.map -o $$@ -h $$(@F) -z defs -i $$(LIB_OBJECTS) $$(LIBS) -lc'
SHARED_CFLAGS="-Kpic"
case $CC in
*/cc|cc) SHARED_CFLAGS="$SHARED_CFLAGS -xstrconst" ;;
- gcc) CFLAGS="-I/usr/include $CFLAGS" ;;
esac
- case $target in
- *sparc*) SHARED_CFLAGS="$SHARED_CFLAGS -xregs=no%appl"
+ case $target_cpu in
+ sparc) SHARED_CFLAGS="$SHARED_CFLAGS -xregs=no%appl"
+ esac
+ case $target_os in
+ solaris2.[[89]]*|solaris2.1[[0-9]]*)
+ LIBR_MANEXT=3lib
+ FUNC_MANEXT=3tecla
+ LIBR_MANDIR=man$LIBR_MANEXT
+ FUNC_MANDIR=man$FUNC_MANEXT
esac
+ MISC_MANDIR="man5"
+ MISC_MANEXT="5"
+ FILE_MANDIR="man4"
+ FILE_MANEXT="4"
;;
*linux*)
SHARED_EXT=".so.${MAJOR_VER}.${MINOR_VER}.${MICRO_VER}"
@@ -340,7 +455,7 @@ dnl See if the installed version of Gnu ld accepts version scripts.
AC_CACHE_CHECK([for --version-script in GNU ld], tecla_cv_gnu_ld_script, [
if (echo 'void dummy(void) {return;}' > dummy.c; $CC -c -fpic dummy.c; \
- ld -o dummy.so dummy.o -shared --version-script=$srcdir/libtecla.map) 1>&2 2>/dev/null; then
+ $LD -o dummy.so dummy.o -shared --version-script=$srcdir/libtecla.map) 1>&2 2>/dev/null; then
tecla_cv_gnu_ld_script=yes
else
tecla_cv_gnu_ld_script=no
@@ -353,18 +468,46 @@ dnl See if the installed version of Gnu ld accepts version scripts.
VERSION_OPT=''
fi
- LINK_SHARED='ld -o $$@ -soname libtecla$$(SUFFIX).so.'${MAJOR_VER}' -shared '$VERSION_OPT' $$(LIB_OBJECTS) $$(LIBS) -lc'
+ LINK_SHARED="$LD"' -o $$@ -soname libtecla$$(SUFFIX).so.'${MAJOR_VER}' -shared '$VERSION_OPT' $$(LIB_OBJECTS) $$(LIBS) -lc'
SHARED_CFLAGS="-fpic"
+
+dnl Reenable the inclusion of symbols which get undefined when POSIX_C_SOURCE
+dnl is specified.
+
+ CFLAGS="-D_SVID_SOURCE -D_BSD_SOURCE $CFLAGS"
;;
*hpux*)
SHARED_EXT=".${MAJOR_VER}"
SHARED_ALT=".sl"
- LINK_SHARED='ld -b +h $$(@F) +k +vshlibunsats -o $$@ -c libtecla.map.opt $$(LIB_OBJECTS) $$(LIBS) -lc'
+ LINK_SHARED="$LD"' -b +h $$(@F) +k +vshlibunsats -o $$@ -c libtecla.map.opt $$(LIB_OBJECTS) $$(LIBS) -lc'
SHARED_CFLAGS="+z"
+ MISC_MANEXT=5
+ FILE_MANEXT=4
+ MISC_MANDIR=man$MISC_MANEXT
+ FILE_MANDIR=man$FILE_MANEXT
+ ;;
+*darwin*)
+ SHARED_EXT=".${MAJOR_VER}.${MINOR_VER}.${MICRO_VER}.dylib"
+ SHARED_ALT=".dylib .${MAJOR_VER}.dylib"
+ LINK_SHARED='$(CC) -o $$@ -dynamiclib -flat_namespace -undefined suppress -compatibility_version '${MAJOR_VER}.${MINOR_VER}' -current_version '${MAJOR_VER}.${MINOR_VER}.${MICRO_VER}' -install_name '${libdir}'/$$@ $$(LIB_OBJECTS)'
+ SHARED_CFLAGS=""
;;
*dec-osf*)
AC_DEFINE(_OSF_SOURCE)
;;
+*freebsd*)
+ SHARED_EXT=".so.${MAJOR_VER}"
+ SHARED_ALT=".so"
+ VERSION_OPT='--version-script=$$(srcdir)/libtecla.map'
+ LINK_SHARED='ld -o $$@ -soname libtecla$$(SUFFIX).so.'${MAJOR_VER}' -shared '$VERSION_OPT' $$(LIB_OBJECTS) $$(LIBS) -lc'
+ SHARED_CFLAGS="-fpic"
+ ;;
+mips-sgi-irix*)
+ DEFS_R="$DEFS_R -D_XOPEN_SOURCE=500"
+ if test "$RANLIB"_ = "_"; then
+ RANLIB=":"
+ fi
+ ;;
esac
dnl The following statement checks to see if the GNU C compiler has
@@ -376,8 +519,13 @@ dnl library to the shared library link line.
if test "$GCC"_ = "yes"_ && test "$LINK_SHARED"_ != "_" ; then
SHARED_CFLAGS="-fpic"
- case $target_os in
- sparc*solaris*) SHARED_CFLAGS="$SHARED_CFLAGS -mno-app-regs"
+ case $target in
+ sparc-*-solaris*)
+ SHARED_CFLAGS="$SHARED_CFLAGS -mno-app-regs"
+ ;;
+ *darwin*)
+ SHARED_CFLAGS=""
+ ;;
esac
LINK_SHARED="$LINK_SHARED `gcc -print-libgcc-file-name`"
fi
@@ -397,6 +545,28 @@ else
LINK_SHARED="@:"
fi
+dnl Set the shell variable and Makefile variable, MAKE_MAN_PAGES, to
+dnl "yes" if man pages are desired. By default they are, but if the
+dnl user specifies --with-man-pages=no or --without-man-pages, then
+dnl they won't be preprocessed by the configure script or installed
+dnl by the Makefile.
+
+AC_SUBST(MAKE_MAN_PAGES)
+AC_ARG_WITH(man-pages, AC_HELP_STRING([--with-man-pages], [Are man pages desired (default=yes)]),
+ MAKE_MAN_PAGES="$withval", MAKE_MAN_PAGES="yes")
+
+dnl Create the list of files to be generated by the configure script.
+
+OUTPUT_FILES="Makefile"
+rm -rf man/man*
+if test "$MAKE_MAN_PAGES"_ = "yes"_; then
+ for area in libr func misc prog file; do
+ for page in man/$area/*.in; do
+ OUTPUT_FILES="$OUTPUT_FILES `echo $page | sed 's/\.in$//'`"
+ done
+ done
+fi
+
dnl The following directive must always be the last line of any
dnl autoconf script. It causes autoconf to create the configure
dnl script, which for each argument of AC_OUTPUT, will look for a
@@ -409,4 +579,4 @@ dnl with the AC_SUBST() directive will be substituted in @VAR@
dnl directives (some macros like AC_PROG_CC also call AC_SUBST for you
dnl for the variables that they output).
-AC_OUTPUT(Makefile)
+AC_OUTPUT($OUTPUT_FILES)
diff --git a/libtecla-1.4.1/cplfile.c b/libtecla-1.6.1/cplfile.c
index 73eef1d..eee3166 100644
--- a/libtecla-1.4.1/cplfile.c
+++ b/libtecla-1.6.1/cplfile.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2001 by Martin C. Shepherd.
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
*
* All rights reserved.
*
@@ -30,6 +30,12 @@
*/
/*
+ * If file-system access is to be excluded, this module has no function,
+ * so all of its code should be excluded.
+ */
+#ifndef WITHOUT_FILE_SYSTEM
+
+/*
* Standard includes.
*/
#include <stdio.h>
@@ -47,6 +53,7 @@
#include "homedir.h"
#include "pathutil.h"
#include "cplfile.h"
+#include "errmsg.h"
/*
* Set the maximum length allowed for usernames.
@@ -60,18 +67,11 @@
#define ENV_LEN 100
/*
- * Set the max length of the error-reporting string. There is no point
- * in this being longer than the width of a typical terminal window.
- * In composing error messages, I have assumed that this number is
- * at least 80, so you don't decrease it below this number.
- */
-#define ERRLEN 200
-
-/*
* The resources needed to complete a filename are maintained in objects
* of the following type.
*/
struct CompleteFile {
+ ErrMsg *err; /* The error reporting buffer */
DirReader *dr; /* A directory reader */
HomeDir *home; /* A home directory expander */
PathName *path; /* The buffer in which to accumulate the path */
@@ -80,7 +80,6 @@ struct CompleteFile {
/* users. */
char envnam[ENV_LEN+1]; /* The buffer used when reading the names of */
/* environment variables. */
- char errmsg[ERRLEN+1]; /* The error-report buffer */
};
static int cf_expand_home_dir(CompleteFile *cf, const char *user);
@@ -105,7 +104,7 @@ static int cf_prepare_suffix(CompleteFile *cf, const char *suffix,
typedef struct {
CompleteFile *cf; /* The file-completion resource object */
WordCompletion *cpl; /* The string-completion rsource object */
- const char *prefix; /* The username prefix to be completed */
+ size_t prefix_len; /* The length of the prefix being completed */
const char *line; /* The line from which the prefix was extracted */
int word_start; /* The index in line[] of the start of the username */
int word_end; /* The index in line[] following the end of the prefix */
@@ -126,7 +125,7 @@ CompleteFile *_new_CompleteFile(void)
*/
cf = (CompleteFile *) malloc(sizeof(CompleteFile));
if(!cf) {
- fprintf(stderr, "_new_CompleteFile: Insufficient memory.\n");
+ errno = ENOMEM;
return NULL;
};
/*
@@ -134,13 +133,19 @@ CompleteFile *_new_CompleteFile(void)
* container at least up to the point at which it can safely be passed
* to _del_CompleteFile().
*/
+ cf->err = NULL;
cf->dr = NULL;
cf->home = NULL;
cf->path = NULL;
cf->buff = NULL;
cf->usrnam[0] = '\0';
cf->envnam[0] = '\0';
- cf->errmsg[0] = '\0';
+/*
+ * Allocate a place to record error messages.
+ */
+ cf->err = _new_ErrMsg();
+ if(!cf->err)
+ return _del_CompleteFile(cf);
/*
* Create the object that is used for reading directories.
*/
@@ -179,6 +184,7 @@ CompleteFile *_new_CompleteFile(void)
CompleteFile *_del_CompleteFile(CompleteFile *cf)
{
if(cf) {
+ cf->err = _del_ErrMsg(cf->err);
cf->dr = _del_DirReader(cf->dr);
cf->home = _del_HomeDir(cf->home);
cf->path = _del_PathName(cf->path);
@@ -231,8 +237,10 @@ int _cf_complete_file(WordCompletion *cpl, CompleteFile *cf,
* Check the arguments.
*/
if(!cpl || !cf || !line || word_end < word_start) {
- if(cf)
- strcpy(cf->errmsg, "_cf_complete_file: Invalid arguments");
+ if(cf) {
+ _err_record_msg(cf->err, "_cf_complete_file: Invalid arguments",
+ END_ERR_MSG);
+ };
return 1;
};
/*
@@ -326,7 +334,8 @@ int _cf_complete_file(WordCompletion *cpl, CompleteFile *cf,
* backslash-escapes where needed.
*/
if(_pn_append_to_path(cf->path, lptr, seglen, escaped) == NULL) {
- strcpy(cf->errmsg, "Insufficient memory to complete filename");
+ _err_record_msg(cf->err, "Insufficient memory to complete filename",
+ END_ERR_MSG);
return 1;
};
lptr += seglen;
@@ -357,8 +366,8 @@ int _cf_complete_file(WordCompletion *cpl, CompleteFile *cf,
*/
value = getenv(cf->envnam);
if(!value) {
- const char *fmt = "Unknown environment variable: %.*s";
- sprintf(cf->errmsg, fmt, ERRLEN - strlen(fmt), cf->envnam);
+ _err_record_msg(cf->err, "Unknown environment variable: ", cf->envnam,
+ END_ERR_MSG);
return 1;
};
vlen = strlen(value);
@@ -387,7 +396,8 @@ int _cf_complete_file(WordCompletion *cpl, CompleteFile *cf,
* Append the value of the environment variable to the output path.
*/
if(_pn_append_to_path(cf->path, value, strlen(value), escaped)==NULL) {
- strcpy(cf->errmsg, "Insufficient memory to complete filename");
+ _err_record_msg(cf->err, "Insufficient memory to complete filename",
+ END_ERR_MSG);
return 1;
};
/*
@@ -422,8 +432,7 @@ int _cf_complete_file(WordCompletion *cpl, CompleteFile *cf,
if(nleft == 0) {
if(cpl_add_completion(cpl, line, lptr-line, word_end, FS_DIR_SEP,
"", "")) {
- strncpy(cf->errmsg, cpl_last_error(cpl), ERRLEN);
- cf->errmsg[ERRLEN] = '\0';
+ _err_record_msg(cf->err, cpl_last_error(cpl), END_ERR_MSG);
return 1;
};
return 0;
@@ -447,7 +456,7 @@ int _cf_complete_file(WordCompletion *cpl, CompleteFile *cf,
*/
const char *_cf_last_error(CompleteFile *cf)
{
- return cf ? cf->errmsg : "NULL CompleteFile argument";
+ return cf ? _err_get_msg(cf->err) : "NULL CompleteFile argument";
}
/*.......................................................................
@@ -472,15 +481,15 @@ static int cf_expand_home_dir(CompleteFile *cf, const char *user)
* Failed?
*/
if(!home_dir) {
- strncpy(cf->errmsg, _hd_last_home_dir_error(cf->home), ERRLEN);
- cf->errmsg[ERRLEN] = '\0';
+ _err_record_msg(cf->err, _hd_last_home_dir_error(cf->home), END_ERR_MSG);
return 1;
};
/*
* Append the home directory to the pathname string.
*/
if(_pn_append_to_path(cf->path, home_dir, -1, 0) == NULL) {
- strcpy(cf->errmsg, "Insufficient memory for home directory expansion");
+ _err_record_msg(cf->err, "Insufficient memory for home directory expansion",
+ END_ERR_MSG);
return 1;
};
return 0;
@@ -515,7 +524,7 @@ static int cf_complete_username(CompleteFile *cf, WordCompletion *cpl,
CfHomeArgs args;
args.cf = cf;
args.cpl = cpl;
- args.prefix = prefix;
+ args.prefix_len = strlen(prefix);
args.line = line;
args.word_start = word_start;
args.word_end = word_end;
@@ -524,9 +533,8 @@ static int cf_complete_username(CompleteFile *cf, WordCompletion *cpl,
* Iterate through the list of users, recording those which start
* with the specified prefix.
*/
- if(_hd_scan_user_home_dirs(cf->home, &args, cf_homedir_callback)) {
- strncpy(cf->errmsg, _hd_last_home_dir_error(cf->home), ERRLEN);
- cf->errmsg[ERRLEN] = '\0';
+ if(_hd_scan_user_home_dirs(cf->home, prefix, &args, cf_homedir_callback)) {
+ _err_record_msg(cf->err, _hd_last_home_dir_error(cf->home), END_ERR_MSG);
return 1;
};
return 0;
@@ -545,37 +553,22 @@ static HOME_DIR_FN(cf_homedir_callback)
WordCompletion *cpl = args->cpl;
CompleteFile *cf = args->cf;
/*
- * Get the length of the username prefix.
- */
- int prefix_len = strlen(args->prefix);
-/*
- * Get the length of the latest user name that is to be compared to
- * the prefix.
- */
- int name_len = strlen(usrnam);
-/*
- * See if the latest username starts with the prefix that we are
- * searching for, and record its suffix in the array of matches if so.
- */
- if(name_len >= prefix_len && strncmp(args->prefix, usrnam, prefix_len)==0) {
-/*
* Copy the username into the pathname work buffer, adding backslash
* escapes where needed.
*/
- if(cf_prepare_suffix(cf, usrnam+prefix_len, args->escaped)) {
- strncpy(errmsg, cf->errmsg, maxerr);
- errmsg[maxerr] = '\0';
- return 1;
- };
+ if(cf_prepare_suffix(cf, usrnam+args->prefix_len, args->escaped)) {
+ strncpy(errmsg, _err_get_msg(cf->err), maxerr);
+ errmsg[maxerr] = '\0';
+ return 1;
+ };
/*
* Report the completion suffix that was copied above.
*/
- if(cpl_add_completion(cpl, args->line, args->word_start, args->word_end,
- cf->buff->name, FS_DIR_SEP, FS_DIR_SEP)) {
- strncpy(errmsg, cpl_last_error(cpl), maxerr);
- errmsg[maxerr] = '\0';
- return 1;
- };
+ if(cpl_add_completion(cpl, args->line, args->word_start, args->word_end,
+ cf->buff->name, FS_DIR_SEP, FS_DIR_SEP)) {
+ strncpy(errmsg, cpl_last_error(cpl), maxerr);
+ errmsg[maxerr] = '\0';
+ return 1;
};
return 0;
}
@@ -660,8 +653,7 @@ static int cf_complete_entry(CompleteFile *cf, WordCompletion *cpl,
* Attempt to open the directory.
*/
if(_dr_open_dir(cf->dr, dirpath, NULL)) {
- const char *fmt = "Can't open directory: %.*s";
- sprintf(cf->errmsg, fmt, ERRLEN - strlen(fmt), dirpath);
+ _err_record_msg(cf->err, "Can't open directory: ", dirpath, END_ERR_MSG);
return 1;
};
/*
@@ -711,7 +703,9 @@ static int cf_complete_entry(CompleteFile *cf, WordCompletion *cpl,
const char *type_suffix = ""; /* The suffix to add when listing */
if(_pn_append_to_path(cf->path, file_name + prefix_len,
-1, escaped) == NULL) {
- strcpy(cf->errmsg, "Insufficient memory to complete filename.");
+ _err_record_msg(cf->err,
+ "Insufficient memory to complete filename.",
+ END_ERR_MSG);
return 1;
};
/*
@@ -763,7 +757,7 @@ static int cf_complete_entry(CompleteFile *cf, WordCompletion *cpl,
* Output:
* return char * A pointer to nambuf on success. On error NULL is
* returned and a description of the error is recorded
- * in cf->errmsg[].
+ * in cf->err.
*/
static char *cf_read_name(CompleteFile *cf, const char *type,
const char *string, int slen,
@@ -788,8 +782,7 @@ static char *cf_read_name(CompleteFile *cf, const char *type,
* Did the name overflow the buffer?
*/
if(namlen >= nammax) {
- const char *fmt = "%.*s name too long";
- sprintf(cf->errmsg, fmt, ERRLEN - strlen(fmt), type);
+ _err_record_msg(cf->err, type, " name too long", END_ERR_MSG);
return NULL;
};
/*
@@ -844,7 +837,8 @@ static int cf_prepare_suffix(CompleteFile *cf, const char *suffix,
* both the suffix and any backslashes that have to be inserted.
*/
if(_pn_resize_path(cf->buff, suffix_len + nbsl) == NULL) {
- strcpy(cf->errmsg, "Insufficient memory to complete filename");
+ _err_record_msg(cf->err, "Insufficient memory to complete filename",
+ END_ERR_MSG);
return 1;
};
/*
@@ -872,3 +866,5 @@ static int cf_prepare_suffix(CompleteFile *cf, const char *suffix,
};
return 0;
}
+
+#endif /* ifndef WITHOUT_FILE_SYSTEM */
diff --git a/libtecla-1.4.1/cplfile.h b/libtecla-1.6.1/cplfile.h
index 31683ba..a7ca9fb 100644
--- a/libtecla-1.4.1/cplfile.h
+++ b/libtecla-1.6.1/cplfile.h
@@ -2,7 +2,7 @@
#define cplfile_h
/*
- * Copyright (c) 2000, 2001 by Martin C. Shepherd.
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
*
* All rights reserved.
*
diff --git a/libtecla-1.4.1/cplmatch.c b/libtecla-1.6.1/cplmatch.c
index 111f5bd..ece93d3 100644
--- a/libtecla-1.4.1/cplmatch.c
+++ b/libtecla-1.6.1/cplmatch.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2001 by Martin C. Shepherd.
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
*
* All rights reserved.
*
@@ -35,14 +35,18 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#include <errno.h>
/*
* Local includes.
*/
#include "libtecla.h"
+#include "ioutil.h"
#include "stringrp.h"
#include "pathutil.h"
#include "cplfile.h"
+#include "cplmatch.h"
+#include "errmsg.h"
/*
* Specify the number of strings to allocate when the string free-list
@@ -52,23 +56,23 @@
#define STR_BLK_FACT 100
/*
- * Set the max length of the error-reporting string. There is no point
- * in this being longer than the width of a typical terminal window.
- * In composing error messages, I have assumed that this number is
- * at least 80, so don't decrease it below 80.
+ * Set the default number of spaces place between columns when listing
+ * a set of completions.
*/
-#define ERRLEN 200
+#define CPL_COL_SEP 2
/*
* Completion matches are recorded in containers of the following
* type.
*/
struct WordCompletion {
+ ErrMsg *err; /* The error reporting buffer */
StringGroup *sg; /* Memory for a group of strings */
int matches_dim; /* The allocated size of result.matches[] */
- char errmsg[ERRLEN+1]; /* The error-reporting buffer */
CplMatches result; /* Completions to be returned to the caller */
+#ifndef WITHOUT_FILE_SYSTEM
CompleteFile *cf; /* The resources used for filename completion */
+#endif
};
static void cpl_sort_matches(WordCompletion *cpl);
@@ -85,6 +89,7 @@ static int cpl_cmp_suffixes(const void *v1, const void *v2);
*/
#define CFC_ID_CODE 4568
+#ifndef WITHOUT_FILE_SYSTEM
/*
* A pointer to a structure of the following type can be passed to
* the builtin file-completion callback function to modify its behavior.
@@ -113,6 +118,39 @@ struct CplFileConf {
static void cpl_init_FileConf(CplFileConf *cfc);
+/*
+ * When file-system access is being excluded, define a dummy structure
+ * to satisfy the typedef in libtecla.h.
+ */
+#else
+struct CplFileConf {int dummy;};
+#endif
+
+/*
+ * Encapsulate the formatting information needed to layout a
+ * multi-column listing of completions.
+ */
+typedef struct {
+ int term_width; /* The width of the terminal (characters) */
+ int column_width; /* The number of characters within in each column. */
+ int ncol; /* The number of columns needed */
+ int nline; /* The number of lines needed */
+} CplListFormat;
+
+/*
+ * Given the current terminal width, and a list of completions, determine
+ * how to best use the terminal width to display a multi-column listing
+ * of completions.
+ */
+static void cpl_plan_listing(CplMatches *result, int term_width,
+ CplListFormat *fmt);
+
+/*
+ * Display a given line of a multi-column list of completions.
+ */
+static int cpl_format_line(CplMatches *result, CplListFormat *fmt, int lnum,
+ GlWriteFn *write_fn, void *data);
+
/*.......................................................................
* Create a new string-completion object.
*
@@ -127,7 +165,7 @@ WordCompletion *new_WordCompletion(void)
*/
cpl = (WordCompletion *) malloc(sizeof(WordCompletion));
if(!cpl) {
- fprintf(stderr, "new_WordCompletion: Insufficient memory.\n");
+ errno = ENOMEM;
return NULL;
};
/*
@@ -135,18 +173,31 @@ WordCompletion *new_WordCompletion(void)
* container at least up to the point at which it can safely be passed
* to del_WordCompletion().
*/
+ cpl->err = NULL;
cpl->sg = NULL;
cpl->matches_dim = 0;
cpl->result.suffix = NULL;
cpl->result.cont_suffix = NULL;
cpl->result.matches = NULL;
cpl->result.nmatch = 0;
+#ifndef WITHOUT_FILE_SYSTEM
cpl->cf = NULL;
+#endif
+/*
+ * Allocate a place to record error messages.
+ */
+ cpl->err = _new_ErrMsg();
+ if(!cpl->err)
+ return del_WordCompletion(cpl);
/*
* Allocate an object that allows a group of strings to be allocated
* efficiently by placing many of them in contiguous string segments.
*/
+#ifdef WITHOUT_FILE_SYSTEM
+ cpl->sg = _new_StringGroup(MAX_PATHLEN_FALLBACK);
+#else
cpl->sg = _new_StringGroup(_pu_pathname_dim());
+#endif
if(!cpl->sg)
return del_WordCompletion(cpl);
/*
@@ -157,16 +208,17 @@ WordCompletion *new_WordCompletion(void)
cpl->result.matches = (CplMatch *) malloc(sizeof(cpl->result.matches[0]) *
cpl->matches_dim);
if(!cpl->result.matches) {
- fprintf(stderr,
- "new_WordCompletion: Insufficient memory to allocate array of matches.\n");
+ errno = ENOMEM;
return del_WordCompletion(cpl);
};
/*
* Allocate a filename-completion resource object.
*/
+#ifndef WITHOUT_FILE_SYSTEM
cpl->cf = _new_CompleteFile();
if(!cpl->cf)
return del_WordCompletion(cpl);
+#endif
return cpl;
}
@@ -181,11 +233,14 @@ WordCompletion *new_WordCompletion(void)
WordCompletion *del_WordCompletion(WordCompletion *cpl)
{
if(cpl) {
+ cpl->err = _del_ErrMsg(cpl->err);
cpl->sg = _del_StringGroup(cpl->sg);
if(cpl->result.matches) {
free(cpl->result.matches);
cpl->result.matches = NULL;
+#ifndef WITHOUT_FILE_SYSTEM
cpl->cf = _del_CompleteFile(cpl->cf);
+#endif
};
free(cpl);
};
@@ -255,7 +310,9 @@ int cpl_add_completion(WordCompletion *cpl, const char *line,
CplMatch *matches = (CplMatch *) realloc(cpl->result.matches,
sizeof(cpl->result.matches[0]) * needed);
if(!matches) {
- strcpy(cpl->errmsg, "Insufficient memory to extend array of matches.");
+ _err_record_msg(cpl->err,
+ "Insufficient memory to extend array of matches.",
+ END_ERR_MSG);
return 1;
};
cpl->result.matches = matches;
@@ -267,7 +324,8 @@ int cpl_add_completion(WordCompletion *cpl, const char *line,
*/
string = _sg_alloc_string(cpl->sg, word_end-word_start + strlen(suffix));
if(!string) {
- strcpy(cpl->errmsg, "Insufficient memory to extend array of matches.");
+ _err_record_msg(cpl->err, "Insufficient memory to extend array of matches.",
+ END_ERR_MSG);
return 1;
};
/*
@@ -402,8 +460,9 @@ static int cpl_common_suffix(WordCompletion *cpl)
*/
result->suffix = _sg_alloc_string(cpl->sg, length);
if(!result->suffix) {
- strcpy(cpl->errmsg,
- "Insufficient memory to record common completion suffix.");
+ _err_record_msg(cpl->err,
+ "Insufficient memory to record common completion suffix.",
+ END_ERR_MSG);
return 1;
};
/*
@@ -435,7 +494,7 @@ static void cpl_clear_completions(WordCompletion *cpl)
/*
* Also clear the error message.
*/
- cpl->errmsg[0] = '\0';
+ _err_clear_msg(cpl->err);
return;
}
@@ -464,8 +523,8 @@ static void cpl_clear_completions(WordCompletion *cpl)
* cpl_last_error(cpl).
*/
CplMatches *cpl_complete_word(WordCompletion *cpl, const char *line,
- int word_end, void *data,
- CplMatchFn *match_fn)
+ int word_end, void *data,
+ CplMatchFn *match_fn)
{
int line_len; /* The total length of the input line */
/*
@@ -476,8 +535,10 @@ CplMatches *cpl_complete_word(WordCompletion *cpl, const char *line,
* Check the arguments.
*/
if(!cpl || !line || !match_fn || word_end < 0 || word_end > line_len) {
- if(cpl)
- strcpy(cpl->errmsg, "cpl_complete_word: Invalid arguments.");
+ if(cpl) {
+ _err_record_msg(cpl->err, "cpl_complete_word: Invalid arguments.",
+ END_ERR_MSG);
+ };
return NULL;
};
/*
@@ -489,8 +550,8 @@ CplMatches *cpl_complete_word(WordCompletion *cpl, const char *line,
* cpl->result.matches.
*/
if(match_fn(cpl, data, line, word_end)) {
- if(cpl->errmsg[0] == '\0')
- strcpy(cpl->errmsg, "Error completing word.");
+ if(_err_get_msg(cpl->err)[0] == '\0')
+ _err_record_msg(cpl->err, "Error completing word.", END_ERR_MSG);
return NULL;
};
/*
@@ -519,6 +580,29 @@ CplMatches *cpl_complete_word(WordCompletion *cpl, const char *line,
}
/*.......................................................................
+ * Recall the return value of the last call to cpl_complete_word().
+ *
+ * Input:
+ * cpl WordCompletion * The completion resource object.
+ * Output:
+ * return CplMatches * The container of the array of possible
+ * completions, as returned by the last call to
+ * cpl_complete_word(). The returned pointer refers
+ * to a container owned by the parent WordCompletion
+ * object, and its contents thus potentially
+ * change on every call to cpl_complete_word().
+ * On error, either in the execution of this
+ * function, or in the last call to
+ * cpl_complete_word(), NULL is returned, and a
+ * description of the error can be acquired by
+ * calling cpl_last_error(cpl).
+ */
+CplMatches *cpl_recall_matches(WordCompletion *cpl)
+{
+ return (!cpl || *_err_get_msg(cpl->err)!='\0') ? NULL : &cpl->result;
+}
+
+/*.......................................................................
* Print out an array of matching completions.
*
* Input:
@@ -532,73 +616,47 @@ CplMatches *cpl_complete_word(WordCompletion *cpl, const char *line,
*/
int cpl_list_completions(CplMatches *result, FILE *fp, int term_width)
{
- int maxlen; /* The length of the longest matching string */
- int width; /* The width of a column */
- int ncol; /* The number of columns to list */
- int nrow; /* The number of rows needed to list all of the matches */
- int row,col; /* The row and column being written to */
- int i;
-/*
- * Check the arguments.
+ return _cpl_output_completions(result, _io_write_stdio, fp, term_width);
+}
+
+/*.......................................................................
+ * Print an array of matching completions via a callback function.
+ *
+ * Input:
+ * result CplMatches * The container of the sorted array of
+ * completions.
+ * write_fn GlWriteFn * The function to call to write the completions,
+ * or 0 to discard the output.
+ * data void * Anonymous data to pass to write_fn().
+ * term_width int The width of the terminal.
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
*/
- if(!result || !fp) {
- fprintf(stderr, "cpl_list_completions: NULL argument(s).\n");
- return 1;
- };
+int _cpl_output_completions(CplMatches *result, GlWriteFn *write_fn, void *data,
+ int term_width)
+{
+ CplListFormat fmt; /* List formatting information */
+ int lnum; /* The sequential number of the line to print next */
/*
* Not enough space to list anything?
*/
if(term_width < 1)
return 0;
/*
- * Work out the maximum length of the matching strings.
+ * Do we have a callback to write via, and any completions to be listed?
*/
- maxlen = 0;
- for(i=0; i<result->nmatch; i++) {
- CplMatch *match = result->matches + i;
- int len = strlen(match->completion) +
- strlen(match->type_suffix);
- if(len > maxlen)
- maxlen = len;
- };
+ if(write_fn && result && result->nmatch>0) {
/*
- * Nothing to list?
+ * Work out how to arrange the listing into fixed sized columns.
*/
- if(maxlen == 0)
- return 0;
+ cpl_plan_listing(result, term_width, &fmt);
/*
- * Split the available terminal width into columns of maxlen + 2 characters.
+ * Print the listing via the specified callback.
*/
- width = maxlen + 2;
- ncol = term_width / width;
-/*
- * If the column width is greater than the terminal width, the matches will
- * just have to overlap onto the next line.
- */
- if(ncol < 1)
- ncol = 1;
-/*
- * How many rows will be needed?
- */
- nrow = (result->nmatch + ncol - 1) / ncol;
-/*
- * Print the matches out in ncol columns, sorted in row order within each
- * column.
- */
- for(row=0; row < nrow; row++) {
- for(col=0; col < ncol; col++) {
- int m = col*nrow + row;
- if(m < result->nmatch) {
- CplMatch *match = result->matches + m;
- if(fprintf(fp, "%s%-*s%s", match->completion,
- (int) (ncol > 1 ? maxlen - strlen(match->completion):0),
- match->type_suffix, col<ncol-1 ? " " : "\r\n") < 0)
- return 1;
- } else {
- if(fprintf(fp, "\r\n") < 0)
- return 1;
- break;
- };
+ for(lnum=0; lnum < fmt.nline; lnum++) {
+ if(cpl_format_line(result, &fmt, lnum, write_fn, data))
+ return 1;
};
};
return 0;
@@ -614,7 +672,7 @@ int cpl_list_completions(CplMatches *result, FILE *fp, int term_width)
*/
const char *cpl_last_error(WordCompletion *cpl)
{
- return cpl ? cpl->errmsg : "NULL WordCompletion argument";
+ return cpl ? _err_get_msg(cpl->err) : "NULL WordCompletion argument";
}
/*.......................................................................
@@ -629,10 +687,8 @@ const char *cpl_last_error(WordCompletion *cpl)
*/
void cpl_record_error(WordCompletion *cpl, const char *errmsg)
{
- if(cpl && errmsg) {
- strncpy(cpl->errmsg, errmsg, ERRLEN);
- cpl->errmsg[ERRLEN] = '\0';
- };
+ if(cpl && errmsg)
+ _err_record_msg(cpl->err, errmsg, END_ERR_MSG);
}
/*.......................................................................
@@ -657,6 +713,9 @@ void cpl_record_error(WordCompletion *cpl, const char *errmsg)
*/
CPL_MATCH_FN(cpl_file_completions)
{
+#ifdef WITHOUT_FILE_SYSTEM
+ return 0;
+#else
const char *start_path; /* The pointer to the start of the pathname */
/* in line[]. */
CplFileConf *conf; /* The new-style configuration object. */
@@ -671,7 +730,8 @@ CPL_MATCH_FN(cpl_file_completions)
if(!cpl)
return 1;
if(!line || word_end < 0) {
- strcpy(cpl->errmsg, "cpl_file_completions: Invalid arguments.");
+ _err_record_msg(cpl->err, "cpl_file_completions: Invalid arguments.",
+ END_ERR_MSG);
return 1;
};
/*
@@ -706,7 +766,8 @@ CPL_MATCH_FN(cpl_file_completions)
if(conf->file_start < 0) {
start_path = _pu_start_of_path(line, word_end);
if(!start_path) {
- strcpy(cpl->errmsg, "Unable to find the start of the filename.");
+ _err_record_msg(cpl->err, "Unable to find the start of the filename.",
+ END_ERR_MSG);
return 1;
};
} else {
@@ -721,6 +782,7 @@ CPL_MATCH_FN(cpl_file_completions)
return 1;
};
return 0;
+#endif
}
/*.......................................................................
@@ -741,6 +803,7 @@ void cpl_init_FileArgs(CplFileArgs *cfa)
};
}
+#ifndef WITHOUT_FILE_SYSTEM
/*.......................................................................
* Initialize a CplFileConf structure with default configuration
* parameters.
@@ -759,6 +822,7 @@ static void cpl_init_FileConf(CplFileConf *cfc)
cfc->chk_data = NULL;
};
}
+#endif
/*.......................................................................
* Create a new CplFileConf object and initialize it with defaults.
@@ -768,6 +832,10 @@ static void cpl_init_FileConf(CplFileConf *cfc)
*/
CplFileConf *new_CplFileConf(void)
{
+#ifdef WITHOUT_FILE_SYSTEM
+ errno = EINVAL;
+ return NULL;
+#else
CplFileConf *cfc; /* The object to be returned */
/*
* Allocate the container.
@@ -782,6 +850,7 @@ CplFileConf *new_CplFileConf(void)
*/
cpl_init_FileConf(cfc);
return cfc;
+#endif
}
/*.......................................................................
@@ -794,12 +863,14 @@ CplFileConf *new_CplFileConf(void)
*/
CplFileConf *del_CplFileConf(CplFileConf *cfc)
{
+#ifndef WITHOUT_FILE_SYSTEM
if(cfc) {
/*
* Delete the container.
*/
free(cfc);
};
+#endif
return NULL;
}
@@ -818,8 +889,10 @@ CplFileConf *del_CplFileConf(CplFileConf *cfc)
*/
void cfc_literal_escapes(CplFileConf *cfc, int literal)
{
+#ifndef WITHOUT_FILE_SYSTEM
if(cfc)
cfc->escaped = !literal;
+#endif
}
/*.......................................................................
@@ -837,8 +910,10 @@ void cfc_literal_escapes(CplFileConf *cfc, int literal)
*/
void cfc_file_start(CplFileConf *cfc, int start_index)
{
+#ifndef WITHOUT_FILE_SYSTEM
if(cfc)
cfc->file_start = start_index;
+#endif
}
/*.......................................................................
@@ -858,10 +933,12 @@ void cfc_file_start(CplFileConf *cfc, int start_index)
*/
void cfc_set_check_fn(CplFileConf *cfc, CplCheckFn *chk_fn, void *chk_data)
{
+#ifndef WITHOUT_FILE_SYSTEM
if(cfc) {
cfc->chk_fn = chk_fn;
cfc->chk_data = chk_data;
};
+#endif
}
/*.......................................................................
@@ -870,7 +947,11 @@ void cfc_set_check_fn(CplFileConf *cfc, CplCheckFn *chk_fn, void *chk_data)
*/
CPL_CHECK_FN(cpl_check_exe)
{
+#ifdef WITHOUT_FILE_SYSTEM
+ return 0;
+#else
return _pu_path_is_exe(pathname);
+#endif
}
/*.......................................................................
@@ -925,3 +1006,165 @@ static void cpl_zap_duplicates(WordCompletion *cpl)
cpl->result.nmatch = dst;
return;
}
+
+/*.......................................................................
+ * Work out how to arrange a given array of completions into a listing
+ * of one or more fixed size columns.
+ *
+ * Input:
+ * result CplMatches * The set of completions to be listed.
+ * term_width int The width of the terminal. A lower limit of
+ * zero is quietly enforced.
+ * Input/Output:
+ * fmt CplListFormat * The formatting information will be assigned
+ * to the members of *fmt.
+ */
+static void cpl_plan_listing(CplMatches *result, int term_width,
+ CplListFormat *fmt)
+{
+ int maxlen; /* The length of the longest matching string */
+ int i;
+/*
+ * Ensure that term_width >= 0.
+ */
+ if(term_width < 0)
+ term_width = 0;
+/*
+ * Start by assuming the worst case, that either nothing will fit
+ * on the screen, or that there are no matches to be listed.
+ */
+ fmt->term_width = term_width;
+ fmt->column_width = 0;
+ fmt->nline = fmt->ncol = 0;
+/*
+ * Work out the maximum length of the matching strings.
+ */
+ maxlen = 0;
+ for(i=0; i<result->nmatch; i++) {
+ CplMatch *match = result->matches + i;
+ int len = strlen(match->completion) + strlen(match->type_suffix);
+ if(len > maxlen)
+ maxlen = len;
+ };
+/*
+ * Nothing to list?
+ */
+ if(maxlen == 0)
+ return;
+/*
+ * Split the available terminal width into columns of
+ * maxlen + CPL_COL_SEP characters.
+ */
+ fmt->column_width = maxlen;
+ fmt->ncol = fmt->term_width / (fmt->column_width + CPL_COL_SEP);
+/*
+ * If the column width is greater than the terminal width, zero columns
+ * will have been selected. Set a lower limit of one column. Leave it
+ * up to the caller how to deal with completions who's widths exceed
+ * the available terminal width.
+ */
+ if(fmt->ncol < 1)
+ fmt->ncol = 1;
+/*
+ * How many lines of output will be needed?
+ */
+ fmt->nline = (result->nmatch + fmt->ncol - 1) / fmt->ncol;
+ return;
+}
+
+/*.......................................................................
+ * Render one line of a multi-column listing of completions, using a
+ * callback function to pass the output to an arbitrary destination.
+ *
+ * Input:
+ * result CplMatches * The container of the sorted array of
+ * completions.
+ * fmt CplListFormat * Formatting information.
+ * lnum int The index of the line to print, starting
+ * from 0, and incrementing until the return
+ * value indicates that there is nothing more
+ * to be printed.
+ * write_fn GlWriteFn * The function to call to write the line, or
+ * 0 to discard the output.
+ * data void * Anonymous data to pass to write_fn().
+ * Output:
+ * return int 0 - Line printed ok.
+ * 1 - Nothing to print.
+ */
+static int cpl_format_line(CplMatches *result, CplListFormat *fmt, int lnum,
+ GlWriteFn *write_fn, void *data)
+{
+ int col; /* The index of the list column being output */
+/*
+ * If the line index is out of bounds, there is nothing to be written.
+ */
+ if(lnum < 0 || lnum >= fmt->nline)
+ return 1;
+/*
+ * If no output function has been provided, return as though the
+ * line had been printed.
+ */
+ if(!write_fn)
+ return 0;
+/*
+ * Print the matches in 'ncol' columns, sorted in line order within each
+ * column.
+ */
+ for(col=0; col < fmt->ncol; col++) {
+ int m = col*fmt->nline + lnum;
+/*
+ * Is there another match to be written? Note that in general
+ * the last line of a listing will have fewer filled columns
+ * than the initial lines.
+ */
+ if(m < result->nmatch) {
+ CplMatch *match = result->matches + m;
+/*
+ * How long are the completion and type-suffix strings?
+ */
+ int clen = strlen(match->completion);
+ int tlen = strlen(match->type_suffix);
+/*
+ * Write the completion string.
+ */
+ if(write_fn(data, match->completion, clen) != clen)
+ return 1;
+/*
+ * Write the type suffix, if any.
+ */
+ if(tlen > 0 && write_fn(data, match->type_suffix, tlen) != tlen)
+ return 1;
+/*
+ * If another column follows the current one, pad to its start with spaces.
+ */
+ if(col+1 < fmt->ncol) {
+/*
+ * The following constant string of spaces is used to pad the output.
+ */
+ static const char spaces[] = " ";
+ static const int nspace = sizeof(spaces) - 1;
+/*
+ * Pad to the next column, using as few sub-strings of the spaces[]
+ * array as possible.
+ */
+ int npad = fmt->column_width + CPL_COL_SEP - clen - tlen;
+ while(npad>0) {
+ int n = npad > nspace ? nspace : npad;
+ if(write_fn(data, spaces + nspace - n, n) != n)
+ return 1;
+ npad -= n;
+ };
+ };
+ };
+ };
+/*
+ * Start a new line.
+ */
+ {
+ char s[] = "\r\n";
+ int n = strlen(s);
+ if(write_fn(data, s, n) != n)
+ return 1;
+ };
+ return 0;
+}
diff --git a/libtecla-1.6.1/cplmatch.h b/libtecla-1.6.1/cplmatch.h
new file mode 100644
index 0000000..cb50006
--- /dev/null
+++ b/libtecla-1.6.1/cplmatch.h
@@ -0,0 +1,47 @@
+#ifndef cplmatch_h
+#define cplmatch_h
+
+/*
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
+ *
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, and/or sell copies of the Software, and to permit persons
+ * to whom the Software is furnished to do so, provided that the above
+ * copyright notice(s) and this permission notice appear in all copies of
+ * the Software and that both the above copyright notice(s) and this
+ * permission notice appear in supporting documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+ * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
+ * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder
+ * shall not be used in advertising or otherwise to promote the sale, use
+ * or other dealings in this Software without prior written authorization
+ * of the copyright holder.
+ */
+
+/*
+ * This header is not for use by external applicatons. It contains
+ * internal immplementation features of the libtecla library, which
+ * may change incompatibly between releases.
+ */
+
+/*
+ * Display a list of completions via a callback function.
+ */
+int _cpl_output_completions(CplMatches *result, GlWriteFn *write_fn, void *data,
+ int term_width);
+
+#endif
diff --git a/libtecla-1.4.1/demo.c b/libtecla-1.6.1/demo.c
index 8bee92d..d29b11a 100644
--- a/libtecla-1.4.1/demo.c
+++ b/libtecla-1.6.1/demo.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2001 by the California Institute of Technology.
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd
*
* All rights reserved.
*
@@ -41,6 +41,14 @@
#include "libtecla.h"
+/* The function which displays the introductory text of the demo */
+
+static void show_demo_introduction(GetLine *gl);
+
+/*.......................................................................
+ * This program demonstrates how to use gl_get_line() as a line editor to
+ * to enable users to enter input. It takes no arguments.
+ */
int main(int argc, char *argv[])
{
char *line; /* A line of input */
@@ -62,12 +70,18 @@ int main(int argc, char *argv[])
* Lookup and display the version number of the library.
*/
libtecla_version(&major, &minor, &micro);
- printf("Welcome to the demo program of libtecla version %d.%d.%d\n",
+ printf("\n Welcome to the main demo program of libtecla version %d.%d.%d\n",
major, minor, micro);
/*
+ * Display an introductory banner.
+ */
+ show_demo_introduction(gl);
+/*
* Load history.
*/
+#ifndef WITHOUT_FILE_SYSTEM
(void) gl_load_history(gl, "~/.demo_history", "#");
+#endif
/*
* Read lines of input from the user and print them to stdout.
*/
@@ -94,12 +108,17 @@ int main(int argc, char *argv[])
GlTerminalSize size = gl_terminal_size(gl, 80, 24);
printf("Terminal size = %d columns x %d lines.\n", size.ncolumn,
size.nline);
+ } else if(strcmp(line, "clear\n")==0) {
+ if(gl_erase_terminal(gl))
+ return 1;
};
} while(1);
/*
* Save historical command lines.
*/
+#ifndef WITHOUT_FILE_SYSTEM
(void) gl_save_history(gl, "~/.demo_history", "#", -1);
+#endif
/*
* Clean up.
*/
@@ -107,3 +126,41 @@ int main(int argc, char *argv[])
return 0;
}
+/*.......................................................................
+ * Display introductory text to the user, formatted according to the
+ * current terminal width and enclosed in a box of asterixes.
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ */
+static void show_demo_introduction(GetLine *gl)
+{
+ int start; /* The column in which gl_display_text() left the cursor */
+ int i;
+/*
+ * Break the indtroductory text into an array of strings, so as to
+ * avoid overflowing any compiler string limits.
+ */
+ const char *doc[] = {
+ "This program is a simple shell with which you can experiment with the ",
+ "line editing and tab completion facilities provided by the gl_get_line() ",
+ "function. The file demo.c also serves as a fully commented example ",
+ "of how to use gl_get_line().\n"
+ };
+/*
+ * Form the top line of the documentation box by filling the area of
+ * the line between a " *" prefix and a "* " suffix with asterixes.
+ */
+ printf("\n");
+ gl_display_text(gl, 0, " *", "* ", '*', 80, 0, "\n");
+/*
+ * Justify the documentation text within margins of asterixes.
+ */
+ for(start=0,i=0; i<sizeof(doc)/sizeof(doc[0]) && start >= 0; i++)
+ start = gl_display_text(gl, 0, " * ", " * ", ' ', 80, start,doc[i]);
+/*
+ * Draw the bottom line of the documentation box.
+ */
+ gl_display_text(gl, 0, " *", "* ", '*', 80, 0, "\n");
+ printf("\n");
+}
diff --git a/libtecla-1.4.1/demo2.c b/libtecla-1.6.1/demo2.c
index e1e80c6..63a9a0c 100644
--- a/libtecla-1.4.1/demo2.c
+++ b/libtecla-1.6.1/demo2.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2001 by Martin C. Shepherd.
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
*
* All rights reserved.
*
@@ -42,6 +42,21 @@
#include "libtecla.h"
/*
+ * If the library is being built with file-system access excluded, this
+ * demo program won't have anything to demonstrate.
+ */
+#ifdef WITHOUT_FILE_SYSTEM
+int main(int argc, char *argv[])
+{
+ fprintf(stderr, "\n"
+ " This program normally demonstrates tecla's path-lookup\n"
+ " facility. However libtecla has been installed with\n"
+ " file-system facilities explicitly excluded, so there is\n"
+ " nothing to demonstrate.\n\n");
+ return 1;
+}
+#else
+/*
* Encapsulate the resources needed by this demo.
*/
typedef struct {
@@ -74,6 +89,10 @@ static int get_word_limits(const char *string, int *wa, int *wb);
*/
static CPL_MATCH_FN(demo_cpl_fn);
+/* The function which displays the introductory text of the demo */
+
+static void show_demo_introduction(GetLine *gl);
+
/*.......................................................................
* This demo takes no arguments. It reads lines of input until the
* word 'exit' is entered, or C-d is pressed. It replaces the default
@@ -107,9 +126,14 @@ int main(int argc, char *argv[])
* Lookup and display the version number of the library.
*/
libtecla_version(&major, &minor, &micro);
- printf("Welcome to the demo2 program of libtecla version %d.%d.%d\n",
+ printf("\n Welcome to the path-search demo of libtecla version %d.%d.%d\n",
major, minor, micro);
/*
+ * Display some introductory text, left-justifying it within the current
+ * width of the terminal and enclosing it in a box of asterixes.
+ */
+ show_demo_introduction(res->gl);
+/*
* Read lines of input from the user and print them to stdout.
*/
do {
@@ -350,3 +374,50 @@ static int get_word_limits(const char *string, int *wa, int *wb)
};
return *wa == *wb;
}
+
+/*.......................................................................
+ * Display introductory text to the user, formatted according to the
+ * current terminal width and enclosed in a box of asterixes.
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ */
+static void show_demo_introduction(GetLine *gl)
+{
+ int start; /* The column in which gl_display_text() left the cursor */
+ int i;
+/*
+ * Break the indtroductory text into an array of strings, so as to
+ * avoid overflowing any compiler string limits.
+ */
+ const char *doc[] = {
+ "This program demonstrates the use of the pca_lookup_file() function ",
+ "for finding executables in the UNIX PATH. It also demonstrates ",
+ "tab completion of the names of executables found in the path. For ",
+ "example, if you type:\n\n ta\n\nthen hit the tab key, you will be ",
+ "presented with a list of executables such as tar and tail whose names ",
+ "start with the string \"ta\". If you decide to add an \"r\" to select ",
+ "the tar command, then you type return, the full pathname of the tar ",
+ "program will be printed.\n\nThe file demo2.c contains the code ",
+ "of this program, and is fully commented to enable its use as ",
+ "a working example of how to use the facilities documented in the ",
+ "pca_lookup_file man page.\n"};
+/*
+ * Form the top line of the documentation box by filling the area of
+ * the line between a " *" prefix and a "* " suffix with asterixes.
+ */
+ printf("\n");
+ gl_display_text(gl, 0, " *", "* ", '*', 80, 0, "\n");
+/*
+ * Justify the documentation text within margins of asterixes.
+ */
+ for(start=0,i=0; i<sizeof(doc)/sizeof(doc[0]) && start >= 0; i++)
+ start = gl_display_text(gl, 0, " * ", " * ", ' ', 80, start,doc[i]);
+/*
+ * Draw the bottom line of the documentation box.
+ */
+ gl_display_text(gl, 0, " *", "* ", '*', 80, 0, "\n");
+ printf("\n");
+}
+
+#endif /* ifndef WITHOUT_FILE_SYSTEM */
diff --git a/libtecla-1.6.1/demo3.c b/libtecla-1.6.1/demo3.c
new file mode 100644
index 0000000..aa204d0
--- /dev/null
+++ b/libtecla-1.6.1/demo3.c
@@ -0,0 +1,738 @@
+/*
+ * Copyright (c) 2002, 2003, 2004 by Martin C. Shepherd
+ *
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, and/or sell copies of the Software, and to permit persons
+ * to whom the Software is furnished to do so, provided that the above
+ * copyright notice(s) and this permission notice appear in all copies of
+ * the Software and that both the above copyright notice(s) and this
+ * permission notice appear in supporting documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+ * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
+ * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder
+ * shall not be used in advertising or otherwise to promote the sale, use
+ * or other dealings in this Software without prior written authorization
+ * of the copyright holder.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+#include <locale.h>
+#include <setjmp.h>
+
+#ifdef HAVE_SELECT
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#endif
+
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <signal.h>
+
+#include "libtecla.h"
+
+/*
+ * The SignalActions object provides a way to temporarily install
+ * a signal handler to a given set of signals, and later restore all
+ * of the signal handlers that this displaced.
+ */
+typedef struct {
+ int nsignal; /* The number of signals on the host OS */
+ sigset_t mask; /* The set of signals who's signal handlers */
+ /* are stored in the following actions[] */
+ /* array. */
+ struct sigaction *actions; /* An array of nsignal actions */
+} SignalActions;
+
+static SignalActions *new_SignalActions(void);
+static SignalActions *del_SignalActions(SignalActions *si);
+static int displace_signal_handlers(SignalActions *si, sigset_t *mask,
+ void (*handler)(int));
+static int reinstate_signal_handlers(SignalActions *si);
+
+/* Return resources, restore the terminal to a usable state and exit */
+
+static void cleanup_and_exit(GetLine *gl, SignalActions *si, int status);
+
+/* The function which displays the introductory text of the demo */
+
+static void show_demo_introduction(GetLine *gl);
+
+/* A signal-aware version of select() */
+
+static int demo_sigselect(int n, fd_set *readfds, fd_set *writefds,
+ fd_set *exceptfds, struct timeval *timeout,
+ sigset_t *mask, SignalActions *si);
+
+/*
+ * The following variables are accessed from signal handlers. Note
+ * that these variables don't need to be either volatile or
+ * sig_atomic_t because:
+ *
+ * 1. Outside of signal handlers we only access them when signal
+ * delivery is blocked, so we know that no signal handlers can
+ * be accessing them at that time.
+ *
+ * 2. When the signal handlers that set these variables are installed,
+ * the sa_mask member of the sigaction structure is used to ensure
+ * that only one instance of these signal handlers can be running
+ * at a time, so we also know that there can't be simultaneous
+ * accesses to them by multiple signal handlers.
+ */
+static GetLine *demo_gl; /* The line editor object */
+static sigjmp_buf demo_setjmp_buffer; /* The sigsetjmp() buffer */
+static int demo_setjmp_signo = -1; /* The signal that was caught */
+
+/* Signal handlers */
+
+static void demo_signal_handler(int signo);
+static void demo_setjmp_handler(int signo);
+
+/*
+ * Set the amount of time that gl_get_line() should wait for I/O before
+ * returning to let the external event loop continue.
+ */
+#define DEMO_IO_TIMEOUT 100000000 /* ns => 100ms */
+
+/* The timeout handler */
+
+static GL_TIMEOUT_FN(demo_timeout_fn);
+
+/*.......................................................................
+ * This program demonstrates the use of gl_get_line() from an external
+ * event loop. It takes no arguments.
+ */
+int main(int argc, char *argv[])
+{
+ int major,minor,micro; /* The version number of the library */
+ GetLine *gl=NULL; /* The resource object of gl_get_line() */
+ SignalActions *si=NULL; /* Temporary storage of displaced signal */
+ /* handlers. */
+ sigset_t all_signal_mask; /* The set of signals known by gl_get_line() */
+/*
+ * This program requires select().
+ */
+#if !defined(HAVE_SELECT)
+ fprintf(stderr, "The select() system call isn't available - aborting.\n");
+ exit(1);
+#else
+/*
+ * Create the line editor, specifying a maximum line length of 500 bytes,
+ * and 10000 bytes to allocate to storage of historical input lines.
+ */
+ gl = demo_gl = new_GetLine(500, 5000);
+ if(!gl)
+ cleanup_and_exit(gl, si, 1);
+
+/*
+ * Allocate an object in which to temporarily record displaced
+ * signal handlers.
+ */
+ si = new_SignalActions();
+ if(!si)
+ cleanup_and_exit(gl, si, 1);
+/*
+ * If the user has the LC_CTYPE or LC_ALL environment variables set,
+ * enable display of characters corresponding to the specified locale.
+ */
+ (void) setlocale(LC_CTYPE, "");
+/*
+ * Lookup and display the version number of the library.
+ */
+ libtecla_version(&major, &minor, &micro);
+ printf(
+ "\n Welcome to the server-mode demo program of libtecla version %d.%d.%d\n",
+ major, minor, micro);
+/*
+ * Display some introductory text, left-justifying it within the current
+ * width of the terminal and enclosing it in a box of asterixes.
+ */
+ show_demo_introduction(gl);
+/*
+ * Load history.
+ */
+#ifndef WITHOUT_FILE_SYSTEM
+ (void) gl_load_history(gl, "~/.demo_history", "#");
+#endif
+/*
+ * In this demo, rather than having gl_get_line() return immediately
+ * when it would otherwise have to wait for I/O, we register a timeout
+ * callback which causes gl_get_line() to give up waiting after a short
+ * interval.
+ */
+ gl_inactivity_timeout(gl, demo_timeout_fn, NULL, 0, DEMO_IO_TIMEOUT);
+/*
+ * Install our signal handlers for process termination, suspension and
+ * terminal resize signals. Ignore process continuation signals.
+ */
+ gl_tty_signals(demo_signal_handler, demo_signal_handler, SIG_DFL,
+ demo_signal_handler);
+/*
+ * Get a list of all of the signals that gl_get_line() currently catches.
+ */
+ gl_list_signals(gl, &all_signal_mask);
+/*
+ * Switch gl_get_line() to non-blocking server mode.
+ */
+ if(gl_io_mode(gl, GL_SERVER_MODE))
+ cleanup_and_exit(gl, si, 1);
+/*
+ * Instruct gl_get_line() to unblock any signals that it catches
+ * while waiting for input. Note that in non-blocking server mode,
+ * this is only necessary when using gl_inactivity_timeout() to make
+ * gl_get_line() block for a non-zero amount of time.
+ */
+ gl_catch_blocked(gl);
+/*
+ * Enter the event loop.
+ */
+ while(1) {
+ int nready; /* The number of file-descriptors that are */
+ /* ready for I/O */
+ fd_set rfds; /* The set of file descriptors to watch for */
+ /* readability */
+ fd_set wfds; /* The set of file descriptors to watch for */
+ /* writability */
+/*
+ * Construct the sets of file descriptors to be watched by select(),
+ * starting from empty sets.
+ */
+ FD_ZERO(&rfds);
+ FD_ZERO(&wfds);
+/*
+ * To ensure that no signals are received whos handlers might change
+ * the requirements for the contents of the above signal sets, block
+ * all of the signals that we are handling.
+ */
+ sigprocmask(SIG_BLOCK, &all_signal_mask, NULL);
+/*
+ * Depending on which direction of I/O gl_get_line()s is currently
+ * waiting for, add the terminal file descriptor to either the set
+ * of file descriptors to watch for readability, or those to watch
+ * for writability. Note that at the start of a new line, such as
+ * after an error, or the return of a completed line, we need to
+ * wait for writability, so that a prompt can be written.
+ */
+ switch(gl_pending_io(gl)) {
+ case GLP_READ:
+ FD_SET(STDIN_FILENO, &rfds);
+ break;
+ default:
+ FD_SET(STDIN_FILENO, &wfds);
+ break;
+ };
+/*
+ * Wait for I/O to become possible on the selected file descriptors.
+ * The following is a signal-aware wrapper around the select() system
+ * call. This wrapper guarantees that if any of the signals marked in
+ * all_signal_mask arrive after the statement above where we blocked
+ * these signals, it will detect this and abort with nready=-1 and
+ * errno=EINTR. If instead, we just unblocked the above signals just
+ * before calling a normal call to select(), there would be a small
+ * window of time between those two statements in which a signal could
+ * arrive without aborting select(). This would be a problem, since
+ * the functions called by our signal handler may change the type
+ * of I/O that gl_get_line() wants us to wait for in select().
+ */
+ nready = demo_sigselect(STDIN_FILENO + 1, &rfds, &wfds, NULL, NULL,
+ &all_signal_mask, si);
+/*
+ * We can now unblock our signals again.
+ */
+ sigprocmask(SIG_UNBLOCK, &all_signal_mask, NULL);
+/*
+ * Did an I/O error occur?
+ */
+ if(nready < 0 && errno != EINTR)
+ cleanup_and_exit(gl, si, 1);
+/*
+ * If the terminal file descriptor is now ready for I/O, call
+ * gl_get_line() to continue editing the current input line.
+ */
+ if(FD_ISSET(STDIN_FILENO, &rfds) || FD_ISSET(STDIN_FILENO, &wfds)) {
+/*
+ * Start or continue editing an input line.
+ */
+ char *line = gl_get_line(gl, "$ ", NULL, 0);
+/*
+ * Did the user finish entering a new line?
+ */
+ if(line) {
+/*
+ * Before writing messages to the terminal, start a new line and
+ * switch back to normal terminal I/O.
+ */
+ gl_normal_io(gl);
+/*
+ * Display what was entered.
+ */
+ if(printf("You entered: %s", line) < 0 || fflush(stdout))
+ break;
+/*
+ * Implement a few simple commands.
+ */
+ if(strcmp(line, "exit\n")==0)
+ cleanup_and_exit(gl, si, 0);
+ else if(strcmp(line, "history\n")==0)
+ gl_show_history(gl, stdout, "%N %T %H\n", 0, -1);
+ else if(strcmp(line, "size\n")==0) {
+ GlTerminalSize size = gl_terminal_size(gl, 80, 24);
+ printf("Terminal size = %d columns x %d lines.\n", size.ncolumn,
+ size.nline);
+ } else if(strcmp(line, "clear\n")==0) {
+ if(gl_erase_terminal(gl))
+ return 1;
+ };
+/*
+ * To resume command-line editing, return the terminal to raw,
+ * non-blocking I/O mode.
+ */
+ gl_raw_io(gl);
+/*
+ * If gl_get_line() returned NULL because of an error or end-of-file,
+ * abort the program.
+ */
+ } else if(gl_return_status(gl) == GLR_ERROR ||
+ gl_return_status(gl) == GLR_EOF) {
+ cleanup_and_exit(gl, si, 1);
+ };
+ };
+ };
+#endif
+ return 0;
+}
+
+/*.......................................................................
+ * This function is called to return resources to the system and restore
+ * the terminal to its original state before exiting the process.
+ *
+ * Input:
+ * gl GetLine * The line editor.
+ * si SignalActions * The repository for displaced signal handlers.
+ * status int The exit code of the process.
+ */
+static void cleanup_and_exit(GetLine *gl, SignalActions *si, int status)
+{
+/*
+ * Restore the terminal to its original state before exiting the program.
+ */
+ gl_normal_io(gl);
+/*
+ * Save historical command lines.
+ */
+#ifndef WITHOUT_FILE_SYSTEM
+ (void) gl_save_history(gl, "~/.demo_history", "#", -1);
+#endif
+/*
+ * Clean up.
+ */
+ gl = del_GetLine(gl);
+ si = del_SignalActions(si);
+/*
+ * Exit the process.
+ */
+ exit(status);
+}
+
+/*.......................................................................
+ * This is a signal-aware wrapper around the select() system call. It
+ * is designed to facilitate reliable signal handling of a given set
+ * of signals, without the race conditions that would usually surround
+ * the use of select(). See the "RELIABLE SIGNAL HANDLING" section of
+ * the gl_get_line(3) man page for further details.
+ *
+ * Provided that the calling function has blocked the specified set of
+ * signals before calling this function, this function guarantees that
+ * select() will be aborted by any signal that arrives between the
+ * time that the caller blocked the specified signals and this
+ * function returns. On return these signals will again be blocked to
+ * prevent any signals that arrive after select() returns, from being
+ * missed by the caller.
+ *
+ * Note that this function is written not to be specific to this
+ * program, and is thus suitable for use in other programs, whether or
+ * not they use gl_get_line().
+ *
+ * Also note that this function depends on the NSIG preprocessor
+ * constant being >= the maximum number of signals available on the
+ * host operating system. Under BSD and SysV, this macro is set
+ * appropriately in signal.h. On other systems, a reasonably large
+ * guess should be substituted. Although nothing terrible will happen
+ * if a value that is too small is chosen, signal numbers that exceed
+ * the specified value of NSIG will be ignored by this function. A
+ * more robust method than depending on nsig would be to use the
+ * POSIX sigismember() function to count valid signals, and use this
+ * to allocate the array of sigaction structures used to preserve
+ *
+ *
+ * Input:
+ * n int The number of file descriptors to pay
+ * attention to at the start of each of the
+ * following sets of file descriptors.
+ * readfds fd_set * The set of file descriptors to check for
+ * readability, or NULL if not pertinent.
+ * wwritefds fd_set * The set of file descriptors to check for
+ * writability, or NULL if not pertinent.
+ * exceptfds fd_set * The set of file descriptors to check for
+ * the arrival of urgent data, or NULL if
+ * not pertinent.
+ * timeout struct timeval * The maximum time that select() should
+ * wait, or NULL to wait forever.
+ * mask sigset_t * The set of signals to catch.
+ * si SignalHandlers * An object in which to preserve temporary
+ * copies signal handlers.
+ * Output:
+ * return int > 0 The number of entries in all of the
+ * sets of descriptors that are ready
+ * for I/O.
+ * 0 Select() timed out.
+ * -1 Error (see errno).
+ */
+static int demo_sigselect(int n, fd_set *readfds, fd_set *writefds,
+ fd_set *exceptfds, struct timeval *timeout,
+ sigset_t *mask, SignalActions *si)
+{
+/*
+ * The reason that the the following variables are marked as volatile
+ * is to prevent the compiler from placing their values in registers
+ * that might not be saved and restored by sigsetjmp().
+ */
+ volatile sigset_t old_mask; /* The displaced process signal mask */
+ volatile int status; /* The return value of select() */
+/*
+ * Make sure that all of the specified signals are blocked. This is
+ * redundant if the caller has already blocked signals.
+ */
+ if(sigprocmask(SIG_BLOCK, mask, (sigset_t *) &old_mask) < 0)
+ return -1;
+/*
+ * Record the fact that no signal has been caught yet.
+ */
+ demo_setjmp_signo = -1;
+/*
+ * Now set up the point where our temporary signal handlers will return
+ * control if a signal is received.
+ */
+ if(sigsetjmp(demo_setjmp_buffer, 1) == 0) {
+/*
+ * Now install the temporary signal handlers that cause the above
+ * sigsetjmp() to return non-zero when a signal is detected.
+ */
+ if(displace_signal_handlers(si, mask, demo_setjmp_handler)) {
+ reinstate_signal_handlers(si);
+ return 1;
+ };
+/*
+ * Now that we are ready to catch the signals, unblock them.
+ */
+ sigprocmask(SIG_UNBLOCK, mask, NULL);
+/*
+ * At last, call select().
+ */
+ status = select(n, readfds, writefds, exceptfds, timeout);
+/*
+ * Block the specified signals again.
+ */
+ sigprocmask(SIG_BLOCK, mask, NULL);
+/*
+ * Record the fact that no signal was caught.
+ */
+ demo_setjmp_signo = -1;
+ };
+/*
+ * We can get to this point in one of two ways. Either no signals were
+ * caught, and the above block ran to completion (with demo_setjmp_signo=-1),
+ * or a signal was caught that caused the above block to be aborted,
+ * in which case demo_setjmp_signo will now equal the number of the signal that
+ * was caught, and sigsetjmp() will have restored the process signal
+ * mask to how it was before it was called (ie. all of the specified
+ * signals blocked).
+ *
+ * First restore the signal handlers to how they were on entry to
+ * this function.
+ */
+ reinstate_signal_handlers(si);
+/*
+ * Was a signal caught?
+ */
+ if(demo_setjmp_signo > 0) {
+ sigset_t new_mask;
+/*
+ * Send the signal again, then unblock its delivery, so that the application's
+ * signal handler gets invoked.
+ */
+ raise(demo_setjmp_signo);
+ sigemptyset(&new_mask);
+ sigaddset(&new_mask, demo_setjmp_signo);
+ sigprocmask(SIG_UNBLOCK, &new_mask, NULL);
+/*
+ * Set the return status to show that a signal was caught.
+ */
+ errno = EINTR;
+ status = -1;
+ };
+/*
+ * Now restore the process signal mask to how it was on entry to this
+ * function.
+ */
+ sigprocmask(SIG_SETMASK, (sigset_t *) &old_mask, NULL);
+ return status;
+}
+
+/*.......................................................................
+ * This is the main signal handler of this demonstration program. If a
+ * SIGINT is received by the process, it arranges that the next call
+ * to gl_get_line() will abort entry of the current line and start
+ * entering a new one. Otherwise it calls the library function which
+ * handles terminal resize signals and process suspension and process
+ * termination signals. Both of the functions called by this signal
+ * handler are designed to be async-signal safe, provided that the
+ * rules laid out in the gl_io_mode(3) man page are followed.
+ */
+static void demo_signal_handler(int signo)
+{
+ if(signo==SIGINT)
+ gl_abandon_line(demo_gl);
+ else
+ gl_handle_signal(signo, demo_gl, 1);
+}
+
+/*.......................................................................
+ * The following signal handler is installed while select() is being
+ * called from within a block of code protected by sigsetjmp(). It
+ * simply records the signal that was caught in setjmp_signo, then
+ * causes the sigsetjmp() to return non-zero.
+ */
+static void demo_setjmp_handler(int signo)
+{
+ demo_setjmp_signo = signo;
+ siglongjmp(demo_setjmp_buffer, 1);
+}
+
+/*.......................................................................
+ * This optional inactivity timeout function is used in this
+ * demonstration to cause gl_get_line() to wait for a small amount of
+ * time for I/O, before returning and allowing the event loop to
+ * continue. This isn't needed if you want gl_get_line() to return
+ * immediately, rather than blocking.
+ */
+static GL_TIMEOUT_FN(demo_timeout_fn)
+{
+ return GLTO_CONTINUE;
+}
+
+/*.......................................................................
+ * Display introductory text to the user, formatted according to the
+ * current terminal width and enclosed in a box of asterixes.
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ */
+static void show_demo_introduction(GetLine *gl)
+{
+ int start; /* The column in which gl_display_text() left the cursor */
+ int i;
+/*
+ * Break the indtroductory text into an array of strings, so as to
+ * avoid overflowing any compiler string limits.
+ */
+ const char *doc[] = {
+ "To the user this program appears to act identically to the main ",
+ "demo program. However whereas the code underlying the main demo ",
+ "program uses gl_get_line() in its default configuration, where each ",
+ "call blocks the caller until the user has entered a complete input ",
+ "line, demo3 uses gl_get_line() in its non-blocking server mode, ",
+ "where it must be called repeatedly from an external ",
+ "event loop to incrementally accept entry of the input ",
+ "line, as and when terminal I/O becomes possible. The well commented ",
+ "source code of demo3, which can be found in demo3.c, thus provides ",
+ "a working example of how to use gl_get_line() in a manner that ",
+ "doesn't block the caller. Documentation of this mode can be found ",
+ "in the gl_io_mode(3) man page.\n"
+ };
+/*
+ * Form the top line of the documentation box by filling the area of
+ * the line between a " *" prefix and a "* " suffix with asterixes.
+ */
+ printf("\n");
+ gl_display_text(gl, 0, " *", "* ", '*', 80, 0, "\n");
+/*
+ * Justify the documentation text within margins of asterixes.
+ */
+ for(start=0,i=0; i<sizeof(doc)/sizeof(doc[0]) && start >= 0; i++)
+ start = gl_display_text(gl, 0, " * ", " * ", ' ', 80, start,doc[i]);
+/*
+ * Draw the bottom line of the documentation box.
+ */
+ gl_display_text(gl, 0, " *", "* ", '*', 80, 0, "\n");
+ printf("\n");
+}
+
+
+/*.......................................................................
+ * This is a constructor function for an object who's role is to allow
+ * a signal handler to be assigned to potentially all available signals,
+ * while preserving a copy of the original signal handlers, for later
+ * restration.
+ *
+ * Output:
+ * return SignalActions * The new object, or NULL on error.
+ */
+static SignalActions *new_SignalActions(void)
+{
+ SignalActions *si; /* The object to be returned */
+/*
+ * Allocate the container.
+ */
+ si = malloc(sizeof(SignalActions));
+ if(!si) {
+ fprintf(stderr, "new_SignalActions: Insufficient memory.\n");
+ return NULL;
+ };
+/*
+ * Before attempting any operation that might fail, initialize the
+ * container at least up to the point at which it can safely be passed
+ * to del_SignalActions().
+ */
+ si->nsignal = 0;
+ sigemptyset(&si->mask);
+ si->actions = NULL;
+/*
+ * Count the number of signals that are available of the host
+ * platform. Note that si->mask has no members set, and that
+ * sigismember() is defined to return -1 if the signal number
+ * isn't valid.
+ */
+ for(si->nsignal=1; sigismember(&si->mask, si->nsignal) == 0; si->nsignal++)
+ ;
+/*
+ * Allocate the array of sigaction structures to use to keep a record
+ * of displaced signal handlers.
+ */
+ si->actions = (struct sigaction *) malloc(sizeof(*si->actions) * si->nsignal);
+ if(!si->actions) {
+ fprintf(stderr, "Insufficient memory for %d sigaction structures.\n",
+ si->nsignal);
+ return del_SignalActions(si);
+ };
+ return si;
+}
+
+/*.......................................................................
+ * Delete a SignalActions object.
+ *
+ * Input:
+ * si SignalActions * The object to be deleted.
+ * Output:
+ * return SignalActions * The deleted object (always NULL).
+ */
+static SignalActions *del_SignalActions(SignalActions *si)
+{
+ if(si) {
+ if(si->actions)
+ free(si->actions);
+ free(si);
+ };
+ return NULL;
+}
+
+/*.......................................................................
+ * Replace the signal handlers of all of the signals in 'mask' with
+ * the signal handler 'handler'.
+ *
+ * Input:
+ * si SignalActions * The object in which to record the displaced
+ * signal handlers.
+ * mask sigset_t * The set of signals who's signal handlers
+ * should be displaced.
+ * handler void (*handler)(int) The new signal handler to assign to each
+ * of the signals marked in 'mask'.
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+static int displace_signal_handlers(SignalActions *si, sigset_t *mask,
+ void (*handler)(int))
+{
+ int signo; /* A signal number */
+ struct sigaction action; /* The new signal handler */
+/*
+ * Mark the fact that so far we haven't displaced any signal handlers.
+ */
+ sigemptyset(&si->mask);
+/*
+ * Set up the description of the new signal handler. Note that
+ * we make sa_mask=mask. This ensures that only one instance of the
+ * signal handler will ever be running at one time.
+ */
+ action.sa_handler = handler;
+ memcpy(&action.sa_mask, mask, sizeof(*mask));
+ action.sa_flags = 0;
+/*
+ * Check each of the available signals to see if it is specified in 'mask'.
+ * If so, install the new signal handler, record the displaced one in
+ * the corresponding element of si->actions[], and make a record in
+ * si->mask that this signal handler has been displaced.
+ */
+ for(signo=1; signo < si->nsignal; signo++) {
+ if(sigismember(mask, signo)) {
+ if(sigaction(signo, &action, &si->actions[signo]) < 0) {
+ fprintf(stderr, "sigaction error (%s)\n", strerror(errno));
+ return 1;
+ };
+ sigaddset(&si->mask, signo);
+ };
+ };
+ return 0;
+}
+
+/*.......................................................................
+ * Reinstate any signal handlers displaced by displace_signal_handlers().
+ *
+ * Input:
+ * sig SignalActions * The object containing the displaced signal
+ * handlers.
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+static int reinstate_signal_handlers(SignalActions *si)
+{
+ int signo; /* A signal number */
+/*
+ * Check each of the available signals to see if it is specified in
+ * si->mask. If so, reinstate the displaced recorded in the
+ * corresponding element of si->actions[], and make a record in
+ * si->mask that this signal handler has been reinstated.
+ */
+ for(signo=1; signo < si->nsignal; signo++) {
+ if(sigismember(&si->mask, signo)) {
+ if(sigaction(signo, &si->actions[signo], NULL) < 0) {
+ fprintf(stderr, "sigaction error (%s)\n", strerror(errno));
+ return 1;
+ };
+ sigdelset(&si->mask, signo);
+ };
+ };
+ return 0;
+}
diff --git a/libtecla-1.4.1/direader.c b/libtecla-1.6.1/direader.c
index 8a81fbf..68db93f 100644
--- a/libtecla-1.4.1/direader.c
+++ b/libtecla-1.6.1/direader.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2001 by Martin C. Shepherd.
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
*
* All rights reserved.
*
@@ -30,6 +30,12 @@
*/
/*
+ * If file-system access is to be excluded, this module has no function,
+ * so all of its code should be excluded.
+ */
+#ifndef WITHOUT_FILE_SYSTEM
+
+/*
* Standard includes.
*/
#include <stdio.h>
@@ -46,33 +52,27 @@
#include <dirent.h>
#include "direader.h"
+#include "errmsg.h"
/*
* Use the reentrant POSIX threads version of readdir()?
*/
-#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199506L
+#if defined(PREFER_REENTRANT) && defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199506L
#define USE_READDIR_R 1
#endif
/*
- * Set the max length of the error-reporting string. There is no point
- * in this being longer than the width of a typical terminal window.
- * In composing error messages, I have assumed that this number is
- * at least 80, so you don't decrease it below this number.
- */
-#define ERRLEN 200
-
-/*
* Objects of the following type are used to maintain the resources
* needed to read directories.
*/
struct DirReader {
- DIR *dir; /* The directory stream (if open, NULL otherwise) */
- struct dirent *file; /* The latest directory entry */
- char errmsg[ERRLEN+1]; /* Error-report buffer */
+ ErrMsg *err; /* The error reporting buffer */
+ DIR *dir; /* The directory stream (if open, NULL otherwise) */
+ struct dirent *file; /* The latest directory entry */
#ifdef USE_READDIR_R
- struct dirent *buffer; /* A buffer used by the threaded version of readdir */
- int buffer_dim; /* The allocated size of buffer[] */
+ struct dirent *buffer; /* A buffer used by the threaded version of */
+ /* readdir() */
+ int buffer_dim; /* The allocated size of buffer[] */
#endif
};
@@ -92,7 +92,7 @@ DirReader *_new_DirReader(void)
*/
dr = (DirReader *) malloc(sizeof(DirReader));
if(!dr) {
- fprintf(stderr, "_new_DirReader: Insufficient memory.\n");
+ errno = ENOMEM;
return NULL;
};
/*
@@ -100,13 +100,19 @@ DirReader *_new_DirReader(void)
* container at least up to the point at which it can safely be passed
* to _del_DirReader().
*/
+ dr->err = NULL;
dr->dir = NULL;
dr->file = NULL;
- dr->errmsg[0] = '\0';
#ifdef USE_READDIR_R
dr->buffer = NULL;
dr->buffer_dim = 0;
#endif
+/*
+ * Allocate a place to record error messages.
+ */
+ dr->err = _new_ErrMsg();
+ if(!dr->err)
+ return _del_DirReader(dr);
return dr;
}
@@ -125,6 +131,7 @@ DirReader *_del_DirReader(DirReader *dr)
#ifdef USE_READDIR_R
free(dr->buffer);
#endif
+ dr->err = _del_ErrMsg(dr->err);
free(dr);
};
return NULL;
@@ -156,9 +163,8 @@ int _dr_open_dir(DirReader *dr, const char *path, char **errmsg)
*/
if(!_dr_path_is_dir(path)) {
if(errmsg) {
- const char *fmt = "Can't open directory: %.*s\n";
- sprintf(dr->errmsg, fmt, ERRLEN - strlen(fmt), path);
- *errmsg = dr->errmsg;
+ _err_record_msg(dr->err, "Can't open directory: ", path, END_ERR_MSG);
+ *errmsg = _err_get_msg(dr->err);
};
return 1;
};
@@ -168,9 +174,8 @@ int _dr_open_dir(DirReader *dr, const char *path, char **errmsg)
dir = opendir(path);
if(!dir) {
if(errmsg) {
- const char *fmt = "Can't open directory: %.*s\n";
- sprintf(dr->errmsg, fmt, ERRLEN - strlen(fmt), path);
- *errmsg = dr->errmsg;
+ _err_record_msg(dr->err, "Can't open directory: ", path, END_ERR_MSG);
+ *errmsg = _err_get_msg(dr->err);
};
return 1;
};
@@ -187,8 +192,9 @@ int _dr_open_dir(DirReader *dr, const char *path, char **errmsg)
#endif
if(name_max < 0) {
if(errmsg) {
- strcpy(dr->errmsg, "Unable to deduce readdir() buffer size.");
- *errmsg = dr->errmsg;
+ _err_record_msg(dr->err, "Unable to deduce readdir() buffer size.",
+ END_ERR_MSG);
+ *errmsg = _err_get_msg(dr->err);
};
closedir(dir);
return 1;
@@ -206,10 +212,12 @@ int _dr_open_dir(DirReader *dr, const char *path, char **errmsg)
malloc(size));
if(!buffer) {
if(errmsg) {
- strcpy(dr->errmsg, "Insufficient memory for readdir() buffer.");
- *errmsg = dr->errmsg;
+ _err_record_msg(dr->err, "Insufficient memory for readdir() buffer.",
+ END_ERR_MSG);
+ *errmsg = _err_get_msg(dr->err);
};
closedir(dir);
+ errno = ENOMEM;
return 1;
};
dr->buffer = buffer;
@@ -237,7 +245,7 @@ void _dr_close_dir(DirReader *dr)
closedir(dr->dir);
dr->dir = NULL;
dr->file = NULL;
- dr->errmsg[0] = '\0';
+ _err_clear_msg(dr->err);
};
}
@@ -297,3 +305,5 @@ static int _dr_path_is_dir(const char *pathname)
*/
return S_ISDIR(statbuf.st_mode) != 0;
}
+
+#endif /* ifndef WITHOUT_FILE_SYSTEM */
diff --git a/libtecla-1.4.1/direader.h b/libtecla-1.6.1/direader.h
index 2cf178e..c529231 100644
--- a/libtecla-1.4.1/direader.h
+++ b/libtecla-1.6.1/direader.h
@@ -2,7 +2,7 @@
#define dirreader_h
/*
- * Copyright (c) 2000, 2001 by Martin C. Shepherd.
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
*
* All rights reserved.
*
diff --git a/libtecla-1.4.1/enhance.c b/libtecla-1.6.1/enhance.c
index 72f5061..bd5af1f 100644
--- a/libtecla-1.4.1/enhance.c
+++ b/libtecla-1.6.1/enhance.c
@@ -8,6 +8,12 @@
#include <unistd.h>
#include <termios.h>
+#ifdef HAVE_SELECT
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#endif
+
#include <fcntl.h>
#include <sys/time.h>
#include <sys/types.h>
diff --git a/libtecla-1.6.1/errmsg.c b/libtecla-1.6.1/errmsg.c
new file mode 100644
index 0000000..6abce9b
--- /dev/null
+++ b/libtecla-1.6.1/errmsg.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
+ *
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, and/or sell copies of the Software, and to permit persons
+ * to whom the Software is furnished to do so, provided that the above
+ * copyright notice(s) and this permission notice appear in all copies of
+ * the Software and that both the above copyright notice(s) and this
+ * permission notice appear in supporting documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+ * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
+ * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder
+ * shall not be used in advertising or otherwise to promote the sale, use
+ * or other dealings in this Software without prior written authorization
+ * of the copyright holder.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdarg.h>
+
+#include "errmsg.h"
+
+/*
+ * Encapsulate the error reporting buffer in an opaque object.
+ */
+struct ErrMsg {
+ char msg[ERR_MSG_LEN+1]; /* An error message */
+};
+
+/*.......................................................................
+ * Create a new error-message object.
+ *
+ * Output:
+ * return ErrMsg * The new object, or NULL on error.
+ */
+ErrMsg *_new_ErrMsg(void)
+{
+ ErrMsg *err; /* The object to be returned */
+/*
+ * Allocate the container.
+ */
+ err = malloc(sizeof(ErrMsg));
+ if(!err) {
+ errno = ENOMEM;
+ return NULL;
+ };
+/*
+ * Before attempting any operation that might fail, initialize the
+ * container at least up to the point at which it can safely be passed
+ * to del_ErrMsg().
+ */
+ err->msg[0] = '\0';
+ return err;
+}
+
+/*.......................................................................
+ * Delete an error-message object.
+ *
+ * Input:
+ * err ErrMsg * The object to be deleted.
+ * Output:
+ * return ErrMsg * The deleted object (always NULL).
+ */
+ErrMsg *_del_ErrMsg(ErrMsg *err)
+{
+ if(err) {
+ free(err);
+ };
+ return NULL;
+}
+
+/*.......................................................................
+ * Record the concatenation of a list of string arguments in an error
+ * message object. The last argument must be END_ERR_MSG to terminate
+ * the argument list.
+ *
+ * Input:
+ * err ErrMsg * The error-message container.
+ * ... const char * Zero or more strings to be concatenated in buff[].
+ * ... const char * The last argument must always be END_ERR_MSG to
+ * terminate the argument list.
+ */
+void _err_record_msg(ErrMsg *err, ...)
+{
+ va_list ap; /* The variable argument list */
+ const char *s; /* The string being printed */
+ size_t msglen = 0; /* The total length of the message */
+/*
+ * Nowhere to record the result?
+ */
+ if(!err) {
+ errno = EINVAL;
+ return;
+ };
+/*
+ * Concatenate the list of argument strings in err->msg[].
+ */
+ va_start(ap, err);
+ while((s = va_arg(ap, const char *)) != END_ERR_MSG) {
+/*
+ * How much room is left in the output buffer (note that the output
+ * buffer has ERR_MSG_LEN+1 elements).
+ */
+ int nleft = ERR_MSG_LEN - msglen;
+/*
+ * How long is the next string to be appended?
+ */
+ size_t slen = strlen(s);
+/*
+ * If there is any room left, append as much of the string
+ * as will fit.
+ */
+ if(nleft > 0) {
+ int nnew = slen < nleft ? slen : nleft;
+ strncpy(err->msg + msglen, s, nnew);
+ msglen += nnew;
+ };
+ };
+ va_end(ap);
+/*
+ * Terminate the message.
+ */
+ err->msg[msglen] = '\0';
+ return;
+}
+
+/*.......................................................................
+ * Return a pointer to the error message buffer.
+ *
+ * Input:
+ * err ErrMsg * The container of the error message buffer.
+ * Output:
+ * return char * The current error message, or NULL if err==NULL.
+ */
+char *_err_get_msg(ErrMsg *err)
+{
+ return err ? err->msg : NULL;
+}
+
+/*.......................................................................
+ * Replace the current error message with an empty string.
+ *
+ * Input:
+ * err ErrMsg * The container of the error message buffer.
+ */
+void _err_clear_msg(ErrMsg *err)
+{
+ if(err)
+ err->msg[0] = '\0';
+}
+
diff --git a/libtecla-1.6.1/errmsg.h b/libtecla-1.6.1/errmsg.h
new file mode 100644
index 0000000..565d7cd
--- /dev/null
+++ b/libtecla-1.6.1/errmsg.h
@@ -0,0 +1,85 @@
+#ifndef errmsg_h
+#define errmsg_h
+
+/*
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
+ *
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, and/or sell copies of the Software, and to permit persons
+ * to whom the Software is furnished to do so, provided that the above
+ * copyright notice(s) and this permission notice appear in all copies of
+ * the Software and that both the above copyright notice(s) and this
+ * permission notice appear in supporting documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+ * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
+ * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder
+ * shall not be used in advertising or otherwise to promote the sale, use
+ * or other dealings in this Software without prior written authorization
+ * of the copyright holder.
+ */
+
+/*
+ * Set the longest expected length of an error message (excluding its
+ * '\0' terminator. Since any message over a nominal terminal width of
+ * 80 characters is going to look a mess, it makes no sense to support
+ * huge lengths. Note that many uses of strings declared with this
+ * macro assume that it will be at least 81, so don't reduce it below
+ * this limit.
+ */
+#define ERR_MSG_LEN 128
+
+/*
+ * Provide an opaque typedef to the error-message object.
+ */
+typedef struct ErrMsg ErrMsg;
+
+/*
+ * The following token is used to terminate the argument lists of calls
+ * to _err_record_msg().
+ */
+#define END_ERR_MSG ((const char *)0)
+
+/*
+ * Allocate a new error-message buffer.
+ */
+ErrMsg *_new_ErrMsg(void);
+
+/*
+ * Delete an error message buffer.
+ */
+ErrMsg *_del_ErrMsg(ErrMsg *err);
+
+/*
+ * Concatenate a list of string arguments into the specified buffer, buff[],
+ * which has an allocated size of buffdim characters.
+ * The last argument must be END_ERR_MSG to terminate the argument list.
+ */
+void _err_record_msg(ErrMsg *err, ...);
+
+/*
+ * Replace the current error message with an empty string.
+ */
+void _err_clear_msg(ErrMsg *err);
+
+/*
+ * Return a pointer to the error message buffer. This is
+ * a '\0' terminated character array containing ERR_MSG_LEN+1
+ * elements.
+ */
+char *_err_get_msg(ErrMsg *err);
+
+#endif
diff --git a/libtecla-1.4.1/expand.c b/libtecla-1.6.1/expand.c
index c1600ab..b3d80e2 100644
--- a/libtecla-1.4.1/expand.c
+++ b/libtecla-1.6.1/expand.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2001 by Martin C. Shepherd.
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
*
* All rights reserved.
*
@@ -29,6 +29,12 @@
* of the copyright holder.
*/
+/*
+ * If file-system access is to be excluded, this module has no function,
+ * so all of its code should be excluded.
+ */
+#ifndef WITHOUT_FILE_SYSTEM
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -40,6 +46,9 @@
#include "homedir.h"
#include "stringrp.h"
#include "libtecla.h"
+#include "ioutil.h"
+#include "expand.h"
+#include "errmsg.h"
/*
* Specify the number of elements to extend the files[] array by
@@ -82,14 +91,13 @@ typedef struct {
#define ENV_LEN 100
/*
- * Set the max length of the error-reporting string. There is no point
- * in this being longer than the width of a typical terminal window.
- * In composing error messages, I have assumed that this number is
- * at least 80, so you don't decrease it below this number.
+ * Set the default number of spaces place between columns when listing
+ * a set of expansions.
*/
-#define ERRLEN 200
+#define EF_COL_SEP 2
struct ExpandFile {
+ ErrMsg *err; /* The error reporting buffer */
StringGroup *sg; /* A list of string segments in which */
/* matching filenames are stored. */
DirCache cache; /* The cache of directory reader objects */
@@ -98,7 +106,6 @@ struct ExpandFile {
int files_dim; /* The allocated dimension of result.files[] */
char usrnam[USR_LEN+1]; /* A user name */
char envnam[ENV_LEN+1]; /* An environment variable name */
- char errmsg[ERRLEN+1]; /* Error-report buffer */
FileExpansion result; /* The container used to return the results of */
/* expanding a path. */
};
@@ -119,6 +126,31 @@ static int ef_string_matches_pattern(const char *file, const char *pattern,
int xplicit, const char *nextp);
static int ef_cmp_strings(const void *v1, const void *v2);
+/*
+ * Encapsulate the formatting information needed to layout a
+ * multi-column listing of expansions.
+ */
+typedef struct {
+ int term_width; /* The width of the terminal (characters) */
+ int column_width; /* The number of characters within in each column. */
+ int ncol; /* The number of columns needed */
+ int nline; /* The number of lines needed */
+} EfListFormat;
+
+/*
+ * Given the current terminal width, and a list of file expansions,
+ * determine how to best use the terminal width to display a multi-column
+ * listing of expansions.
+ */
+static void ef_plan_listing(FileExpansion *result, int term_width,
+ EfListFormat *fmt);
+
+/*
+ * Display a given line of a multi-column list of file-expansions.
+ */
+static int ef_format_line(FileExpansion *result, EfListFormat *fmt, int lnum,
+ GlWriteFn *write_fn, void *data);
+
/*.......................................................................
* Create the resources needed to expand filenames.
*
@@ -133,7 +165,7 @@ ExpandFile *new_ExpandFile(void)
*/
ef = (ExpandFile *) malloc(sizeof(ExpandFile));
if(!ef) {
- fprintf(stderr, "new_ExpandFile: Insufficient memory.\n");
+ errno = ENOMEM;
return NULL;
};
/*
@@ -141,6 +173,7 @@ ExpandFile *new_ExpandFile(void)
* container at least up to the point at which it can safely be passed
* to del_ExpandFile().
*/
+ ef->err = NULL;
ef->sg = NULL;
ef->cache.mem = NULL;
ef->cache.head = NULL;
@@ -152,7 +185,12 @@ ExpandFile *new_ExpandFile(void)
ef->result.nfile = 0;
ef->usrnam[0] = '\0';
ef->envnam[0] = '\0';
- ef->errmsg[0] = '\0';
+/*
+ * Allocate a place to record error messages.
+ */
+ ef->err = _new_ErrMsg();
+ if(!ef->err)
+ return del_ExpandFile(ef);
/*
* Allocate a list of string segments for storing filenames.
*/
@@ -162,7 +200,7 @@ ExpandFile *new_ExpandFile(void)
/*
* Allocate a freelist for allocating directory cache nodes.
*/
- ef->cache.mem = _new_FreeList("new_ExpandFile", sizeof(DirNode), DIR_CACHE_BLK);
+ ef->cache.mem = _new_FreeList(sizeof(DirNode), DIR_CACHE_BLK);
if(!ef->cache.mem)
return del_ExpandFile(ef);
/*
@@ -184,8 +222,7 @@ ExpandFile *new_ExpandFile(void)
ef->result.files = (char **) malloc(sizeof(ef->result.files[0]) *
ef->files_dim);
if(!ef->result.files) {
- fprintf(stderr,
- "new_ExpandFile: Insufficient memory to allocate array of files.\n");
+ errno = ENOMEM;
return del_ExpandFile(ef);
};
return ef;
@@ -216,7 +253,7 @@ ExpandFile *del_ExpandFile(ExpandFile *ef)
* Delete the memory from which the DirNode list was allocated, thus
* deleting the list at the same time.
*/
- ef->cache.mem = _del_FreeList("del_ExpandFile", ef->cache.mem, 1);
+ ef->cache.mem = _del_FreeList(ef->cache.mem, 1);
ef->cache.head = ef->cache.tail = ef->cache.next = NULL;
/*
* Delete the pathname buffer.
@@ -234,6 +271,10 @@ ExpandFile *del_ExpandFile(ExpandFile *ef)
ef->result.files = NULL;
};
/*
+ * Delete the error report buffer.
+ */
+ ef->err = _del_ErrMsg(ef->err);
+/*
* Delete the container.
*/
free(ef);
@@ -312,10 +353,11 @@ FileExpansion *ef_expand_file(ExpandFile *ef, const char *path, int pathlen)
* Check the arguments.
*/
if(!ef || !path) {
- if(ef)
- strcpy(ef->errmsg, "ef_expand_file: NULL path argument");
- else
- fprintf(stderr, "ef_expand_file: NULL argument(s).\n");
+ if(ef) {
+ _err_record_msg(ef->err, "ef_expand_file: NULL path argument",
+ END_ERR_MSG);
+ };
+ errno = EINVAL;
return NULL;
};
/*
@@ -388,7 +430,8 @@ FileExpansion *ef_expand_file(ExpandFile *ef, const char *path, int pathlen)
if(strncmp(path, FS_ROOT_DIR, FS_ROOT_DIR_LEN) == 0) {
dirname = FS_ROOT_DIR;
if(!_pn_append_to_path(ef->path, FS_ROOT_DIR, -1, 0)) {
- strcpy(ef->errmsg, "Insufficient memory to record path");
+ _err_record_msg(ef->err, "Insufficient memory to record path",
+ END_ERR_MSG);
return NULL;
};
path += FS_ROOT_DIR_LEN;
@@ -417,7 +460,7 @@ FileExpansion *ef_expand_file(ExpandFile *ef, const char *path, int pathlen)
* No files matched?
*/
if(ef->result.nfile < 1) {
- strcpy(ef->errmsg, "No files match");
+ _err_record_msg(ef->err, "No files match", END_ERR_MSG);
return NULL;
};
/*
@@ -487,7 +530,8 @@ static int ef_match_relative_pathname(ExpandFile *ef, DirReader *dr,
*/
if((separate && _pn_append_to_path(ef->path, FS_DIR_SEP, -1, 0)==NULL) ||
_pn_append_to_path(ef->path, file, -1, 0)==NULL) {
- strcpy(ef->errmsg, "Insufficient memory to record path");
+ _err_record_msg(ef->err, "Insufficient memory to record path",
+ END_ERR_MSG);
return 1;
};
/*
@@ -547,7 +591,7 @@ static int ef_match_relative_pathname(ExpandFile *ef, DirReader *dr,
* recorded copy of the pathname.
* Output:
* return int 0 - OK.
- * 1 - Error (ef->errmsg will contain a
+ * 1 - Error (ef->err will contain a
* description of the error).
*/
static int ef_record_pathname(ExpandFile *ef, const char *pathname,
@@ -569,8 +613,10 @@ static int ef_record_pathname(ExpandFile *ef, const char *pathname,
char **files = (char **) realloc(ef->result.files,
files_dim * sizeof(files[0]));
if(!files) {
- sprintf(ef->errmsg,
- "Insufficient memory to record all of the matching filenames");
+ _err_record_msg(ef->err,
+ "Insufficient memory to record all of the matching filenames",
+ END_ERR_MSG);
+ errno = ENOMEM;
return 1;
};
ef->result.files = files;
@@ -594,14 +640,15 @@ static int ef_record_pathname(ExpandFile *ef, const char *pathname,
* Output:
* return char * The pointer to the copy of the pathname.
* On error NULL is returned and a description
- * of the error is left in ef->errmsg[].
+ * of the error is left in ef->err.
*/
static char *ef_cache_pathname(ExpandFile *ef, const char *pathname,
int remove_escapes)
{
char *copy = _sg_store_string(ef->sg, pathname, remove_escapes);
if(!copy)
- strcpy(ef->errmsg, "Insufficient memory to store pathname");
+ _err_record_msg(ef->err, "Insufficient memory to store pathname",
+ END_ERR_MSG);
return copy;
}
@@ -618,7 +665,7 @@ static void ef_clear_files(ExpandFile *ef)
_pn_clear_path(ef->path);
ef->result.exists = 0;
ef->result.nfile = 0;
- ef->errmsg[0] = '\0';
+ _err_clear_msg(ef->err);
return;
}
@@ -630,7 +677,7 @@ static void ef_clear_files(ExpandFile *ef)
* pathname const char * The pathname of the directory.
* Output:
* return DirNode * The cache entry of the new directory reader,
- * or NULL on error. On error, ef->errmsg will
+ * or NULL on error. On error, ef->err will
* contain a description of the error.
*/
static DirNode *ef_open_dir(ExpandFile *ef, const char *pathname)
@@ -647,7 +694,8 @@ static DirNode *ef_open_dir(ExpandFile *ef, const char *pathname)
if(!cache->next) {
node = (DirNode *) _new_FreeListNode(cache->mem);
if(!node) {
- sprintf(ef->errmsg, "Insufficient memory to open a new directory");
+ _err_record_msg(ef->err, "Insufficient memory to open a new directory",
+ END_ERR_MSG);
return NULL;
};
/*
@@ -661,7 +709,8 @@ static DirNode *ef_open_dir(ExpandFile *ef, const char *pathname)
*/
node->dr = _new_DirReader();
if(!node->dr) {
- sprintf(ef->errmsg, "Insufficient memory to open a new directory");
+ _err_record_msg(ef->err, "Insufficient memory to open a new directory",
+ END_ERR_MSG);
node = (DirNode *) _del_FreeListNode(cache->mem, node);
return NULL;
};
@@ -683,8 +732,7 @@ static DirNode *ef_open_dir(ExpandFile *ef, const char *pathname)
* Attempt to open the specified directory.
*/
if(_dr_open_dir(node->dr, pathname, &errmsg)) {
- strncpy(ef->errmsg, errmsg, ERRLEN);
- ef->errmsg[ERRLEN] = '\0';
+ _err_record_msg(ef->err, errmsg, END_ERR_MSG);
return NULL;
};
/*
@@ -988,7 +1036,7 @@ static int ef_cmp_strings(const void *v1, const void *v2)
* Output:
* return char * A pointer to a copy of the output path in the
* cache. On error NULL is returned, and a description
- * of the error is left in ef->errmsg[].
+ * of the error is left in ef->err.
*/
static char *ef_expand_special(ExpandFile *ef, const char *path, int pathlen)
{
@@ -1022,7 +1070,8 @@ static char *ef_expand_special(ExpandFile *ef, const char *path, int pathlen)
*/
if(spos < ppos && _pn_append_to_path(ef->path, path + spos, ppos-spos, 0)
== NULL) {
- strcpy(ef->errmsg, "Insufficient memory to expand path");
+ _err_record_msg(ef->err, "Insufficient memory to expand path",
+ END_ERR_MSG);
return NULL;
};
/*
@@ -1043,7 +1092,8 @@ static char *ef_expand_special(ExpandFile *ef, const char *path, int pathlen)
* whereas our ENV_LEN is much bigger than that.
*/
if(envlen >= ENV_LEN) {
- strcpy(ef->errmsg, "Environment variable name too long");
+ _err_record_msg(ef->err, "Environment variable name too long",
+ END_ERR_MSG);
return NULL;
};
/*
@@ -1055,15 +1105,16 @@ static char *ef_expand_special(ExpandFile *ef, const char *path, int pathlen)
*/
value = getenv(ef->envnam);
if(!value) {
- const char *fmt = "No expansion found for: $%.*s";
- sprintf(ef->errmsg, fmt, ERRLEN - strlen(fmt), ef->envnam);
+ _err_record_msg(ef->err, "No expansion found for: $", ef->envnam,
+ END_ERR_MSG);
return NULL;
};
/*
* Copy the value of the environment variable into the output pathname.
*/
if(_pn_append_to_path(ef->path, value, -1, 0) == NULL) {
- strcpy(ef->errmsg, "Insufficient memory to expand path");
+ _err_record_msg(ef->err, "Insufficient memory to expand path",
+ END_ERR_MSG);
return NULL;
};
/*
@@ -1077,7 +1128,7 @@ static char *ef_expand_special(ExpandFile *ef, const char *path, int pathlen)
*/
if(spos < ppos && _pn_append_to_path(ef->path, path + spos, ppos-spos, 0)
== NULL) {
- strcpy(ef->errmsg, "Insufficient memory to expand path");
+ _err_record_msg(ef->err, "Insufficient memory to expand path", END_ERR_MSG);
return NULL;
};
/*
@@ -1111,7 +1162,7 @@ static char *ef_expand_special(ExpandFile *ef, const char *path, int pathlen)
* whereas our USR_LEN is much bigger than that.
*/
if(usrlen >= USR_LEN) {
- strcpy(ef->errmsg, "Username too long");
+ _err_record_msg(ef->err, "Username too long", END_ERR_MSG);
return NULL;
};
/*
@@ -1123,8 +1174,7 @@ static char *ef_expand_special(ExpandFile *ef, const char *path, int pathlen)
*/
homedir = _hd_lookup_home_dir(ef->home, ef->usrnam);
if(!homedir) {
- strncpy(ef->errmsg, _hd_last_home_dir_error(ef->home), ERRLEN);
- ef->errmsg[ERRLEN] = '\0';
+ _err_record_msg(ef->err, _hd_last_home_dir_error(ef->home), END_ERR_MSG);
return NULL;
};
homelen = strlen(homedir);
@@ -1145,7 +1195,8 @@ static char *ef_expand_special(ExpandFile *ef, const char *path, int pathlen)
* Note that pptr may not be valid after this call.
*/
if(_pn_resize_path(ef->path, plen - usrlen - 1 - skip + homelen)==NULL) {
- strcpy(ef->errmsg, "Insufficient memory to expand filename");
+ _err_record_msg(ef->err, "Insufficient memory to expand filename",
+ END_ERR_MSG);
return NULL;
};
/*
@@ -1176,7 +1227,7 @@ static char *ef_expand_special(ExpandFile *ef, const char *path, int pathlen)
*/
const char *ef_last_error(ExpandFile *ef)
{
- return ef ? ef->errmsg : "NULL ExpandFile argument";
+ return ef ? _err_get_msg(ef->err) : "NULL ExpandFile argument";
}
/*.......................................................................
@@ -1193,26 +1244,83 @@ const char *ef_last_error(ExpandFile *ef)
*/
int ef_list_expansions(FileExpansion *result, FILE *fp, int term_width)
{
- int maxlen; /* The length of the longest matching string */
- int width; /* The width of a column */
- int ncol; /* The number of columns to list */
- int nrow; /* The number of rows needed to list all of the expansions */
- int row,col; /* The row and column being written to */
- int i;
-/*
- * Check the arguments.
+ return _ef_output_expansions(result, _io_write_stdio, fp, term_width);
+}
+
+/*.......................................................................
+ * Print out an array of matching files via a callback.
+ *
+ * Input:
+ * result FileExpansion * The container of the sorted array of
+ * expansions.
+ * write_fn GlWriteFn * The function to call to write the
+ * expansions or 0 to discard the output.
+ * data void * Anonymous data to pass to write_fn().
+ * term_width int The width of the terminal.
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
*/
- if(!result || !fp) {
- fprintf(stderr, "ef_list_expansions: NULL argument(s).\n");
- return 1;
- };
+int _ef_output_expansions(FileExpansion *result, GlWriteFn *write_fn,
+ void *data, int term_width)
+{
+ EfListFormat fmt; /* List formatting information */
+ int lnum; /* The sequential number of the line to print next */
/*
* Not enough space to list anything?
*/
if(term_width < 1)
return 0;
/*
- * Work out the maximum length of the matching filenames.
+ * Do we have a callback to write via, and any expansions to be listed?
+ */
+ if(write_fn && result && result->nfile>0) {
+/*
+ * Work out how to arrange the listing into fixed sized columns.
+ */
+ ef_plan_listing(result, term_width, &fmt);
+/*
+ * Print the listing to the specified stream.
+ */
+ for(lnum=0; lnum < fmt.nline; lnum++) {
+ if(ef_format_line(result, &fmt, lnum, write_fn, data))
+ return 1;
+ };
+ };
+ return 0;
+}
+
+/*.......................................................................
+ * Work out how to arrange a given array of completions into a listing
+ * of one or more fixed size columns.
+ *
+ * Input:
+ * result FileExpansion * The set of completions to be listed.
+ * term_width int The width of the terminal. A lower limit of
+ * zero is quietly enforced.
+ * Input/Output:
+ * fmt EfListFormat * The formatting information will be assigned
+ * to the members of *fmt.
+ */
+static void ef_plan_listing(FileExpansion *result, int term_width,
+ EfListFormat *fmt)
+{
+ int maxlen; /* The length of the longest matching string */
+ int i;
+/*
+ * Ensure that term_width >= 0.
+ */
+ if(term_width < 0)
+ term_width = 0;
+/*
+ * Start by assuming the worst case, that either nothing will fit
+ * on the screen, or that there are no matches to be listed.
+ */
+ fmt->term_width = term_width;
+ fmt->column_width = 0;
+ fmt->nline = fmt->ncol = 0;
+/*
+ * Work out the maximum length of the matching strings.
*/
maxlen = 0;
for(i=0; i<result->nfile; i++) {
@@ -1224,42 +1332,117 @@ int ef_list_expansions(FileExpansion *result, FILE *fp, int term_width)
* Nothing to list?
*/
if(maxlen == 0)
- return 0;
+ return;
/*
- * Split the available terminal width into columns of maxlen + 2 characters.
+ * Split the available terminal width into columns of
+ * maxlen + EF_COL_SEP characters.
*/
- width = maxlen + 2;
- ncol = term_width / width;
+ fmt->column_width = maxlen;
+ fmt->ncol = fmt->term_width / (fmt->column_width + EF_COL_SEP);
/*
- * If the column width is greater than the terminal width, the matches will
- * just have to overlap onto the next line.
+ * If the column width is greater than the terminal width, zero columns
+ * will have been selected. Set a lower limit of one column. Leave it
+ * up to the caller how to deal with completions who's widths exceed
+ * the available terminal width.
*/
- if(ncol < 1)
- ncol = 1;
+ if(fmt->ncol < 1)
+ fmt->ncol = 1;
+/*
+ * How many lines of output will be needed?
+ */
+ fmt->nline = (result->nfile + fmt->ncol - 1) / fmt->ncol;
+ return;
+}
+
+/*.......................................................................
+ * Render one line of a multi-column listing of completions, using a
+ * callback function to pass the output to an arbitrary destination.
+ *
+ * Input:
+ * result FileExpansion * The container of the sorted array of
+ * completions.
+ * fmt EfListFormat * Formatting information.
+ * lnum int The index of the line to print, starting
+ * from 0, and incrementing until the return
+ * value indicates that there is nothing more
+ * to be printed.
+ * write_fn GlWriteFn * The function to call to write the line, or
+ * 0 to discard the output.
+ * data void * Anonymous data to pass to write_fn().
+ * Output:
+ * return int 0 - Line printed ok.
+ * 1 - Nothing to print.
+ */
+static int ef_format_line(FileExpansion *result, EfListFormat *fmt, int lnum,
+ GlWriteFn *write_fn, void *data)
+{
+ int col; /* The index of the list column being output */
+/*
+ * If the line index is out of bounds, there is nothing to be written.
+ */
+ if(lnum < 0 || lnum >= fmt->nline)
+ return 1;
/*
- * How many rows will be needed?
+ * If no output function has been provided, return as though the line
+ * had been printed.
*/
- nrow = (result->nfile + ncol - 1) / ncol;
+ if(!write_fn)
+ return 0;
/*
- * Print the expansions out in ncol columns, sorted in row order within each
+ * Print the matches in 'ncol' columns, sorted in line order within each
* column.
*/
- for(row=0; row < nrow; row++) {
- for(col=0; col < ncol; col++) {
- int m = col*nrow + row;
- if(m < result->nfile) {
- const char *filename = result->files[m];
- if(fprintf(fp, "%s%-*s%s", filename,
- (int) (ncol > 1 ? maxlen - strlen(filename):0), "",
- col<ncol-1 ? " " : "\r\n") < 0)
- return 1;
- } else {
- if(fprintf(fp, "\r\n") < 0)
- return 1;
- break;
+ for(col=0; col < fmt->ncol; col++) {
+ int m = col*fmt->nline + lnum;
+/*
+ * Is there another match to be written? Note that in general
+ * the last line of a listing will have fewer filled columns
+ * than the initial lines.
+ */
+ if(m < result->nfile) {
+ char *file = result->files[m];
+/*
+ * How long are the completion and type-suffix strings?
+ */
+ int flen = strlen(file);
+/*
+ * Write the completion string.
+ */
+ if(write_fn(data, file, flen) != flen)
+ return 1;
+/*
+ * If another column follows the current one, pad to its start with spaces.
+ */
+ if(col+1 < fmt->ncol) {
+/*
+ * The following constant string of spaces is used to pad the output.
+ */
+ static const char spaces[] = " ";
+ static const int nspace = sizeof(spaces) - 1;
+/*
+ * Pad to the next column, using as few sub-strings of the spaces[]
+ * array as possible.
+ */
+ int npad = fmt->column_width + EF_COL_SEP - flen;
+ while(npad>0) {
+ int n = npad > nspace ? nspace : npad;
+ if(write_fn(data, spaces + nspace - n, n) != n)
+ return 1;
+ npad -= n;
+ };
};
};
};
+/*
+ * Start a new line.
+ */
+ {
+ char s[] = "\r\n";
+ int n = strlen(s);
+ if(write_fn(data, s, n) != n)
+ return 1;
+ };
return 0;
}
+#endif /* ifndef WITHOUT_FILE_SYSTEM */
diff --git a/libtecla-1.6.1/expand.h b/libtecla-1.6.1/expand.h
new file mode 100644
index 0000000..8c0bad8
--- /dev/null
+++ b/libtecla-1.6.1/expand.h
@@ -0,0 +1,48 @@
+#ifndef expand_h
+#define expand_h
+
+/*
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
+ *
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, and/or sell copies of the Software, and to permit persons
+ * to whom the Software is furnished to do so, provided that the above
+ * copyright notice(s) and this permission notice appear in all copies of
+ * the Software and that both the above copyright notice(s) and this
+ * permission notice appear in supporting documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+ * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
+ * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder
+ * shall not be used in advertising or otherwise to promote the sale, use
+ * or other dealings in this Software without prior written authorization
+ * of the copyright holder.
+ */
+
+/*
+ * This header is not for use by external applicatons. It contains
+ * internal immplementation features of the libtecla library, which
+ * may change incompatibly between releases.
+ */
+
+/*
+ * Print a list of expansions via a callback function.
+ */
+int _ef_output_expansions(FileExpansion *result, GlWriteFn *write_fn,
+ void *data, int term_width);
+
+
+#endif
diff --git a/libtecla-1.4.1/freelist.c b/libtecla-1.6.1/freelist.c
index 4fe0472..2a85ba1 100644
--- a/libtecla-1.4.1/freelist.c
+++ b/libtecla-1.6.1/freelist.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2001 by Martin C. Shepherd.
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
*
* All rights reserved.
*
@@ -31,6 +31,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <errno.h>
#include "freelist.h"
@@ -44,6 +45,7 @@ struct FreeList {
size_t node_size; /* The size of a free-list node */
unsigned blocking_factor; /* The number of nodes per block */
long nbusy; /* The number of nodes that are in use */
+ long ntotal; /* The total number of nodes in the free list */
FreeListBlock *block; /* The head of the list of free-list blocks */
void *free_list; /* The free-list of nodes */
};
@@ -57,9 +59,6 @@ static void _thread_FreeListBlock(FreeList *fl, FreeListBlock *block);
* node_size.
*
* Input:
- * caller const char * The name of the calling function, for use in
- * error messages, or NULL to not report errors
- * to stderr.
* node_size size_t The size of the free-list nodes to be returned
* by _new_FreeListNode(). Use sizeof() to
* determine this.
@@ -68,8 +67,7 @@ static void _thread_FreeListBlock(FreeList *fl, FreeListBlock *block);
* Output:
* return FreeList * The new freelist, or NULL on error.
*/
-FreeList *_new_FreeList(const char *caller, size_t node_size,
- unsigned blocking_factor)
+FreeList *_new_FreeList(size_t node_size, unsigned blocking_factor)
{
FreeList *fl; /* The new free-list container */
/*
@@ -92,8 +90,7 @@ FreeList *_new_FreeList(const char *caller, size_t node_size,
*/
fl = (FreeList *) malloc(sizeof(FreeList));
if(!fl) {
- if(caller)
- fprintf(stderr, "_new_FreeList (%s): Insufficient memory.\n", caller);
+ errno = ENOMEM;
return NULL;
};
/*
@@ -104,6 +101,7 @@ FreeList *_new_FreeList(const char *caller, size_t node_size,
fl->node_size = node_size;
fl->blocking_factor = blocking_factor;
fl->nbusy = 0;
+ fl->ntotal = 0;
fl->block = NULL;
fl->free_list = NULL;
/*
@@ -111,9 +109,8 @@ FreeList *_new_FreeList(const char *caller, size_t node_size,
*/
fl->block = _new_FreeListBlock(fl);
if(!fl->block) {
- if(caller)
- fprintf(stderr, "_new_FreeList (%s): Insufficient memory.\n", caller);
- return _del_FreeList(caller, fl, 1);
+ errno = ENOMEM;
+ return _del_FreeList(fl, 1);
};
/*
* Add the new list of nodes to the free-list.
@@ -171,9 +168,6 @@ void _rst_FreeList(FreeList *fl)
* Delete a free-list.
*
* Input:
- * caller const char * The name of the calling function, for use in
- * error messages, or NULL if error messages
- * shouldn't be reported to stderr.
* fl FreeList * The free-list to be deleted, or NULL.
* force int If force==0 then _del_FreeList() will complain
* and refuse to delete the free-list if any
@@ -185,16 +179,14 @@ void _rst_FreeList(FreeList *fl)
* return FreeList * Always NULL (even if the list couldn't be
* deleted).
*/
-FreeList *_del_FreeList(const char *caller, FreeList *fl, int force)
+FreeList *_del_FreeList(FreeList *fl, int force)
{
if(fl) {
/*
* Check whether any nodes are in use.
*/
if(!force && _busy_FreeListNodes(fl) != 0) {
- if(caller)
- fprintf(stderr, "_del_FreeList (%s): %ld nodes are still in use.\n",
- caller, _busy_FreeListNodes(fl));
+ errno = EBUSY;
return NULL;
};
/*
@@ -274,9 +266,6 @@ void *_new_FreeListNode(FreeList *fl)
* Return an object to the free-list that it was allocated from.
*
* Input:
- * caller const char * The name of the calling function, for use in
- * error messages, or NULL to not report errors
- * to stderr.
* fl FreeList * The free-list from which the object was taken.
* object void * The node to be returned.
* Output:
@@ -317,6 +306,20 @@ long _busy_FreeListNodes(FreeList *fl)
}
/*.......................................................................
+ * Query the number of allocated nodes in the freelist which are
+ * currently unused.
+ *
+ * Input:
+ * fl FreeList * The list to count wrt, or NULL.
+ * Output:
+ * return long The number of unused nodes (or 0 if fl==NULL).
+ */
+long _idle_FreeListNodes(FreeList *fl)
+{
+ return fl ? (fl->ntotal - fl->nbusy) : 0;
+}
+
+/*.......................................................................
* Allocate a new list of free-list nodes. On return the nodes will
* be linked together as a list starting with the node at the lowest
* address and ending with a NULL next pointer.
@@ -353,6 +356,10 @@ static FreeListBlock *_new_FreeListBlock(FreeList *fl)
* Initialize the block as a linked list of FreeListNode's.
*/
_thread_FreeListBlock(fl, block);
+/*
+ * Update the record of the number of nodes in the freelist.
+ */
+ fl->ntotal += fl->blocking_factor;
return block;
}
diff --git a/libtecla-1.4.1/freelist.h b/libtecla-1.6.1/freelist.h
index 84e6aef..09d966f 100644
--- a/libtecla-1.4.1/freelist.h
+++ b/libtecla-1.6.1/freelist.h
@@ -2,7 +2,7 @@
#define freelist_h
/*
- * Copyright (c) 2000, 2001 by Martin C. Shepherd.
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
*
* All rights reserved.
*
@@ -46,8 +46,7 @@ typedef struct FreeList FreeList;
* the sizeof() operator to the object type that you intend to allocate from
* the freelist.
*/
-FreeList *_new_FreeList(const char *caller, size_t node_size,
- unsigned blocking_factor);
+FreeList *_new_FreeList(size_t node_size, unsigned blocking_factor);
/*
* If it is known that none of the nodes currently allocated from
@@ -62,14 +61,20 @@ void _rst_FreeList(FreeList *fl);
/*
* Delete a free-list.
*/
-FreeList *_del_FreeList(const char *caller, FreeList *fl, int force);
+FreeList *_del_FreeList(FreeList *fl, int force);
/*
- * Determine the number of nodes that are currently allocated.
+ * Determine the number of nodes that are currently in use.
*/
long _busy_FreeListNodes(FreeList *fl);
/*
+ * Query the number of allocated nodes in the freelist which are
+ * currently unused.
+ */
+long _idle_FreeListNodes(FreeList *fl);
+
+/*
* Allocate a new object from a free-list.
*/
void *_new_FreeListNode(FreeList *fl);
diff --git a/libtecla-1.4.1/getline.c b/libtecla-1.6.1/getline.c
index 242fae3..324aadb 100644
--- a/libtecla-1.4.1/getline.c
+++ b/libtecla-1.6.1/getline.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2001 by Martin C. Shepherd.
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
*
* All rights reserved.
*
@@ -39,12 +39,16 @@
#include <errno.h>
#include <ctype.h>
#include <setjmp.h>
+#include <stdarg.h>
/*
* UNIX headers.
*/
#include <sys/ioctl.h>
#ifdef HAVE_SELECT
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
#include <sys/time.h>
#include <sys/types.h>
#endif
@@ -78,14 +82,7 @@
#if defined(USE_TERMCAP) && defined(HAVE_TERMCAP_H)
#include <termcap.h>
#endif
-/*
- * Unfortunately both terminfo and termcap require one to use the tputs()
- * function to output terminal control characters, and this function
- * doesn't allow one to specify a file stream. As a result, the following
- * file-scope variable is used to pass the current output file stream.
- * This is bad, but there doesn't seem to be any alternative.
- */
-static FILE *tputs_fp = NULL;
+
/*
* Under Solaris default Curses the output function that tputs takes is
* declared to have a char argument. On all other systems and on Solaris
@@ -98,44 +95,92 @@ static FILE *tputs_fp = NULL;
* other systems.
*/
#if defined __sun && defined __SVR4 && !defined _XOPEN_CURSES
-static int gl_tputs_putchar(char c) {return putc(c, tputs_fp);}
+typedef int TputsRetType;
+typedef char TputsArgType; /* int tputs(char c, FILE *fp) */
+#define TPUTS_RETURNS_VALUE 1
#elif defined(__APPLE__) && defined(__MACH__)
-static void gl_tputs_putchar(int c) {(void) putc(c, tputs_fp);}
+typedef void TputsRetType;
+typedef int TputsArgType; /* void tputs(int c, FILE *fp) */
+#define TPUTS_RETURNS_VALUE 0
#else
-static int gl_tputs_putchar(int c) {return putc(c, tputs_fp);}
+typedef int TputsRetType;
+typedef int TputsArgType; /* int tputs(int c, FILE *fp) */
+#define TPUTS_RETURNS_VALUE 1
#endif
+
+/*
+ * Use the above specifications to prototype our tputs callback function.
+ */
+static TputsRetType gl_tputs_putchar(TputsArgType c);
+
+#endif /* defined(USE_TERMINFO) || defined(USE_TERMCAP) */
+
+/*
+ * If the library is being compiled without filesystem access facilities,
+ * ensure that none of the action functions that normally do access the
+ * filesystem are bound by default, and that it they do get bound, that
+ * they don't do anything.
+ */
+#if WITHOUT_FILE_SYSTEM
+#define HIDE_FILE_SYSTEM
#endif
/*
* POSIX headers.
*/
#include <unistd.h>
+#include <fcntl.h>
#include <termios.h>
/*
- * Does the system provide the signal and ioctl query facility used
- * to inform the process of terminal window size changes?
+ * Provide typedefs for standard POSIX structures.
+ */
+typedef struct sigaction SigAction;
+typedef struct termios Termios;
+
+/*
+ * Which flag is used to select non-blocking I/O with fcntl()?
*/
-#if defined(SIGWINCH) && defined(TIOCGWINSZ)
-#define USE_SIGWINCH 1
+#undef NON_BLOCKING_FLAG
+#if defined(O_NONBLOCK)
+#define NON_BLOCKING_FLAG (O_NONBLOCK)
+#elif defined(O_NDELAY)
+#define NON_BLOCKING_FLAG (O_NDELAY)
#endif
/*
- * Provide typedefs for standard POSIX structures.
+ * What value should we give errno if I/O blocks when it shouldn't.
*/
-typedef struct sigaction SigAction;
-typedef struct termios Termios;
+#undef BLOCKED_ERRNO
+#if defined(EAGAIN)
+#define BLOCKED_ERRNO (EAGAIN)
+#elif defined(EWOULDBLOCK)
+#define BLOCKED_ERRNO (EWOULDBLOCK)
+#elif defined(EIO)
+#define BLOCKED_ERRNO (EIO)
+#else
+#define BLOCKED_ERRNO 0
+#endif
/*
* Local headers.
*/
+#ifndef WITHOUT_FILE_SYSTEM
#include "pathutil.h"
+#endif
#include "libtecla.h"
#include "keytab.h"
+#include "getline.h"
+#include "ioutil.h"
#include "history.h"
#include "freelist.h"
#include "stringrp.h"
-#include "getline.h"
+#include "chrqueue.h"
+#include "cplmatch.h"
+#ifndef WITHOUT_FILE_SYSTEM
+#include "expand.h"
+#endif
+#include "errmsg.h"
/*
* Enumerate the available editing styles.
@@ -147,6 +192,11 @@ typedef enum {
} GlEditor;
/*
+ * Set the largest key-sequence that can be handled.
+ */
+#define GL_KEY_MAX 64
+
+/*
* In vi mode, the following datatype is used to implement the
* undo command. It records a copy of the input line from before
* the command-mode action which edited the input line.
@@ -165,7 +215,7 @@ typedef struct {
* needed by the vi-repeat-change command.
*/
typedef struct {
- KtKeyFn *fn; /* The last action function that made a */
+ KtAction action; /* The last action function that made a */
/* change to the line. */
int count; /* The repeat count that was passed to the */
/* above command. */
@@ -175,7 +225,7 @@ typedef struct {
int command_curpos; /* Whenever vi command mode is entered, the */
/* the location of the cursor is recorded */
/* here. */
- char input_char; /* Commands that call gl_read_character() */
+ char input_char; /* Commands that call gl_read_terminal() */
/* record the character here, so that it can */
/* used on repeating the function. */
int saved; /* True if a function has been saved since the */
@@ -231,13 +281,12 @@ struct GlFdNode {
*/
#define GLFD_FREELIST_BLOCKING 10
-/*
- * Listen for and handle file-descriptor events.
- */
-static int gl_event_handler(GetLine *gl);
static int gl_call_fd_handler(GetLine *gl, GlFdHandler *gfh, int fd,
GlFdEvent event);
+
+static int gl_call_timeout_handler(GetLine *gl);
+
#endif
/*
@@ -263,18 +312,61 @@ struct GlSignalNode {
#define GLS_FREELIST_BLOCKING 30
/*
+ * Completion handlers and their callback data are recorded in
+ * nodes of the following type.
+ */
+typedef struct GlCplCallback GlCplCallback;
+struct GlCplCallback {
+ CplMatchFn *fn; /* The completion callback function */
+ void *data; /* Arbitrary callback data */
+};
+
+/*
+ * The following function is used as the default completion handler when
+ * the filesystem is to be hidden. It simply reports no completions.
+ */
+#ifdef HIDE_FILE_SYSTEM
+static CPL_MATCH_FN(gl_no_completions);
+#endif
+
+/*
+ * Specify how many GlCplCallback nodes are added to the GlCplCallback freelist
+ * whenever it becomes exhausted.
+ */
+#define GL_CPL_FREELIST_BLOCKING 10
+
+/*
+ * External action functions and their callback data are recorded in
+ * nodes of the following type.
+ */
+typedef struct GlExternalAction GlExternalAction;
+struct GlExternalAction {
+ GlActionFn *fn; /* The function which implements the action */
+ void *data; /* Arbitrary callback data */
+};
+
+/*
+ * Specify how many GlExternalAction nodes are added to the
+ * GlExternalAction freelist whenever it becomes exhausted.
+ */
+#define GL_EXT_ACT_FREELIST_BLOCKING 10
+
+/*
* Define the contents of the GetLine object.
* Note that the typedef for this object can be found in libtecla.h.
*/
struct GetLine {
+ ErrMsg *err; /* The error-reporting buffer */
GlHistory *glh; /* The line-history buffer */
WordCompletion *cpl; /* String completion resource object */
- CplMatchFn(*cpl_fn); /* The tab completion callback function */
- void *cpl_data; /* Callback data to pass to cpl_fn() */
+ GlCplCallback cplfn; /* The completion callback */
+#ifndef WITHOUT_FILE_SYSTEM
ExpandFile *ef; /* ~user/, $envvar and wildcard expansion */
/* resource object. */
+#endif
StringGroup *capmem; /* Memory for recording terminal capability */
/* strings. */
+ GlCharQueue *cq; /* The terminal output character queue */
int input_fd; /* The file descriptor to read on */
int output_fd; /* The file descriptor to write to */
FILE *input_fp; /* A stream wrapper around input_fd */
@@ -285,33 +377,61 @@ struct GetLine {
char *term; /* The terminal type specified on the last call */
/* to gl_change_terminal(). */
int is_term; /* True if stdin is a terminal */
+ GlWriteFn *flush_fn; /* The function to call to write to the terminal */
+ GlIOMode io_mode; /* The I/O mode established by gl_io_mode() */
+ int raw_mode; /* True while the terminal is in raw mode */
+ GlPendingIO pending_io; /* The type of I/O that is currently pending */
+ GlReturnStatus rtn_status; /* The reason why gl_get_line() returned */
+ int rtn_errno; /* THe value of errno associated with rtn_status */
size_t linelen; /* The max number of characters per line */
char *line; /* A line-input buffer of allocated size */
/* linelen+2. The extra 2 characters are */
/* reserved for "\n\0". */
char *cutbuf; /* A cut-buffer of the same size as line[] */
- const char *prompt; /* The current prompt string */
+ char *prompt; /* The current prompt string */
int prompt_len; /* The length of the prompt string */
int prompt_changed; /* True after a callback changes the prompt */
int prompt_style; /* How the prompt string is displayed */
+ FreeList *cpl_mem; /* Memory for GlCplCallback objects */
+ FreeList *ext_act_mem; /* Memory for GlExternalAction objects */
FreeList *sig_mem; /* Memory for nodes of the signal list */
GlSignalNode *sigs; /* The head of the list of signals */
- sigset_t old_signal_set; /* The signal set on entry to gl_get_line() */
- sigset_t new_signal_set; /* The set of signals that we are trapping */
+ int signals_masked; /* True between calls to gl_mask_signals() and */
+ /* gl_unmask_signals() */
+ int signals_overriden; /* True between calls to gl_override_signals() */
+ /* and gl_restore_signals() */
+ sigset_t all_signal_set; /* The set of all signals that we are trapping */
+ sigset_t old_signal_set; /* The set of blocked signals on entry to */
+ /* gl_get_line(). */
+ sigset_t use_signal_set; /* The subset of all_signal_set to unblock */
+ /* while waiting for key-strokes */
Termios oldattr; /* Saved terminal attributes. */
KeyTab *bindings; /* A table of key-bindings */
int ntotal; /* The number of characters in gl->line[] */
int buff_curpos; /* The cursor position within gl->line[] */
int term_curpos; /* The cursor position on the terminal */
+ int term_len; /* The number of terminal characters used to */
+ /* display the current input line. */
int buff_mark; /* A marker location in the buffer */
int insert_curpos; /* The cursor position at start of insert */
int insert; /* True in insert mode */
int number; /* If >= 0, a numeric argument is being read */
int endline; /* True to tell gl_get_input_line() to return */
/* the current contents of gl->line[] */
- KtKeyFn *current_fn; /* The action function that is currently being */
- /* invoked. */
- int current_count; /* The repeat count passed to current_fn() */
+ int displayed; /* True if an input line is currently displayed */
+ int redisplay; /* If true, the input line will be redrawn */
+ /* either after the current action function */
+ /* returns, or when gl_get_input_line() */
+ /* is next called. */
+ int postpone; /* _gl_normal_io() sets this flag, to */
+ /* postpone any redisplays until */
+ /* is next called, to resume line editing. */
+ char keybuf[GL_KEY_MAX+1]; /* A buffer of currently unprocessed key presses */
+ int nbuf; /* The number of characters in keybuf[] */
+ int nread; /* The number of characters read from keybuf[] */
+ KtAction current_action; /* The action function that is being invoked */
+ int current_count; /* The repeat count passed to */
+ /* current_acction.fn() */
GlhLineID preload_id; /* When not zero, this should be the ID of a */
/* line in the history buffer for potential */
/* recall. */
@@ -319,10 +439,12 @@ struct GetLine {
/* gl_get_input_line() is next called. */
long keyseq_count; /* The number of key sequences entered by the */
/* the user since new_GetLine() was called. */
- long last_search; /* The value of oper_count during the last */
+ long last_search; /* The value of keyseq_count during the last */
/* history search operation. */
GlEditor editor; /* The style of editing, (eg. vi or emacs) */
int silence_bell; /* True if gl_ring_bell() should do nothing. */
+ int automatic_history; /* True to automatically archive entered lines */
+ /* in the history list. */
ViMode vi; /* Parameters used when editing in vi mode */
const char *left; /* The string that moves the cursor 1 character */
/* left. */
@@ -384,6 +506,15 @@ struct GetLine {
fd_set wfds; /* The set of fds to watch for writability */
fd_set ufds; /* The set of fds to watch for urgent data */
int max_fd; /* The maximum file-descriptor being watched */
+ struct { /* Inactivity timeout related data */
+ struct timeval dt; /* The inactivity timeout when timer.fn() */
+ /* isn't 0 */
+ GlTimeoutFn *fn; /* The application callback to call when */
+ /* the inactivity timer expires, or 0 if */
+ /* timeouts are not required. */
+ void *data; /* Application provided data to be passed to */
+ /* timer.fn(). */
+ } timer;
#endif
};
@@ -414,6 +545,23 @@ struct GetLine {
#define GL_DEF_NCOLUMN 80
/*
+ * Enumerate the attributes needed to classify different types of
+ * signals. These attributes reflect the standard default
+ * characteristics of these signals (according to Richard Steven's
+ * Advanced Programming in the UNIX Environment). Note that these values
+ * are all powers of 2, so that they can be combined in a bitwise union.
+ */
+typedef enum {
+ GLSA_TERM=1, /* A signal that terminates processes */
+ GLSA_SUSP=2, /* A signal that suspends processes */
+ GLSA_CONT=4, /* A signal that is sent when suspended processes resume */
+ GLSA_IGN=8, /* A signal that is ignored */
+ GLSA_CORE=16, /* A signal that generates a core dump */
+ GLSA_HARD=32, /* A signal generated by a hardware exception */
+ GLSA_SIZE=64 /* A signal indicating terminal size changes */
+} GlSigAttr;
+
+/*
* List the signals that we need to catch. In general these are
* those that by default terminate or suspend the process, since
* in such cases we need to restore terminal settings.
@@ -422,56 +570,64 @@ static const struct GlDefSignal {
int signo; /* The number of the signal */
unsigned flags; /* A bitwise union of GlSignalFlags enumerators */
GlAfterSignal after; /* What to do after the signal has been delivered */
+ int attr; /* The default attributes of this signal, expressed */
+ /* as a bitwise union of GlSigAttr enumerators */
int errno_value; /* What to set errno to */
} gl_signal_list[] = {
- {SIGABRT, GLS_SUSPEND_INPUT, GLS_ABORT, EINTR},
- {SIGINT, GLS_SUSPEND_INPUT, GLS_ABORT, EINTR},
- {SIGTERM, GLS_SUSPEND_INPUT, GLS_ABORT, EINTR},
- {SIGALRM, GLS_RESTORE_ENV, GLS_CONTINUE, 0},
- {SIGCONT, GLS_RESTORE_ENV, GLS_CONTINUE, 0},
+ {SIGABRT, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM|GLSA_CORE, EINTR},
+ {SIGALRM, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_TERM, 0},
+ {SIGCONT, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_CONT|GLSA_IGN, 0},
#if defined(SIGHUP)
#ifdef ENOTTY
- {SIGHUP, GLS_SUSPEND_INPUT, GLS_ABORT, ENOTTY},
+ {SIGHUP, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM, ENOTTY},
#else
- {SIGHUP, GLS_SUSPEND_INPUT, GLS_ABORT, EINTR},
+ {SIGHUP, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM, EINTR},
#endif
#endif
+ {SIGINT, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM, EINTR},
#if defined(SIGPIPE)
#ifdef EPIPE
- {SIGPIPE, GLS_SUSPEND_INPUT, GLS_ABORT, EPIPE},
+ {SIGPIPE, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM, EPIPE},
#else
- {SIGPIPE, GLS_SUSPEND_INPUT, GLS_ABORT, EINTR},
+ {SIGPIPE, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM, EINTR},
#endif
#endif
+#ifdef SIGPOLL
+ {SIGPOLL, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM, EINTR},
+#endif
#ifdef SIGPWR
- {SIGPWR, GLS_RESTORE_ENV, GLS_CONTINUE, 0},
+ {SIGPWR, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_IGN, 0},
#endif
#ifdef SIGQUIT
- {SIGQUIT, GLS_SUSPEND_INPUT, GLS_ABORT, EINTR},
+ {SIGQUIT, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM|GLSA_CORE, EINTR},
#endif
+ {SIGTERM, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM, EINTR},
#ifdef SIGTSTP
- {SIGTSTP, GLS_SUSPEND_INPUT, GLS_CONTINUE, 0},
+ {SIGTSTP, GLS_SUSPEND_INPUT, GLS_CONTINUE, GLSA_SUSP, 0},
#endif
#ifdef SIGTTIN
- {SIGTTIN, GLS_SUSPEND_INPUT, GLS_CONTINUE, 0},
+ {SIGTTIN, GLS_SUSPEND_INPUT, GLS_CONTINUE, GLSA_SUSP, 0},
#endif
#ifdef SIGTTOU
- {SIGTTOU, GLS_SUSPEND_INPUT, GLS_CONTINUE, 0},
+ {SIGTTOU, GLS_SUSPEND_INPUT, GLS_CONTINUE, GLSA_SUSP, 0},
#endif
#ifdef SIGUSR1
- {SIGUSR1, GLS_RESTORE_ENV, GLS_CONTINUE, 0},
+ {SIGUSR1, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_TERM, 0},
#endif
#ifdef SIGUSR2
- {SIGUSR2, GLS_RESTORE_ENV, GLS_CONTINUE, 0},
+ {SIGUSR2, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_TERM, 0},
#endif
#ifdef SIGVTALRM
- {SIGVTALRM, GLS_RESTORE_ENV, GLS_CONTINUE, 0},
+ {SIGVTALRM, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_TERM, 0},
#endif
#ifdef SIGWINCH
- {SIGWINCH, GLS_RESTORE_ENV, GLS_CONTINUE, 0},
+ {SIGWINCH, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_SIZE|GLSA_IGN, 0},
#endif
#ifdef SIGXCPU
- {SIGXCPU, GLS_RESTORE_ENV, GLS_CONTINUE, 0},
+ {SIGXCPU, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_TERM|GLSA_CORE, 0},
+#endif
+#ifdef SIGXFSZ
+ {SIGXFSZ, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_TERM|GLSA_CORE, 0},
#endif
};
@@ -486,17 +642,33 @@ static void gl_signal_handler(int signo);
static int gl_check_caught_signal(GetLine *gl);
/*
+ * Respond to an externally caught process suspension or
+ * termination signal.
+ */
+static void gl_suspend_process(int signo, GetLine *gl, int ngl);
+
+/* Return the default attributes of a given signal */
+
+static int gl_classify_signal(int signo);
+
+/*
+ * Unfortunately both terminfo and termcap require one to use the tputs()
+ * function to output terminal control characters, and this function
+ * doesn't allow one to specify a file stream. As a result, the following
+ * file-scope variable is used to pass the current output file stream.
+ * This is bad, but there doesn't seem to be any alternative.
+ */
+static GetLine *tputs_gl = NULL;
+
+/*
* Define a tab to be a string of 8 spaces.
*/
#define TAB_WIDTH 8
/*
- * Does the system send us SIGWINCH signals when the terminal size
- * changes?
+ * Lookup the current size of the terminal.
*/
-#ifdef USE_SIGWINCH
-static int gl_resize_terminal(GetLine *gl, int redisplay);
-#endif
+static void gl_query_size(GetLine *gl, int *ncolumn, int *nline);
/*
* Getline calls this to temporarily override certain signal handlers
@@ -511,6 +683,28 @@ static int gl_override_signal_handlers(GetLine *gl);
static int gl_restore_signal_handlers(GetLine *gl);
/*
+ * Temporarily block the delivery of all signals that gl_get_line()
+ * is currently configured to trap.
+ */
+static int gl_mask_signals(GetLine *gl, sigset_t *oldset);
+
+/*
+ * Restore the process signal mask that was overriden by a previous
+ * call to gl_mask_signals().
+ */
+static int gl_unmask_signals(GetLine *gl, sigset_t *oldset);
+
+/*
+ * Unblock the signals that gl_get_line() has been configured to catch.
+ */
+static int gl_catch_signals(GetLine *gl);
+
+/*
+ * Return the set of all trappable signals.
+ */
+static void gl_list_trappable_signals(sigset_t *signals);
+
+/*
* Put the terminal into raw input mode, after saving the original
* terminal attributes in gl->oldattr.
*/
@@ -522,15 +716,46 @@ static int gl_raw_terminal_mode(GetLine *gl);
static int gl_restore_terminal_attributes(GetLine *gl);
/*
+ * Switch to non-blocking I/O if possible.
+ */
+static int gl_nonblocking_io(GetLine *gl, int fd);
+
+/*
+ * Switch to blocking I/O if possible.
+ */
+static int gl_blocking_io(GetLine *gl, int fd);
+
+/*
* Read a line from the user in raw mode.
*/
-static int gl_get_input_line(GetLine *gl, const char *start_line,
- int start_pos);
+static int gl_get_input_line(GetLine *gl, const char *prompt,
+ const char *start_line, int start_pos);
/*
- * Set the largest key-sequence that can be handled.
+ * Query the user for a single character.
*/
-#define GL_KEY_MAX 64
+static int gl_get_query_char(GetLine *gl, const char *prompt, int defchar);
+
+/*
+ * Read input from a non-interactive input stream.
+ */
+static int gl_read_stream_line(GetLine *gl);
+
+/*
+ * Read a single character from a non-interactive input stream.
+ */
+static int gl_read_stream_char(GetLine *gl);
+
+/*
+ * Prepare to edit a new line.
+ */
+static int gl_present_line(GetLine *gl, const char *prompt,
+ const char *start_line, int start_pos);
+
+/*
+ * Reset all line-editing parameters for a new input line.
+ */
+static void gl_reset_editor(GetLine *gl);
/*
* Handle the receipt of the potential start of a new key-sequence from
@@ -567,21 +792,35 @@ static const char *gl_tgetstr(GetLine *gl, const char *name, char **bufptr);
/*
* Output a binary string directly to the terminal.
*/
-static int gl_output_raw_string(GetLine *gl, const char *string);
+static int gl_print_raw_string(GetLine *gl, int buffered,
+ const char *string, int n);
+
+/*
+ * Print an informational message, starting and finishing on new lines.
+ * After the list of strings to be printed, the last argument MUST be
+ * GL_END_INFO.
+ */
+static int gl_print_info(GetLine *gl, ...);
+#define GL_END_INFO ((const char *)0)
+
+/*
+ * Start a newline and place the cursor at its start.
+ */
+static int gl_start_newline(GetLine *gl, int buffered);
/*
* Output a terminal control sequence.
*/
-static int gl_output_control_sequence(GetLine *gl, int nline,
- const char *string);
+static int gl_print_control_sequence(GetLine *gl, int nline,
+ const char *string);
/*
* Output a character or string to the terminal after converting tabs
* to spaces and control characters to a caret followed by the modified
* character.
*/
-static int gl_output_char(GetLine *gl, char c, char pad);
-static int gl_output_string(GetLine *gl, const char *string, char pad);
+static int gl_print_char(GetLine *gl, char c, char pad);
+static int gl_print_string(GetLine *gl, const char *string, char pad);
/*
* Delete nc characters starting from the one under the cursor.
@@ -602,10 +841,52 @@ static int gl_add_char_to_line(GetLine *gl, char c);
static int gl_add_string_to_line(GetLine *gl, const char *s);
/*
+ * Record a new character in the input-line buffer.
+ */
+static int gl_buffer_char(GetLine *gl, char c, int bufpos);
+
+/*
+ * Record a string in the input-line buffer.
+ */
+static int gl_buffer_string(GetLine *gl, const char *s, int n, int bufpos);
+
+/*
+ * Make way to insert a string in the input-line buffer.
+ */
+static int gl_make_gap_in_buffer(GetLine *gl, int start, int n);
+
+/*
+ * Remove characters from the input-line buffer, and move any characters
+ * that followed them to the start of the vacated space.
+ */
+static void gl_remove_from_buffer(GetLine *gl, int start, int n);
+
+/*
+ * Terminate the input-line buffer after a specified number of characters.
+ */
+static int gl_truncate_buffer(GetLine *gl, int n);
+
+/*
+ * Delete the displayed part of the input line that follows the current
+ * terminal cursor position.
+ */
+static int gl_truncate_display(GetLine *gl);
+
+/*
+ * Accomodate changes to the contents of the input line buffer
+ * that weren't made by the above gl_*buffer functions.
+ */
+static void gl_update_buffer(GetLine *gl);
+
+/*
* Read a single character from the terminal.
*/
-static int gl_read_character(GetLine *gl, char *c);
+static int gl_read_terminal(GetLine *gl, int keep, char *c);
+/*
+ * Discard processed characters from the key-press lookahead buffer.
+ */
+static void gl_discard_chars(GetLine *gl, int nused);
/*
* Move the terminal cursor n positions to the left or right.
@@ -624,10 +905,15 @@ static int gl_set_term_curpos(GetLine *gl, int term_curpos);
static int gl_place_cursor(GetLine *gl, int buff_curpos);
/*
- * Return the terminal cursor position that corresponds to a given
- * line buffer cursor position.
+ * How many characters are needed to write a number as an octal string?
+ */
+static int gl_octal_width(unsigned num);
+
+/*
+ * Return the number of spaces needed to display a tab character at
+ * a given location of the terminal.
*/
-static int gl_buff_curpos_to_term_curpos(GetLine *gl, int buff_curpos);
+static int gl_displayed_tab_width(GetLine *gl, int term_curpos);
/*
* Return the number of terminal characters needed to display a
@@ -641,6 +927,7 @@ static int gl_displayed_char_width(GetLine *gl, char c, int term_curpos);
*/
static int gl_displayed_string_width(GetLine *gl, const char *string, int nc,
int term_curpos);
+
/*
* Return non-zero if 'c' is to be considered part of a word.
*/
@@ -671,6 +958,8 @@ static GLC_GETC_FN(glc_buff_getc); /* Read from a string */
*/
static int _gl_parse_config_line(GetLine *gl, void *stream, GlcGetcFn *getc_fn,
const char *origin, KtBinder who, int *lineno);
+static int gl_report_config_error(GetLine *gl, const char *origin, int lineno,
+ const char *errmsg);
/*
* Bind the actual arrow key bindings to match those of the symbolic
@@ -682,7 +971,7 @@ static int _gl_bind_arrow_keys(GetLine *gl);
* Copy the binding of the specified symbolic arrow-key binding to
* the terminal specific, and default arrow-key key-sequences.
*/
-static int _gl_rebind_arrow_key(KeyTab *bindings, const char *name,
+static int _gl_rebind_arrow_key(GetLine *gl, const char *name,
const char *term_seq,
const char *def_seq1,
const char *def_seq2);
@@ -701,6 +990,42 @@ static void gl_revert_input(GetLine *gl);
static int gl_flush_output(GetLine *gl);
/*
+ * The callback through which all terminal output is routed.
+ * This simply appends characters to a queue buffer, which is
+ * subsequently flushed to the output channel by gl_flush_output().
+ */
+static GL_WRITE_FN(gl_write_fn);
+
+/*
+ * The callback function which the output character queue object
+ * calls to transfer characters to the output channel.
+ */
+static GL_WRITE_FN(gl_flush_terminal);
+
+/*
+ * Enumerate the possible return statuses of gl_read_input().
+ */
+typedef enum {
+ GL_READ_OK, /* A character was read successfully */
+ GL_READ_ERROR, /* A read-error occurred */
+ GL_READ_BLOCKED, /* The read would have blocked the caller */
+ GL_READ_EOF /* The end of the current input file was reached */
+} GlReadStatus;
+
+static GlReadStatus gl_read_input(GetLine *gl, char *c);
+/*
+ * Private functions of gl_read_input().
+ */
+static int gl_event_handler(GetLine *gl, int fd);
+static GlReadStatus gl_read_unmasked(GetLine *gl, int fd, char *c);
+
+
+/*
+ * A private function of gl_tty_signals().
+ */
+static int gl_set_tty_signal(int signo, void (*handler)(int));
+
+/*
* Change the editor style being emulated.
*/
static int gl_change_editor(GetLine *gl, GlEditor editor);
@@ -790,9 +1115,89 @@ static int gl_display_prompt(GetLine *gl);
static int gl_displayed_prompt_width(GetLine *gl);
/*
- * Prepare the return the current input line to the caller of gl_get_line().
+ * Prepare to return the current input line to the caller of gl_get_line().
*/
-static int gl_line_ended(GetLine *gl, int newline_char, int archive);
+static int gl_line_ended(GetLine *gl, int newline_char);
+
+/*
+ * Arrange for the input line to be redisplayed when the current contents
+ * of the output queue have been flushed.
+ */
+static void gl_queue_redisplay(GetLine *gl);
+
+/*
+ * Erase the displayed representation of the input line, without
+ * touching the buffered copy.
+ */
+static int gl_erase_line(GetLine *gl);
+
+/*
+ * This function is called whenever the input line has been erased.
+ */
+static void gl_line_erased(GetLine *gl);
+
+/*
+ * Arrange for the current input line to be discarded.
+ */
+void _gl_abandon_line(GetLine *gl);
+
+/*
+ * The following are private internally callable versions of pertinent
+ * public functions. Unlike their public wrapper functions, they don't
+ * block signals while running, and assume that their arguments are valid.
+ * They are designed to be called from places where signals are already
+ * blocked, and where simple sanity checks have already been applied to
+ * their arguments.
+ */
+static char *_gl_get_line(GetLine *gl, const char *prompt,
+ const char *start_line, int start_pos);
+static int _gl_query_char(GetLine *gl, const char *prompt, char defchar);
+static int _gl_read_char(GetLine *gl);
+static int _gl_update_size(GetLine *gl);
+/*
+ * Redraw the current input line to account for a change in the terminal
+ * size. Also install the new size in gl.
+ */
+static int gl_handle_tty_resize(GetLine *gl, int ncolumn, int nline);
+
+static int _gl_change_terminal(GetLine *gl, FILE *input_fp, FILE *output_fp,
+ const char *term);
+static int _gl_configure_getline(GetLine *gl, const char *app_string,
+ const char *app_file, const char *user_file);
+static int _gl_save_history(GetLine *gl, const char *filename,
+ const char *comment, int max_lines);
+static int _gl_load_history(GetLine *gl, const char *filename,
+ const char *comment);
+static int _gl_watch_fd(GetLine *gl, int fd, GlFdEvent event,
+ GlFdEventFn *callback, void *data);
+static void _gl_terminal_size(GetLine *gl, int def_ncolumn, int def_nline,
+ GlTerminalSize *size);
+static void _gl_replace_prompt(GetLine *gl, const char *prompt);
+static int _gl_trap_signal(GetLine *gl, int signo, unsigned flags,
+ GlAfterSignal after, int errno_value);
+static int _gl_raw_io(GetLine *gl, int redisplay);
+static int _gl_normal_io(GetLine *gl);
+static int _gl_completion_action(GetLine *gl, void *data, CplMatchFn *match_fn,
+ int list_only, const char *name,
+ const char *keyseq);
+static int _gl_register_action(GetLine *gl, void *data, GlActionFn *fn,
+ const char *name, const char *keyseq);
+static int _gl_io_mode(GetLine *gl, GlIOMode mode);
+static int _gl_set_term_size(GetLine *gl, int ncolumn, int nline);
+static int _gl_append_history(GetLine *gl, const char *line);
+
+/*
+ * Reset the completion status and associated errno value in
+ * gl->rtn_status and gl->rtn_errno.
+ */
+static void gl_clear_status(GetLine *gl);
+
+/*
+ * Record a completion status, unless a previous abnormal completion
+ * status has already been recorded for the current call.
+ */
+static void gl_record_status(GetLine *gl, GlReturnStatus rtn_status,
+ int rtn_errno);
/*
* Set the maximum length of a line in a user's tecla configuration
@@ -854,10 +1259,14 @@ static KT_KEY_FN(gl_history_re_search_backward);
static KT_KEY_FN(gl_history_search_forward);
static KT_KEY_FN(gl_history_re_search_forward);
static KT_KEY_FN(gl_complete_word);
+#ifndef HIDE_FILE_SYSTEM
static KT_KEY_FN(gl_expand_filename);
+static KT_KEY_FN(gl_read_from_file);
+static KT_KEY_FN(gl_read_init_files);
+static KT_KEY_FN(gl_list_glob);
+#endif
static KT_KEY_FN(gl_del_char_or_list_or_eof);
static KT_KEY_FN(gl_list_or_eof);
-static KT_KEY_FN(gl_read_from_file);
static KT_KEY_FN(gl_beginning_of_history);
static KT_KEY_FN(gl_end_of_history);
static KT_KEY_FN(gl_digit_argument);
@@ -869,7 +1278,6 @@ static KT_KEY_FN(gl_change_case);
static KT_KEY_FN(gl_vi_insert_at_bol);
static KT_KEY_FN(gl_vi_append_at_eol);
static KT_KEY_FN(gl_vi_append);
-static KT_KEY_FN(gl_list_glob);
static KT_KEY_FN(gl_backward_kill_line);
static KT_KEY_FN(gl_goto_column);
static KT_KEY_FN(gl_forward_to_word);
@@ -917,8 +1325,9 @@ static KT_KEY_FN(gl_vi_editing_mode);
static KT_KEY_FN(gl_ring_bell);
static KT_KEY_FN(gl_vi_repeat_change);
static KT_KEY_FN(gl_find_parenthesis);
-static KT_KEY_FN(gl_read_init_files);
static KT_KEY_FN(gl_list_history);
+static KT_KEY_FN(gl_list_completions);
+static KT_KEY_FN(gl_run_external_action);
/*
* Name the available action functions.
@@ -969,9 +1378,13 @@ static const struct {const char *name; KT_KEY_FN(*fn);} gl_actions[] = {
{"history-search-forward", gl_history_search_forward},
{"history-re-search-forward", gl_history_re_search_forward},
{"complete-word", gl_complete_word},
+#ifndef HIDE_FILE_SYSTEM
{"expand-filename", gl_expand_filename},
- {"del-char-or-list-or-eof", gl_del_char_or_list_or_eof},
{"read-from-file", gl_read_from_file},
+ {"read-init-files", gl_read_init_files},
+ {"list-glob", gl_list_glob},
+#endif
+ {"del-char-or-list-or-eof", gl_del_char_or_list_or_eof},
{"beginning-of-history", gl_beginning_of_history},
{"end-of-history", gl_end_of_history},
{"digit-argument", gl_digit_argument},
@@ -983,7 +1396,6 @@ static const struct {const char *name; KT_KEY_FN(*fn);} gl_actions[] = {
{"vi-append-at-eol", gl_vi_append_at_eol},
{"vi-append", gl_vi_append},
{"change-case", gl_change_case},
- {"list-glob", gl_list_glob},
{"backward-kill-line", gl_backward_kill_line},
{"goto-column", gl_goto_column},
{"forward-to-word", gl_forward_to_word},
@@ -1032,7 +1444,6 @@ static const struct {const char *name; KT_KEY_FN(*fn);} gl_actions[] = {
{"ring-bell", gl_ring_bell},
{"vi-repeat-change", gl_vi_repeat_change},
{"find-parenthesis", gl_find_parenthesis},
- {"read-init-files", gl_read_init_files},
{"list-history", gl_list_history},
};
@@ -1085,11 +1496,13 @@ static const KtKeyBinding gl_emacs_bindings[] = {
{"M-n", "history-search-forward"},
{"M-N", "history-search-forward"},
{"\t", "complete-word"},
+#ifndef HIDE_FILE_SYSTEM
{"^X*", "expand-filename"},
{"^X^F", "read-from-file"},
{"^X^R", "read-init-files"},
{"^Xg", "list-glob"},
{"^XG", "list-glob"},
+#endif
{"^Xh", "list-history"},
{"^XH", "list-history"},
{"M-<", "beginning-of-history"},
@@ -1118,7 +1531,9 @@ static const KtKeyBinding gl_emacs_bindings[] = {
*/
static const KtKeyBinding gl_vi_bindings[] = {
{"^D", "list-or-eof"},
+#ifndef HIDE_FILE_SYSTEM
{"^G", "list-glob"},
+#endif
{"^H", "backward-delete-char"},
{"\t", "complete-word"},
{"\r", "newline"},
@@ -1129,13 +1544,17 @@ static const KtKeyBinding gl_vi_bindings[] = {
{"^R", "redisplay"},
{"^U", "backward-kill-line"},
{"^W", "backward-delete-word"},
+#ifndef HIDE_FILE_SYSTEM
{"^X^F", "read-from-file"},
{"^X^R", "read-init-files"},
{"^X*", "expand-filename"},
+#endif
{"^?", "backward-delete-char"},
{"M- ", "cursor-right"},
{"M-$", "end-of-line"},
+#ifndef HIDE_FILE_SYSTEM
{"M-*", "expand-filename"},
+#endif
{"M-+", "down-history"},
{"M--", "up-history"},
{"M-<", "beginning-of-history"},
@@ -1274,7 +1693,9 @@ static const KtKeyBinding gl_vi_bindings[] = {
{"M-\r", "newline"},
{"M-\t", "complete-word"},
{"M-\n", "newline"},
+#ifndef HIDE_FILE_SYSTEM
{"M-^X^R", "read-init-files"},
+#endif
{"M-^Xh", "list-history"},
{"M-^XH", "list-history"},
{"down", "down-history"},
@@ -1301,7 +1722,7 @@ GetLine *new_GetLine(size_t linelen, size_t histlen)
* Check the arguments.
*/
if(linelen < 10) {
- fprintf(stderr, "new_GetLine: Line length too small.\n");
+ errno = ENOMEM;
return NULL;
};
/*
@@ -1309,7 +1730,7 @@ GetLine *new_GetLine(size_t linelen, size_t histlen)
*/
gl = (GetLine *) malloc(sizeof(GetLine));
if(!gl) {
- fprintf(stderr, "new_GetLine: Insufficient memory.\n");
+ errno = ENOMEM;
return NULL;
};
/*
@@ -1317,52 +1738,66 @@ GetLine *new_GetLine(size_t linelen, size_t histlen)
* container at least up to the point at which it can safely be passed
* to del_GetLine().
*/
+ gl->err = NULL;
gl->glh = NULL;
gl->cpl = NULL;
- gl->cpl_fn = cpl_file_completions;
- gl->cpl_data = NULL;
+#ifndef HIDE_FILE_SYSTEM
+ gl->cplfn.fn = cpl_file_completions;
+#else
+ gl->cplfn.fn = gl_no_completions;
+#endif
+ gl->cplfn.data = NULL;
+#ifndef WITHOUT_FILE_SYSTEM
gl->ef = NULL;
+#endif
gl->capmem = NULL;
- gl->term = NULL;
- gl->is_term = 0;
+ gl->cq = NULL;
gl->input_fd = -1;
gl->output_fd = -1;
gl->input_fp = NULL;
gl->output_fp = NULL;
gl->file_fp = NULL;
+ gl->term = NULL;
+ gl->is_term = 0;
+ gl->flush_fn = gl_flush_terminal;
+ gl->io_mode = GL_NORMAL_MODE;
+ gl->raw_mode = 0;
+ gl->pending_io = GLP_WRITE; /* We will start by writing the prompt */
+ gl_clear_status(gl);
gl->linelen = linelen;
gl->line = NULL;
gl->cutbuf = NULL;
- gl->linelen = linelen;
- gl->prompt = "";
+ gl->prompt = NULL;
gl->prompt_len = 0;
gl->prompt_changed = 0;
gl->prompt_style = GL_LITERAL_PROMPT;
- gl->vi.undo.line = NULL;
- gl->vi.undo.buff_curpos = 0;
- gl->vi.undo.ntotal = 0;
- gl->vi.undo.saved = 0;
- gl->vi.repeat.fn = 0;
- gl->vi.repeat.count = 0;
- gl->vi.repeat.input_curpos = 0;
- gl->vi.repeat.command_curpos = 0;
- gl->vi.repeat.input_char = '\0';
- gl->vi.repeat.saved = 0;
- gl->vi.repeat.active = 0;
+ gl->cpl_mem = NULL;
+ gl->ext_act_mem = NULL;
gl->sig_mem = NULL;
gl->sigs = NULL;
+ gl->signals_masked = 0;
+ gl->signals_overriden = 0;
+ sigemptyset(&gl->all_signal_set);
sigemptyset(&gl->old_signal_set);
- sigemptyset(&gl->new_signal_set);
+ sigemptyset(&gl->use_signal_set);
gl->bindings = NULL;
gl->ntotal = 0;
gl->buff_curpos = 0;
gl->term_curpos = 0;
+ gl->term_len = 0;
gl->buff_mark = 0;
gl->insert_curpos = 0;
gl->insert = 1;
gl->number = -1;
- gl->endline = 0;
- gl->current_fn = 0;
+ gl->endline = 1;
+ gl->displayed = 0;
+ gl->redisplay = 0;
+ gl->postpone = 0;
+ gl->keybuf[0]='\0';
+ gl->nbuf = 0;
+ gl->nread = 0;
+ gl->current_action.fn = 0;
+ gl->current_action.data = NULL;
gl->current_count = 0;
gl->preload_id = 0;
gl->preload_history = 0;
@@ -1370,6 +1805,19 @@ GetLine *new_GetLine(size_t linelen, size_t histlen)
gl->last_search = -1;
gl->editor = GL_EMACS_MODE;
gl->silence_bell = 0;
+ gl->automatic_history = 1;
+ gl->vi.undo.line = NULL;
+ gl->vi.undo.buff_curpos = 0;
+ gl->vi.undo.ntotal = 0;
+ gl->vi.undo.saved = 0;
+ gl->vi.repeat.action.fn = 0;
+ gl->vi.repeat.action.data = 0;
+ gl->vi.repeat.count = 0;
+ gl->vi.repeat.input_curpos = 0;
+ gl->vi.repeat.command_curpos = 0;
+ gl->vi.repeat.input_char = '\0';
+ gl->vi.repeat.saved = 0;
+ gl->vi.repeat.active = 0;
gl->vi.command = 0;
gl->vi.find_forward = 0;
gl->vi.find_onto = 0;
@@ -1415,8 +1863,18 @@ GetLine *new_GetLine(size_t linelen, size_t histlen)
FD_ZERO(&gl->wfds);
FD_ZERO(&gl->ufds);
gl->max_fd = 0;
+ gl->timer.dt.tv_sec = 0;
+ gl->timer.dt.tv_usec = 0;
+ gl->timer.fn = 0;
+ gl->timer.data = NULL;
#endif
/*
+ * Allocate an error reporting buffer.
+ */
+ gl->err = _new_ErrMsg();
+ if(!gl->err)
+ return del_GetLine(gl);
+/*
* Allocate the history buffer.
*/
gl->glh = _new_GlHistory(histlen);
@@ -1431,9 +1889,11 @@ GetLine *new_GetLine(size_t linelen, size_t histlen)
/*
* Allocate the resource object for file-completion.
*/
+#ifndef WITHOUT_FILE_SYSTEM
gl->ef = new_ExpandFile();
if(!gl->ef)
return del_GetLine(gl);
+#endif
/*
* Allocate a string-segment memory allocator for use in storing terminal
* capablity strings.
@@ -1442,51 +1902,79 @@ GetLine *new_GetLine(size_t linelen, size_t histlen)
if(!gl->capmem)
return del_GetLine(gl);
/*
+ * Allocate the character queue that is used to buffer terminal output.
+ */
+ gl->cq = _new_GlCharQueue();
+ if(!gl->cq)
+ return del_GetLine(gl);
+/*
* Allocate a line buffer, leaving 2 extra characters for the terminating
* '\n' and '\0' characters
*/
gl->line = (char *) malloc(linelen + 2);
if(!gl->line) {
- fprintf(stderr,
- "new_GetLine: Insufficient memory to allocate line buffer.\n");
+ errno = ENOMEM;
return del_GetLine(gl);
};
- gl->line[0] = '\0';
+/*
+ * Start with an empty input line.
+ */
+ gl_truncate_buffer(gl, 0);
/*
* Allocate a cut buffer.
*/
gl->cutbuf = (char *) malloc(linelen + 2);
if(!gl->cutbuf) {
- fprintf(stderr,
- "new_GetLine: Insufficient memory to allocate cut buffer.\n");
+ errno = ENOMEM;
return del_GetLine(gl);
};
gl->cutbuf[0] = '\0';
/*
+ * Allocate an initial empty prompt.
+ */
+ _gl_replace_prompt(gl, NULL);
+ if(!gl->prompt) {
+ errno = ENOMEM;
+ return del_GetLine(gl);
+ };
+/*
* Allocate a vi undo buffer.
*/
gl->vi.undo.line = (char *) malloc(linelen + 2);
if(!gl->vi.undo.line) {
- fprintf(stderr,
- "new_GetLine: Insufficient memory to allocate undo buffer.\n");
+ errno = ENOMEM;
return del_GetLine(gl);
};
gl->vi.undo.line[0] = '\0';
/*
* Allocate a freelist from which to allocate nodes for the list
+ * of completion functions.
+ */
+ gl->cpl_mem = _new_FreeList(sizeof(GlCplCallback), GL_CPL_FREELIST_BLOCKING);
+ if(!gl->cpl_mem)
+ return del_GetLine(gl);
+/*
+ * Allocate a freelist from which to allocate nodes for the list
+ * of external action functions.
+ */
+ gl->ext_act_mem = _new_FreeList(sizeof(GlExternalAction),
+ GL_EXT_ACT_FREELIST_BLOCKING);
+ if(!gl->ext_act_mem)
+ return del_GetLine(gl);
+/*
+ * Allocate a freelist from which to allocate nodes for the list
* of signals.
*/
- gl->sig_mem = _new_FreeList("new_GetLine", sizeof(GlSignalNode),
- GLS_FREELIST_BLOCKING);
+ gl->sig_mem = _new_FreeList(sizeof(GlSignalNode), GLS_FREELIST_BLOCKING);
if(!gl->sig_mem)
return del_GetLine(gl);
/*
- * Install dispositions for the default list of signals that gl_get_line()
- * traps.
+ * Install initial dispositions for the default list of signals that
+ * gl_get_line() traps.
*/
for(i=0; i<sizeof(gl_signal_list)/sizeof(gl_signal_list[0]); i++) {
const struct GlDefSignal *sig = gl_signal_list + i;
- if(gl_trap_signal(gl, sig->signo, sig->flags, sig->after,
+ if(_gl_trap_signal(gl, sig->signo, sig->flags, sig->after,
sig->errno_value))
return del_GetLine(gl);
};
@@ -1500,7 +1988,7 @@ GetLine *new_GetLine(size_t linelen, size_t histlen)
* Define the available actions that can be bound to key sequences.
*/
for(i=0; i<sizeof(gl_actions)/sizeof(gl_actions[0]); i++) {
- if(_kt_set_action(gl->bindings, gl_actions[i].name, gl_actions[i].fn))
+ if(_kt_set_action(gl->bindings, gl_actions[i].name, gl_actions[i].fn, NULL))
return del_GetLine(gl);
};
/*
@@ -1515,21 +2003,20 @@ GetLine *new_GetLine(size_t linelen, size_t histlen)
gl->tgetent_buf = (char *) malloc(TERMCAP_BUF_SIZE);
gl->tgetstr_buf = (char *) malloc(TERMCAP_BUF_SIZE);
if(!gl->tgetent_buf || !gl->tgetstr_buf) {
- fprintf(stderr, "new_GetLine: Insufficient memory for termcap buffers.\n");
+ errno = ENOMEM;
return del_GetLine(gl);
};
#endif
/*
* Set up for I/O assuming stdin and stdout.
*/
- if(gl_change_terminal(gl, stdin, stdout, getenv("TERM")))
+ if(_gl_change_terminal(gl, stdin, stdout, getenv("TERM")))
return del_GetLine(gl);
/*
* Create a freelist for use in allocating GlFdNode list nodes.
*/
#ifdef HAVE_SELECT
- gl->fd_node_mem = _new_FreeList("new_GetLine", sizeof(GlFdNode),
- GLFD_FREELIST_BLOCKING);
+ gl->fd_node_mem = _new_FreeList(sizeof(GlFdNode), GLFD_FREELIST_BLOCKING);
if(!gl->fd_node_mem)
return del_GetLine(gl);
#endif
@@ -1550,32 +2037,55 @@ GetLine *new_GetLine(size_t linelen, size_t histlen)
GetLine *del_GetLine(GetLine *gl)
{
if(gl) {
+/*
+ * If the terminal is in raw server mode, reset it.
+ */
+ _gl_normal_io(gl);
+/*
+ * Deallocate all objects contained by gl.
+ */
+ gl->err = _del_ErrMsg(gl->err);
gl->glh = _del_GlHistory(gl->glh);
gl->cpl = del_WordCompletion(gl->cpl);
+#ifndef WITHOUT_FILE_SYSTEM
gl->ef = del_ExpandFile(gl->ef);
+#endif
gl->capmem = _del_StringGroup(gl->capmem);
+ gl->cq = _del_GlCharQueue(gl->cq);
+ if(gl->file_fp)
+ fclose(gl->file_fp);
+ if(gl->term)
+ free(gl->term);
if(gl->line)
free(gl->line);
if(gl->cutbuf)
free(gl->cutbuf);
- if(gl->vi.undo.line)
- free(gl->vi.undo.line);
- gl->sig_mem = _del_FreeList(NULL, gl->sig_mem, 1);
+ if(gl->prompt)
+ free(gl->prompt);
+ gl->cpl_mem = _del_FreeList(gl->cpl_mem, 1);
+ gl->ext_act_mem = _del_FreeList(gl->ext_act_mem, 1);
+ gl->sig_mem = _del_FreeList(gl->sig_mem, 1);
gl->sigs = NULL; /* Already freed by freeing sig_mem */
gl->bindings = _del_KeyTab(gl->bindings);
+ if(gl->vi.undo.line)
+ free(gl->vi.undo.line);
#ifdef USE_TERMCAP
if(gl->tgetent_buf)
free(gl->tgetent_buf);
if(gl->tgetstr_buf)
free(gl->tgetstr_buf);
#endif
- if(gl->file_fp)
- fclose(gl->file_fp);
- if(gl->term)
- free(gl->term);
+ if(gl->app_file)
+ free(gl->app_file);
+ if(gl->user_file)
+ free(gl->user_file);
#ifdef HAVE_SELECT
- gl->fd_node_mem = _del_FreeList(NULL, gl->fd_node_mem, 1);
+ gl->fd_node_mem = _del_FreeList(gl->fd_node_mem, 1);
+ gl->fd_nodes = NULL; /* Already freed by freeing gl->fd_node_mem */
#endif
+/*
+ * Delete the now empty container.
+ */
free(gl);
};
return NULL;
@@ -1617,7 +2127,11 @@ static int gl_bind_control_char(GetLine *gl, KtBinder binder, char c,
/*
* Install the binding.
*/
- return _kt_set_keybinding(gl->bindings, binder, keyseq, action);
+ if(_kt_set_keybinding(gl->bindings, binder, keyseq, action)) {
+ _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG);
+ return 1;
+ };
+ return 0;
}
/*.......................................................................
@@ -1645,41 +2159,211 @@ static int gl_bind_control_char(GetLine *gl, KtBinder binder, char c,
char *gl_get_line(GetLine *gl, const char *prompt,
const char *start_line, int start_pos)
{
- int waserr = 0; /* True if an error occurs */
+ char *retval; /* The return value of _gl_get_line() */
/*
* Check the arguments.
*/
- if(!gl || !prompt) {
- fprintf(stderr, "gl_get_line: NULL argument(s).\n");
+ if(!gl) {
+ errno = EINVAL;
return NULL;
};
/*
+ * Temporarily block all of the signals that we have been asked to trap.
+ */
+ if(gl_mask_signals(gl, &gl->old_signal_set))
+ return NULL;
+/*
+ * Perform the command-line editing task.
+ */
+ retval = _gl_get_line(gl, prompt, start_line, start_pos);
+/*
+ * Restore the process signal mask to how it was when this function was
+ * first called.
+ */
+ gl_unmask_signals(gl, &gl->old_signal_set);
+ return retval;
+}
+
+
+/*.......................................................................
+ * This is the main body of the public function gl_get_line().
+ */
+static char *_gl_get_line(GetLine *gl, const char *prompt,
+ const char *start_line, int start_pos)
+{
+ int waserr = 0; /* True if an error occurs */
+/*
+ * Assume that this call will successfully complete the input
+ * line until proven otherwise.
+ */
+ gl_clear_status(gl);
+/*
* If this is the first call to this function since new_GetLine(),
* complete any postponed configuration.
*/
if(!gl->configured) {
- (void) gl_configure_getline(gl, NULL, NULL, TECLA_CONFIG_FILE);
+ (void) _gl_configure_getline(gl, NULL, NULL, TECLA_CONFIG_FILE);
gl->configured = 1;
};
/*
- * If input is temporarily being taken from a file, return lines
- * from the file until the file is exhausted, then revert to
- * the normal input stream.
+ * Before installing our signal handler functions, record the fact
+ * that there are no pending signals.
*/
- if(gl->file_fp) {
- if(fgets(gl->line, gl->linelen, gl->file_fp))
- return gl->line;
- gl_revert_input(gl);
+ gl_pending_signal = -1;
+/*
+ * Temporarily override the signal handlers of the calling program,
+ * so that we can intercept signals that would leave the terminal
+ * in a bad state.
+ */
+ waserr = gl_override_signal_handlers(gl);
+/*
+ * After recording the current terminal settings, switch the terminal
+ * into raw input mode.
+ */
+ waserr = waserr || _gl_raw_io(gl, 1);
+/*
+ * Attempt to read the line. This will require more than one attempt if
+ * either a current temporary input file is opened by gl_get_input_line()
+ * or the end of a temporary input file is reached by gl_read_stream_line().
+ */
+ while(!waserr) {
+/*
+ * Read a line from a non-interactive stream?
+ */
+ if(gl->file_fp || !gl->is_term) {
+ if(gl_read_stream_line(gl)==0) {
+ break;
+ } else if(gl->file_fp) {
+ gl_revert_input(gl);
+ gl_record_status(gl, GLR_NEWLINE, 0);
+ } else {
+ waserr = 1;
+ break;
+ };
+ };
+/*
+ * Read from the terminal? Note that the above if() block may have
+ * changed gl->file_fp, so it is necessary to retest it here, rather
+ * than using an else statement.
+ */
+ if(!gl->file_fp && gl->is_term) {
+ if(gl_get_input_line(gl, prompt, start_line, start_pos))
+ waserr = 1;
+ else
+ break;
+ };
};
/*
- * Is input coming from a non-interactive source?
+ * If an error occurred, but gl->rtn_status is still set to
+ * GLR_NEWLINE, change the status to GLR_ERROR. Otherwise
+ * leave it at whatever specific value was assigned by the function
+ * that aborted input. This means that only functions that trap
+ * non-generic errors have to remember to update gl->rtn_status
+ * themselves.
*/
- if(!gl->is_term)
- return fgets(gl->line, gl->linelen, gl->input_fp);
+ if(waserr && gl->rtn_status == GLR_NEWLINE)
+ gl_record_status(gl, GLR_ERROR, errno);
/*
- * Record the new prompt and its displayed width.
+ * Restore terminal settings.
+ */
+ if(gl->io_mode != GL_SERVER_MODE)
+ _gl_normal_io(gl);
+/*
+ * Restore the signal handlers.
*/
- gl_replace_prompt(gl, prompt);
+ gl_restore_signal_handlers(gl);
+/*
+ * If gl_get_line() gets aborted early, the errno value associated
+ * with the event that caused this to happen is recorded in
+ * gl->rtn_errno. Since errno may have been overwritten by cleanup
+ * functions after this, restore its value to the value that it had
+ * when the error condition occured, so that the caller can examine it
+ * to find out what happened.
+ */
+ errno = gl->rtn_errno;
+/*
+ * Check the completion status to see how to return.
+ */
+ switch(gl->rtn_status) {
+ case GLR_NEWLINE: /* Success */
+ return gl->line;
+ case GLR_BLOCKED: /* These events abort the current input line, */
+ case GLR_SIGNAL: /* when in normal blocking I/O mode, but only */
+ case GLR_TIMEOUT: /* temporarily pause line editing when in */
+ case GLR_FDABORT: /* non-blocking server I/O mode. */
+ if(gl->io_mode != GL_SERVER_MODE)
+ _gl_abandon_line(gl);
+ return NULL;
+ case GLR_ERROR: /* Unrecoverable errors abort the input line, */
+ case GLR_EOF: /* regardless of the I/O mode. */
+ default:
+ _gl_abandon_line(gl);
+ return NULL;
+ };
+}
+
+/*.......................................................................
+ * Read a single character from the user.
+ *
+ * Input:
+ * gl GetLine * A resource object returned by new_GetLine().
+ * prompt char * The prompt to prefix the line with, or NULL if
+ * no prompt is required.
+ * defchar char The character to substitute if the
+ * user simply hits return, or '\n' if you don't
+ * need to substitute anything.
+ * Output:
+ * return int The character that was read, or EOF if the read
+ * had to be aborted (in which case you can call
+ * gl_return_status() to find out why).
+ */
+int gl_query_char(GetLine *gl, const char *prompt, char defchar)
+{
+ int retval; /* The return value of _gl_query_char() */
+/*
+ * Check the arguments.
+ */
+ if(!gl) {
+ errno = EINVAL;
+ return EOF;
+ };
+/*
+ * Temporarily block all of the signals that we have been asked to trap.
+ */
+ if(gl_mask_signals(gl, &gl->old_signal_set))
+ return EOF;
+/*
+ * Perform the character reading task.
+ */
+ retval = _gl_query_char(gl, prompt, defchar);
+/*
+ * Restore the process signal mask to how it was when this function was
+ * first called.
+ */
+ gl_unmask_signals(gl, &gl->old_signal_set);
+ return retval;
+}
+
+/*.......................................................................
+ * This is the main body of the public function gl_query_char().
+ */
+static int _gl_query_char(GetLine *gl, const char *prompt, char defchar)
+{
+ int c = EOF; /* The character to be returned */
+ int waserr = 0; /* True if an error occurs */
+/*
+ * Assume that this call will successfully complete the input operation
+ * until proven otherwise.
+ */
+ gl_clear_status(gl);
+/*
+ * If this is the first call to this function or gl_get_line(),
+ * since new_GetLine(), complete any postponed configuration.
+ */
+ if(!gl->configured) {
+ (void) _gl_configure_getline(gl, NULL, NULL, TECLA_CONFIG_FILE);
+ gl->configured = 1;
+ };
/*
* Before installing our signal handler functions, record the fact
* that there are no pending signals.
@@ -1693,40 +2377,89 @@ char *gl_get_line(GetLine *gl, const char *prompt,
waserr = gl_override_signal_handlers(gl);
/*
* After recording the current terminal settings, switch the terminal
- * into raw input mode.
+ * into raw input mode without redisplaying any partially entered
+ * input line.
+ */
+ waserr = waserr || _gl_raw_io(gl, 0);
+/*
+ * Attempt to read the line. This will require more than one attempt if
+ * either a current temporary input file is opened by gl_get_input_line()
+ * or the end of a temporary input file is reached by gl_read_stream_line().
*/
- waserr = waserr || gl_raw_terminal_mode(gl);
+ while(!waserr) {
/*
- * Attempt to read the line.
+ * Read a line from a non-interactive stream?
*/
- waserr = waserr || gl_get_input_line(gl, start_line, start_pos);
+ if(gl->file_fp || !gl->is_term) {
+ c = gl_read_stream_char(gl);
+ if(c != EOF) { /* Success? */
+ if(c=='\n') c = defchar;
+ break;
+ } else if(gl->file_fp) { /* End of temporary input file? */
+ gl_revert_input(gl);
+ gl_record_status(gl, GLR_NEWLINE, 0);
+ } else { /* An error? */
+ waserr = 1;
+ break;
+ };
+ };
+/*
+ * Read from the terminal? Note that the above if() block may have
+ * changed gl->file_fp, so it is necessary to retest it here, rather
+ * than using an else statement.
+ */
+ if(!gl->file_fp && gl->is_term) {
+ c = gl_get_query_char(gl, prompt, defchar);
+ if(c==EOF)
+ waserr = 1;
+ else
+ break;
+ };
+ };
+/*
+ * If an error occurred, but gl->rtn_status is still set to
+ * GLR_NEWLINE, change the status to GLR_ERROR. Otherwise
+ * leave it at whatever specific value was assigned by the function
+ * that aborted input. This means that only functions that trap
+ * non-generic errors have to remember to update gl->rtn_status
+ * themselves.
+ */
+ if(waserr && gl->rtn_status == GLR_NEWLINE)
+ gl_record_status(gl, GLR_ERROR, errno);
/*
* Restore terminal settings.
*/
- gl_restore_terminal_attributes(gl);
+ if(gl->io_mode != GL_SERVER_MODE)
+ _gl_normal_io(gl);
/*
* Restore the signal handlers.
*/
gl_restore_signal_handlers(gl);
/*
- * Having restored the program terminal and signal environment,
- * re-submit any signals that were received.
+ * If this function gets aborted early, the errno value associated
+ * with the event that caused this to happen is recorded in
+ * gl->rtn_errno. Since errno may have been overwritten by cleanup
+ * functions after this, restore its value to the value that it had
+ * when the error condition occured, so that the caller can examine it
+ * to find out what happened.
*/
- if(gl_pending_signal != -1) {
- raise(gl_pending_signal);
- waserr = 1;
- };
+ errno = gl->rtn_errno;
/*
- * If gl_get_input_line() aborted input due to the user asking to
- * temporarily read lines from a file, read the first line from
- * this file.
+ * Error conditions are signalled to the caller, by setting the returned
+ * character to EOF.
*/
- if(!waserr && gl->file_fp)
- return gl_get_line(gl, prompt, NULL, 0);
+ if(gl->rtn_status != GLR_NEWLINE)
+ c = EOF;
/*
- * Return the new input line.
+ * In this mode, every character that is read is a completed
+ * transaction, just like reading a completed input line, so prepare
+ * for the next input line or character.
*/
- return waserr ? NULL : gl->line;
+ _gl_abandon_line(gl);
+/*
+ * Return the acquired character.
+ */
+ return c;
}
/*.......................................................................
@@ -1747,22 +2480,13 @@ static int gl_override_signal_handlers(GetLine *gl)
*/
SigAction act;
act.sa_handler = gl_signal_handler;
- sigemptyset(&act.sa_mask);
+ memcpy(&act.sa_mask, &gl->all_signal_set, sizeof(sigset_t));
act.sa_flags = 0;
/*
- * Get the process signal mask so that we can see which signals the
- * calling program currently has blocked, and so that we can restore this
- * mask before returning to the calling program.
- */
- if(sigprocmask(SIG_SETMASK, NULL, &gl->old_signal_set) == -1) {
- fprintf(stderr, "gl_get_line(): sigprocmask error: %s\n", strerror(errno));
- return 1;
- };
-/*
- * Form a new process signal mask from the list of signals that we have
- * been asked to trap.
+ * Get the subset of the signals that we are supposed to trap that
+ * should actually be trapped.
*/
- sigemptyset(&gl->new_signal_set);
+ sigemptyset(&gl->use_signal_set);
for(sig=gl->sigs; sig; sig=sig->next) {
/*
* Trap this signal? If it is blocked by the calling program and we
@@ -1770,40 +2494,37 @@ static int gl_override_signal_handlers(GetLine *gl)
*/
if(sig->flags & GLS_UNBLOCK_SIG ||
!sigismember(&gl->old_signal_set, sig->signo)) {
- if(sigaddset(&gl->new_signal_set, sig->signo) == -1) {
- fprintf(stderr, "gl_get_line(): sigaddset error: %s\n",
- strerror(errno));
+ if(sigaddset(&gl->use_signal_set, sig->signo) == -1) {
+ _err_record_msg(gl->err, "sigaddset error", END_ERR_MSG);
return 1;
};
};
};
/*
- * Before installing our signal handlers, block all of the signals
- * that we are going to be trapping.
- */
- if(sigprocmask(SIG_BLOCK, &gl->new_signal_set, NULL) == -1) {
- fprintf(stderr, "gl_get_line(): sigprocmask error: %s\n", strerror(errno));
- return 1;
- };
-/*
* Override the actions of the signals that we are trapping.
*/
for(sig=gl->sigs; sig; sig=sig->next) {
- if(sigismember(&gl->new_signal_set, sig->signo) &&
- sigaction(sig->signo, &act, &sig->original)) {
- fprintf(stderr, "gl_get_line(): sigaction error: %s\n", strerror(errno));
- return 1;
+ if(sigismember(&gl->use_signal_set, sig->signo)) {
+ sigdelset(&act.sa_mask, sig->signo);
+ if(sigaction(sig->signo, &act, &sig->original)) {
+ _err_record_msg(gl->err, "sigaction error", END_ERR_MSG);
+ return 1;
+ };
+ sigaddset(&act.sa_mask, sig->signo);
};
};
/*
+ * Record the fact that the application's signal handlers have now
+ * been overriden.
+ */
+ gl->signals_overriden = 1;
+/*
* Just in case a SIGWINCH signal was sent to the process while our
* SIGWINCH signal handler wasn't in place, check to see if the terminal
* size needs updating.
*/
-#ifdef USE_SIGWINCH
- if(gl_resize_terminal(gl, 0))
+ if(_gl_update_size(gl))
return 1;
-#endif
return 0;
}
@@ -1824,19 +2545,17 @@ static int gl_restore_signal_handlers(GetLine *gl)
* by gl_override_signal_handlers().
*/
for(sig=gl->sigs; sig; sig=sig->next) {
- if(sigismember(&gl->new_signal_set, sig->signo) &&
+ if(sigismember(&gl->use_signal_set, sig->signo) &&
sigaction(sig->signo, &sig->original, NULL)) {
- fprintf(stderr, "gl_get_line(): sigaction error: %s\n", strerror(errno));
+ _err_record_msg(gl->err, "sigaction error", END_ERR_MSG);
return 1;
};
};
/*
- * Restore the original signal mask.
+ * Record the fact that the application's signal handlers have now
+ * been restored.
*/
- if(sigprocmask(SIG_SETMASK, &gl->old_signal_set, NULL) == -1) {
- fprintf(stderr, "gl_get_line(): sigprocmask error: %s\n", strerror(errno));
- return 1;
- };
+ gl->signals_overriden = 0;
return 0;
}
@@ -1864,10 +2583,15 @@ static int gl_raw_terminal_mode(GetLine *gl)
{
Termios newattr; /* The new terminal attributes */
/*
+ * If the terminal is already in raw mode, do nothing.
+ */
+ if(gl->raw_mode)
+ return 0;
+/*
* Record the current terminal attributes.
*/
if(tcgetattr(gl->input_fd, &gl->oldattr)) {
- fprintf(stderr, "getline(): tcgetattr error: %s\n", strerror(errno));
+ _err_record_msg(gl->err, "tcgetattr error", END_ERR_MSG);
return 1;
};
/*
@@ -1901,17 +2625,21 @@ static int gl_raw_terminal_mode(GetLine *gl)
/*
* Request one byte at a time, without waiting.
*/
- newattr.c_cc[VMIN] = 1;
+ newattr.c_cc[VMIN] = gl->io_mode==GL_SERVER_MODE ? 0:1;
newattr.c_cc[VTIME] = 0;
/*
* Install the new terminal modes.
*/
while(tcsetattr(gl->input_fd, TCSADRAIN, &newattr)) {
- if (errno != EINTR) {
- fprintf(stderr, "getline(): tcsetattr error: %s\n", strerror(errno));
+ if(errno != EINTR) {
+ _err_record_msg(gl->err, "tcsetattr error", END_ERR_MSG);
return 1;
};
};
+/*
+ * Record the new terminal mode.
+ */
+ gl->raw_mode = 1;
return 0;
}
@@ -1928,6 +2656,11 @@ static int gl_restore_terminal_attributes(GetLine *gl)
{
int waserr = 0;
/*
+ * If not in raw mode, do nothing.
+ */
+ if(!gl->raw_mode)
+ return 0;
+/*
* Before changing the terminal attributes, make sure that all output
* has been passed to the terminal.
*/
@@ -1939,19 +2672,92 @@ static int gl_restore_terminal_attributes(GetLine *gl)
*/
while(tcsetattr(gl->input_fd, TCSADRAIN, &gl->oldattr)) {
if(errno != EINTR) {
- fprintf(stderr, "gl_get_line(): tcsetattr error: %s\n", strerror(errno));
+ _err_record_msg(gl->err, "tcsetattr error", END_ERR_MSG);
waserr = 1;
break;
};
};
+/*
+ * Record the new terminal mode.
+ */
+ gl->raw_mode = 0;
return waserr;
}
/*.......................................................................
+ * Switch the terminal file descriptor to use non-blocking I/O.
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ * fd int The file descriptor to make non-blocking.
+ */
+static int gl_nonblocking_io(GetLine *gl, int fd)
+{
+ int fcntl_flags; /* The new file-descriptor control flags */
+/*
+ * Is non-blocking I/O supported on this system? Note that even
+ * without non-blocking I/O, the terminal will probably still act as
+ * though it was non-blocking, because we also set the terminal
+ * attributes to return immediately if no input is available and we
+ * use select() to wait to be able to write. If select() also isn't
+ * available, then input will probably remain fine, but output could
+ * block, depending on the behaviour of the terminal driver.
+ */
+#if defined(NON_BLOCKING_FLAG)
+/*
+ * Query the current file-control flags, and add the
+ * non-blocking I/O flag.
+ */
+ fcntl_flags = fcntl(fd, F_GETFL) | NON_BLOCKING_FLAG;
+/*
+ * Install the new control flags.
+ */
+ if(fcntl(fd, F_SETFL, fcntl_flags) == -1) {
+ _err_record_msg(gl->err, "fcntl error", END_ERR_MSG);
+ return 1;
+ };
+#endif
+ return 0;
+}
+
+/*.......................................................................
+ * Switch to blocking terminal I/O.
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ * fd int The file descriptor to make blocking.
+ */
+static int gl_blocking_io(GetLine *gl, int fd)
+{
+ int fcntl_flags; /* The new file-descriptor control flags */
+/*
+ * Is non-blocking I/O implemented on this system?
+ */
+#if defined(NON_BLOCKING_FLAG)
+/*
+ * Query the current file control flags and remove the non-blocking
+ * I/O flag.
+ */
+ fcntl_flags = fcntl(fd, F_GETFL) & ~NON_BLOCKING_FLAG;
+/*
+ * Install the modified control flags.
+ */
+ if(fcntl(fd, F_SETFL, fcntl_flags) == -1) {
+ _err_record_msg(gl->err, "fcntl error", END_ERR_MSG);
+ return 1;
+ };
+#endif
+ return 0;
+}
+
+/*.......................................................................
* Read a new input line from the user.
*
* Input:
* gl GetLine * The resource object of this library.
+ * prompt char * The prompt to prefix the line with, or NULL to
+ * use the same prompt that was used by the previous
+ * line.
* start_line char * The initial contents of the input line, or NULL
* if it should start out empty.
* start_pos int If start_line isn't NULL, this specifies the
@@ -1963,91 +2769,34 @@ static int gl_restore_terminal_attributes(GetLine *gl)
* return int 0 - OK.
* 1 - Error.
*/
-static int gl_get_input_line(GetLine *gl, const char *start_line, int start_pos)
+static int gl_get_input_line(GetLine *gl, const char *prompt,
+ const char *start_line, int start_pos)
{
- char c; /* The character being read */
-/*
- * Reset the properties of the line.
- */
- gl->ntotal = 0;
- gl->buff_curpos = 0;
- gl->term_curpos = 0;
- gl->insert_curpos = 0;
- gl->number = -1;
- gl->endline = 0;
- gl->vi.command = 0;
- gl->vi.undo.line[0] = '\0';
- gl->vi.undo.ntotal = 0;
- gl->vi.undo.buff_curpos = 0;
- gl->vi.repeat.fn = 0;
- gl->last_signal = -1;
+ char c; /* The character being read */
/*
- * Reset the history search pointers.
+ * Flush any pending output to the terminal.
*/
- if(_glh_cancel_search(gl->glh))
+ if(_glq_char_count(gl->cq) > 0 && gl_flush_output(gl))
return 1;
/*
- * Draw the prompt at the start of the line.
+ * Are we starting a new line?
*/
- if(gl_display_prompt(gl))
- return 1;
+ if(gl->endline) {
/*
- * Present an initial line?
+ * Delete any incompletely enterred line.
*/
- if(start_line) {
- char *cptr; /* A pointer into gl->line[] */
-/*
- * Load the line into the buffer, and display it.
- */
- if(start_line != gl->line)
- strncpy(gl->line, start_line, gl->linelen);
- gl->line[gl->linelen] = '\0';
- gl->ntotal = strlen(gl->line);
-/*
- * Strip off any trailing newline and carriage return characters.
- */
- for(cptr=gl->line + gl->ntotal - 1; cptr >= gl->line &&
- (*cptr=='\n' || *cptr=='\r'); cptr--,gl->ntotal--)
- ;
- if(gl->ntotal < 0)
- gl->ntotal = 0;
- gl->line[gl->ntotal] = '\0';
-/*
- * Display the string that remains.
- */
- if(gl_output_string(gl, gl->line, '\0'))
+ if(gl_erase_line(gl))
return 1;
/*
- * Where should the cursor be placed within the line?
- */
- if(start_pos < 0 || start_pos > gl->ntotal) {
- if(gl_place_cursor(gl, gl->ntotal))
- return 1;
- } else {
- if(gl_place_cursor(gl, start_pos))
- return 1;
- };
- } else {
- gl->line[0] = '\0';
- };
-/*
- * Preload a history line?
+ * Display the new line to be edited.
*/
- if(gl->preload_history) {
- gl->preload_history = 0;
- if(gl->preload_id) {
- if(_glh_recall_line(gl->glh, gl->preload_id, gl->line, gl->linelen)) {
- gl->ntotal = strlen(gl->line);
- gl->buff_curpos = strlen(gl->line);
- };
- gl->preload_id = 0;
- };
- gl_redisplay(gl, 1);
+ if(gl_present_line(gl, prompt, start_line, start_pos))
+ return 1;
};
/*
* Read one character at a time.
*/
- while(gl_read_character(gl, &c) == 0) {
+ while(gl_read_terminal(gl, 1, &c) == 0) {
/*
* Increment the count of the number of key sequences entered.
*/
@@ -2069,20 +2818,120 @@ static int gl_get_input_line(GetLine *gl, const char *start_line, int start_pos)
* Has the line been completed?
*/
if(gl->endline)
- return gl_line_ended(gl, isprint((int)(unsigned char) c) ? c : '\n',
- gl->echo && (c=='\n' || c=='\r'));
+ return gl_line_ended(gl, c);
};
/*
- * To get here, gl_read_character() must have returned non-zero. See
- * if this was because a signal was caught that requested that the
- * current line be returned.
+ * To get here, gl_read_terminal() must have returned non-zero. See
+ * whether a signal was caught that requested that the current line
+ * be returned.
*/
if(gl->endline)
- return gl_line_ended(gl, '\n', gl->echo);
+ return gl_line_ended(gl, '\n');
+/*
+ * If I/O blocked while attempting to get the latest character
+ * of the key sequence, rewind the key buffer to allow interpretation of
+ * the current key sequence to be restarted on the next call to this
+ * function.
+ */
+ if(gl->rtn_status == GLR_BLOCKED && gl->pending_io == GLP_READ)
+ gl->nread = 0;
return 1;
}
/*.......................................................................
+ * This is the private function of gl_query_char() that handles
+ * prompting the user, reading a character from the terminal, and
+ * displaying what the user entered.
+ *
+ * Input:
+ * gl GetLine * The resource object of this library.
+ * prompt char * The prompt to prefix the line with.
+ * defchar char The character to substitute if the
+ * user simply hits return, or '\n' if you don't
+ * need to substitute anything.
+ * Output:
+ * return int The character that was read, or EOF if something
+ * prevented a character from being read.
+ */
+static int gl_get_query_char(GetLine *gl, const char *prompt, int defchar)
+{
+ char c; /* The character being read */
+ int retval; /* The return value of this function */
+/*
+ * Flush any pending output to the terminal.
+ */
+ if(_glq_char_count(gl->cq) > 0 && gl_flush_output(gl))
+ return EOF;
+/*
+ * Delete any incompletely entered line.
+ */
+ if(gl_erase_line(gl))
+ return EOF;
+/*
+ * Reset the line input parameters and display the prompt, if any.
+ */
+ if(gl_present_line(gl, prompt, NULL, 0))
+ return EOF;
+/*
+ * Read one character.
+ */
+ if(gl_read_terminal(gl, 1, &c) == 0) {
+/*
+ * In this mode, count each character as being a new key-sequence.
+ */
+ gl->keyseq_count++;
+/*
+ * Delete the character that was read, from the key-press buffer.
+ */
+ gl_discard_chars(gl, gl->nread);
+/*
+ * Convert carriage returns to newlines.
+ */
+ if(c == '\r')
+ c = '\n';
+/*
+ * If the user just hit return, subsitute the default character.
+ */
+ if(c == '\n')
+ c = defchar;
+/*
+ * Display the entered character to the right of the prompt.
+ */
+ if(c!='\n') {
+ if(gl_end_of_line(gl, 1, NULL)==0)
+ gl_print_char(gl, c, ' ');
+ };
+/*
+ * Record the return character, and mark the call as successful.
+ */
+ retval = c;
+ gl_record_status(gl, GLR_NEWLINE, 0);
+/*
+ * Was a signal caught whose disposition is to cause the current input
+ * line to be returned? If so return a newline character.
+ */
+ } else if(gl->endline) {
+ retval = '\n';
+ gl_record_status(gl, GLR_NEWLINE, 0);
+ } else {
+ retval = EOF;
+ };
+/*
+ * Start a new line.
+ */
+ if(gl_start_newline(gl, 1))
+ return EOF;
+/*
+ * Attempt to flush any pending output.
+ */
+ (void) gl_flush_output(gl);
+/*
+ * Return either the character that was read, or EOF if an error occurred.
+ */
+ return retval;
+}
+
+/*.......................................................................
* Add a character to the line buffer at the current cursor position,
* inserting or overwriting according the current mode.
*
@@ -2119,26 +2968,18 @@ static int gl_add_char_to_line(GetLine *gl, char c)
/*
* If inserting, make room for the new character.
*/
- if(buff_curpos < gl->ntotal) {
- memmove(gl->line + buff_curpos + 1, gl->line + buff_curpos,
- gl->ntotal - buff_curpos);
- };
+ if(buff_curpos < gl->ntotal)
+ gl_make_gap_in_buffer(gl, buff_curpos, 1);
/*
* Copy the character into the buffer.
*/
- gl->line[buff_curpos] = c;
+ gl_buffer_char(gl, c, buff_curpos);
gl->buff_curpos++;
/*
- * If the line was extended, update the record of the string length
- * and terminate the extended string.
- */
- gl->ntotal++;
- gl->line[gl->ntotal] = '\0';
-/*
* Redraw the line from the cursor position to the end of the line,
* and move the cursor to just after the added character.
*/
- if(gl_output_string(gl, gl->line + buff_curpos, '\0') ||
+ if(gl_print_string(gl, gl->line + buff_curpos, '\0') ||
gl_set_term_curpos(gl, term_curpos + width))
return 1;
/*
@@ -2146,15 +2987,14 @@ static int gl_add_char_to_line(GetLine *gl, char c)
*/
} else {
/*
- * Get the widths of the character to be overwritten and the character
- * that is going to replace it.
+ * Get the width of the character being overwritten.
*/
int old_width = gl_displayed_char_width(gl, gl->line[buff_curpos],
term_curpos);
/*
* Overwrite the character in the buffer.
*/
- gl->line[buff_curpos] = c;
+ gl_buffer_char(gl, c, buff_curpos);
/*
* If we are replacing with a narrower character, we need to
* redraw the terminal string to the end of the line, then
@@ -2162,12 +3002,12 @@ static int gl_add_char_to_line(GetLine *gl, char c)
* with spaces.
*/
if(old_width > width) {
- if(gl_output_string(gl, gl->line + buff_curpos, '\0'))
+ if(gl_print_string(gl, gl->line + buff_curpos, '\0'))
return 1;
/*
* Clear to the end of the terminal.
*/
- if(gl_output_control_sequence(gl, gl->nline, gl->clear_eod))
+ if(gl_truncate_display(gl))
return 1;
/*
* Move the cursor to the end of the new character.
@@ -2184,7 +3024,7 @@ static int gl_add_char_to_line(GetLine *gl, char c)
* Redraw the line from the cursor position to the end of the line,
* and move the cursor to just after the added character.
*/
- if(gl_output_string(gl, gl->line + buff_curpos, '\0') ||
+ if(gl_print_string(gl, gl->line + buff_curpos, '\0') ||
gl_set_term_curpos(gl, term_curpos + width))
return 1;
gl->buff_curpos++;
@@ -2196,12 +3036,12 @@ static int gl_add_char_to_line(GetLine *gl, char c)
/*
* Copy the character into the buffer.
*/
- gl->line[buff_curpos] = c;
+ gl_buffer_char(gl, c, buff_curpos);
gl->buff_curpos++;
/*
* Overwrite the original character.
*/
- if(gl_output_char(gl, c, gl->line[gl->buff_curpos]))
+ if(gl_print_char(gl, c, gl->line[gl->buff_curpos]))
return 1;
};
};
@@ -2246,25 +3086,18 @@ static int gl_add_string_to_line(GetLine *gl, const char *s)
* Move the characters that follow the cursor in the buffer by
* buff_slen characters to the right.
*/
- if(gl->ntotal > gl->buff_curpos) {
- memmove(gl->line + gl->buff_curpos + buff_slen, gl->line + gl->buff_curpos,
- gl->ntotal - gl->buff_curpos);
- };
+ if(gl->ntotal > gl->buff_curpos)
+ gl_make_gap_in_buffer(gl, gl->buff_curpos, buff_slen);
/*
* Copy the string into the buffer.
*/
- memcpy(gl->line + gl->buff_curpos, s, buff_slen);
- gl->ntotal += buff_slen;
+ gl_buffer_string(gl, s, buff_slen, gl->buff_curpos);
gl->buff_curpos += buff_slen;
/*
- * Maintain the buffer properly terminated.
- */
- gl->line[gl->ntotal] = '\0';
-/*
* Write the modified part of the line to the terminal, then move
* the terminal cursor to the end of the displayed input string.
*/
- if(gl_output_string(gl, gl->line + buff_curpos, '\0') ||
+ if(gl_print_string(gl, gl->line + buff_curpos, '\0') ||
gl_set_term_curpos(gl, term_curpos + term_slen))
return 1;
return 0;
@@ -2275,6 +3108,13 @@ static int gl_add_string_to_line(GetLine *gl, const char *s)
*
* Input:
* gl GetLine * The resource object of this library.
+ * keep int If true, the returned character will be kept in
+ * the input buffer, for potential replays. It should
+ * subsequently be removed from the buffer when the
+ * key sequence that it belongs to has been fully
+ * processed, by calling gl_discard_chars().
+ * Input/Output:
+ * c char * The character that is read, is assigned to *c.
* Output:
* return int 0 - OK.
* 1 - Either an I/O error occurred, or a signal was
@@ -2283,7 +3123,7 @@ static int gl_add_string_to_line(GetLine *gl, const char *s)
* as though the user had pressed return. In the
* latter case gl->endline will be non-zero.
*/
-static int gl_read_character(GetLine *gl, char *c)
+static int gl_read_terminal(GetLine *gl, int keep, char *c)
{
/*
* Before waiting for a new character to be input, flush unwritten
@@ -2292,56 +3132,135 @@ static int gl_read_character(GetLine *gl, char *c)
if(gl_flush_output(gl))
return 1;
/*
+ * Record the fact that we are about to read from the terminal.
+ */
+ gl->pending_io = GLP_READ;
+/*
+ * If there is already an unread character in the buffer,
+ * return it.
+ */
+ if(gl->nread < gl->nbuf) {
+ *c = gl->keybuf[gl->nread];
+/*
+ * Retain the character in the key buffer, but mark it as having been read?
+ */
+ if(keep) {
+ gl->nread++;
+/*
+ * Completely remove the character from the key buffer?
+ */
+ } else {
+ memmove(gl->keybuf + gl->nread, gl->keybuf + gl->nread + 1,
+ gl->nbuf - gl->nread - 1);
+ };
+ return 0;
+ };
+/*
+ * Make sure that there is space in the key buffer for one more character.
+ * This should always be true if gl_interpret_char() is called for each
+ * new character added, since it will clear the buffer once it has recognized
+ * or rejected a key sequence.
+ */
+ if(gl->nbuf + 1 > GL_KEY_MAX) {
+ gl_print_info(gl, "gl_read_terminal: Buffer overflow avoided.",
+ GL_END_INFO);
+ errno = EIO;
+ return 1;
+ };
+/*
+ * Read one character from the terminal.
+ */
+ switch(gl_read_input(gl, c)) {
+ case GL_READ_OK:
+ break;
+ case GL_READ_BLOCKED:
+ gl_record_status(gl, GLR_BLOCKED, BLOCKED_ERRNO);
+ return 1;
+ break;
+ default:
+ return 1;
+ break;
+ };
+/*
+ * Append the character to the key buffer?
+ */
+ if(keep) {
+ gl->keybuf[gl->nbuf] = *c;
+ gl->nread = ++gl->nbuf;
+ };
+ return 0;
+}
+
+/*.......................................................................
+ * Read one or more keypresses from the terminal of an input stream.
+ *
+ * Input:
+ * gl GetLine * The resource object of this module.
+ * c char * The character that was read is assigned to *c.
+ * Output:
+ * return GlReadStatus The completion status of the read operation.
+ */
+static GlReadStatus gl_read_input(GetLine *gl, char *c)
+{
+/*
* We may have to repeat the read if window change signals are received.
*/
for(;;) {
/*
+ * Which file descriptor should we read from? Mark this volatile, so
+ * that siglongjmp() can't clobber it.
+ */
+ volatile int fd = gl->file_fp ? fileno(gl->file_fp) : gl->input_fd;
+/*
* If the endline flag becomes set, don't wait for another character.
*/
if(gl->endline)
- return 1;
+ return GL_READ_ERROR;
/*
* Since the code in this function can block, trap signals.
*/
if(sigsetjmp(gl_setjmp_buffer, 1)==0) {
/*
- * Unblock the signals that we are trapping.
+ * Handle the different I/O modes.
*/
- if(sigprocmask(SIG_UNBLOCK, &gl->new_signal_set, NULL) == -1) {
- fprintf(stderr, "getline(): sigprocmask error: %s\n", strerror(errno));
- return 1;
- };
+ switch(gl->io_mode) {
/*
- * If select() is available, watch for activity on any file descriptors
- * that the user has registered, and for data available on the terminal
- * file descriptor.
+ * In normal I/O mode, we call the event handler before attempting
+ * to read, since read() blocks.
*/
-#ifdef HAVE_SELECT
- if(gl_event_handler(gl))
- return 1;
-#endif
+ case GL_NORMAL_MODE:
+ if(gl_event_handler(gl, fd))
+ return GL_READ_ERROR;
+ return gl_read_unmasked(gl, fd, c); /* Read one character */
+ break;
/*
- * Read one character from the terminal. This could take more
- * than one call if an interrupt that we aren't trapping is
- * received.
- */
- while(read(gl->input_fd, (void *)c, 1) != 1) {
- if(errno != EINTR) {
-#ifdef EAGAIN
- if(!errno) /* This can happen with SysV O_NDELAY */
- errno = EAGAIN;
-#endif
- return 1;
+ * In non-blocking server I/O mode, we attempt to read a character,
+ * and only if this fails, call the event handler to wait for a any
+ * user-configured timeout and any other user-configured events. In
+ * addition, we turn off the fcntl() non-blocking flag when reading
+ * from the terminal, to work around a bug in Solaris. We can do this
+ * without causing the read() to block, because when in non-blocking
+ * server-I/O mode, gl_raw_io() sets the VMIN terminal attribute to 0,
+ * which tells the terminal driver to return immediately if no
+ * characters are available to be read.
+ */
+ case GL_SERVER_MODE:
+ {
+ GlReadStatus status; /* The return status */
+ if(isatty(fd)) /* If we reading from a terminal, */
+ gl_blocking_io(gl, fd); /* switch to blocking I/O */
+ status = gl_read_unmasked(gl, fd, c); /* Try reading */
+ if(status == GL_READ_BLOCKED) { /* Nothing readable yet */
+ if(gl_event_handler(gl, fd)) /* Wait for input */
+ status = GL_READ_ERROR;
+ else
+ status = gl_read_unmasked(gl, fd, c); /* Try reading again */
+ };
+ gl_nonblocking_io(gl, fd); /* Restore non-blocking I/O */
+ return status;
};
+ break;
};
-/*
- * Block all of the signals that we are trapping.
- */
- if(sigprocmask(SIG_BLOCK, &gl->new_signal_set, NULL) == -1) {
- fprintf(stderr, "getline(): sigprocmask error: %s\n", strerror(errno));
- return 1;
- };
- return 0;
};
/*
* To get here, one of the signals that we are trapping must have
@@ -2349,9 +3268,82 @@ static int gl_read_character(GetLine *gl, char *c)
* the signal mask that was blocking these signals will have been
* reinstated, so we can be sure that no more of these signals will
* be received until we explicitly unblock them again.
+ *
+ * First, if non-blocking I/O was temporarily disabled, reinstate it.
*/
+ if(gl->io_mode == GL_SERVER_MODE)
+ gl_nonblocking_io(gl, fd);
+/*
+ * Now respond to the signal that was caught.
+ */
if(gl_check_caught_signal(gl))
- return 1;
+ return GL_READ_ERROR;
+ };
+}
+
+/*.......................................................................
+ * This is a private function of gl_read_input(), which unblocks signals
+ * temporarily while it reads a single character from the specified file
+ * descriptor.
+ *
+ * Input:
+ * gl GetLine * The resource object of this module.
+ * fd int The file descriptor to read from.
+ * c char * The character that was read is assigned to *c.
+ * Output:
+ * return GlReadStatus The completion status of the read.
+ */
+static GlReadStatus gl_read_unmasked(GetLine *gl, int fd, char *c)
+{
+ int nread; /* The return value of read() */
+/*
+ * Unblock the signals that we are trapping, while waiting for I/O.
+ */
+ gl_catch_signals(gl);
+/*
+ * Attempt to read one character from the terminal, restarting the read
+ * if any signals that we aren't trapping, are received.
+ */
+ do {
+ errno = 0;
+ nread = read(fd, c, 1);
+ } while(nread < 0 && errno==EINTR);
+/*
+ * Block all of the signals that we are trapping.
+ */
+ gl_mask_signals(gl, NULL);
+/*
+ * Check the completion status of the read.
+ */
+ switch(nread) {
+ case 1:
+ return GL_READ_OK;
+ case 0:
+ return (isatty(fd) || errno != 0) ? GL_READ_BLOCKED : GL_READ_EOF;
+ default:
+ return GL_READ_ERROR;
+ };
+}
+
+/*.......................................................................
+ * Remove a specified number of characters from the start of the
+ * key-press lookahead buffer, gl->keybuf[], and arrange for the next
+ * read to start from the character at the start of the shifted buffer.
+ *
+ * Input:
+ * gl GetLine * The resource object of this module.
+ * nused int The number of characters to discard from the start
+ * of the buffer.
+ */
+static void gl_discard_chars(GetLine *gl, int nused)
+{
+ int nkeep = gl->nbuf - nused;
+ if(nkeep > 0) {
+ memmove(gl->keybuf, gl->keybuf + nused, nkeep);
+ gl->nbuf = nkeep;
+ gl->nread = 0;
+ } else {
+ gl->nbuf = gl->nread = 0;
};
}
@@ -2369,50 +3361,87 @@ static int gl_check_caught_signal(GetLine *gl)
{
GlSignalNode *sig; /* The signal disposition */
SigAction keep_action; /* The signal disposition of tecla signal handlers */
+ unsigned flags; /* The signal processing flags to use */
+ int signo; /* The signal to be handled */
/*
* Was no signal caught?
*/
if(gl_pending_signal == -1)
return 0;
/*
- * Record the signal that was caught, so that the user can query it later.
+ * Get the signal to be handled.
*/
- gl->last_signal = gl_pending_signal;
+ signo = gl_pending_signal;
/*
- * Did we receive a terminal size signal?
+ * Mark the signal as handled. Note that at this point, all of
+ * the signals that we are trapping are blocked from delivery.
+ */
+ gl_pending_signal = -1;
+/*
+ * Record the signal that was caught, so that the user can query it later.
*/
-#ifdef USE_SIGWINCH
- if(gl_pending_signal == SIGWINCH && gl_resize_terminal(gl, 1))
+ gl->last_signal = signo;
+/*
+ * In non-blocking server mode, the application is responsible for
+ * responding to terminal signals, and we don't want gl_get_line()s
+ * normal signal handling to clash with this, so whenever a signal
+ * is caught, we arrange for gl_get_line() to abort and requeue the
+ * signal while signals are still blocked. If the application
+ * had the signal unblocked when gl_get_line() was called, the signal
+ * will be delivered again as soon as gl_get_line() restores the
+ * process signal mask, just before returning to the application.
+ * Note that the caller of this function should set gl->pending_io
+ * to the appropriate choice of GLP_READ and GLP_WRITE, before returning.
+ */
+ if(gl->io_mode==GL_SERVER_MODE) {
+ gl_record_status(gl, GLR_SIGNAL, EINTR);
+ raise(signo);
return 1;
-#endif
+ };
/*
* Lookup the requested disposition of this signal.
*/
- for(sig=gl->sigs; sig && sig->signo != gl_pending_signal; sig=sig->next)
+ for(sig=gl->sigs; sig && sig->signo != signo; sig=sig->next)
;
if(!sig)
return 0;
/*
- * Start a fresh line?
+ * Get the signal response flags for this signal.
+ */
+ flags = sig->flags;
+/*
+ * Only perform terminal-specific actions if the session is interactive.
*/
- if(sig->flags & GLS_RESTORE_LINE) {
- if(gl_set_term_curpos(gl, gl_buff_curpos_to_term_curpos(gl, gl->ntotal)) ||
- gl_output_raw_string(gl, "\r\n"))
+ if(gl->is_term) {
+/*
+ * Did we receive a terminal size signal?
+ */
+#ifdef SIGWINCH
+ if(signo == SIGWINCH && _gl_update_size(gl))
return 1;
- };
+#endif
+/*
+ * Start a fresh line?
+ */
+ if(flags & GLS_RESTORE_LINE) {
+ if(gl_start_newline(gl, 0))
+ return 1;
+ };
/*
* Restore terminal settings to how they were before gl_get_line() was
* called?
*/
- if(sig->flags & GLS_RESTORE_TTY)
- gl_restore_terminal_attributes(gl);
+ if(flags & GLS_RESTORE_TTY)
+ gl_restore_terminal_attributes(gl);
+ };
/*
* Restore signal handlers to how they were before gl_get_line() was
* called? If this hasn't been requested, only reinstate the signal
* handler of the signal that we are handling.
*/
- if(sig->flags & GLS_RESTORE_SIG) {
+ if(flags & GLS_RESTORE_SIG) {
gl_restore_signal_handlers(gl);
+ gl_unmask_signals(gl, &gl->old_signal_set);
} else {
(void) sigaction(sig->signo, &sig->original, &keep_action);
(void) sigprocmask(SIG_UNBLOCK, &sig->proc_mask, NULL);
@@ -2420,44 +3449,48 @@ static int gl_check_caught_signal(GetLine *gl)
/*
* Forward the signal to the application's signal handler.
*/
- if(!(sig->flags & GLS_DONT_FORWARD))
- raise(gl_pending_signal);
- gl_pending_signal = -1;
+ if(!(flags & GLS_DONT_FORWARD))
+ raise(signo);
/*
* Reinstate our signal handlers.
*/
- if(sig->flags & GLS_RESTORE_SIG) {
+ if(flags & GLS_RESTORE_SIG) {
+ gl_mask_signals(gl, NULL);
gl_override_signal_handlers(gl);
} else {
(void) sigaction(sig->signo, &keep_action, NULL);
(void) sigprocmask(SIG_BLOCK, &sig->proc_mask, NULL);
};
/*
- * Do we need to reinstate our terminal settings?
+ * Prepare the terminal for continued editing, if this is an interactive
+ * session.
*/
- if(sig->flags & GLS_RESTORE_TTY)
- gl_raw_terminal_mode(gl);
+ if(gl->is_term) {
/*
- * Redraw the line?
+ * Do we need to reinstate our terminal settings?
*/
- if(sig->flags & GLS_REDRAW_LINE && gl_redisplay(gl, 1))
- return 1;
+ if(flags & GLS_RESTORE_TTY)
+ gl_raw_terminal_mode(gl);
/*
- * Set errno.
+ * Redraw the line?
*/
- errno = sig->errno_value;
+ if(flags & GLS_REDRAW_LINE)
+ gl_queue_redisplay(gl);
+ };
/*
* What next?
*/
switch(sig->after) {
case GLS_RETURN:
- return gl_newline(gl, 1);
+ gl_newline(gl, 1, NULL);
+ return gl->is_term && gl_flush_output(gl);
break;
case GLS_ABORT:
+ gl_record_status(gl, GLR_SIGNAL, sig->errno_value);
return 1;
break;
case GLS_CONTINUE:
- return 0;
+ return gl->is_term && gl_flush_output(gl);
break;
};
return 0;
@@ -2510,31 +3543,34 @@ static int gl_control_strings(GetLine *gl, const char *term)
* database.
*/
#ifdef USE_TERMINFO
- if(!term || setupterm((char *)term, gl->input_fd, NULL) == ERR) {
- bad_term = 1;
- } else {
- _clr_StringGroup(gl->capmem);
- gl->left = gl_tigetstr(gl, "cub1");
- gl->right = gl_tigetstr(gl, "cuf1");
- gl->up = gl_tigetstr(gl, "cuu1");
- gl->down = gl_tigetstr(gl, "cud1");
- gl->home = gl_tigetstr(gl, "home");
- gl->clear_eol = gl_tigetstr(gl, "el");
- gl->clear_eod = gl_tigetstr(gl, "ed");
- gl->u_arrow = gl_tigetstr(gl, "kcuu1");
- gl->d_arrow = gl_tigetstr(gl, "kcud1");
- gl->l_arrow = gl_tigetstr(gl, "kcub1");
- gl->r_arrow = gl_tigetstr(gl, "kcuf1");
- gl->left_n = gl_tigetstr(gl, "cub");
- gl->right_n = gl_tigetstr(gl, "cuf");
- gl->sound_bell = gl_tigetstr(gl, "bel");
- gl->bold = gl_tigetstr(gl, "bold");
- gl->underline = gl_tigetstr(gl, "smul");
- gl->standout = gl_tigetstr(gl, "smso");
- gl->dim = gl_tigetstr(gl, "dim");
- gl->reverse = gl_tigetstr(gl, "rev");
- gl->blink = gl_tigetstr(gl, "blink");
- gl->text_attr_off = gl_tigetstr(gl, "sgr0");
+ {
+ int errret;
+ if(!term || setupterm((char *)term, gl->input_fd, &errret) == ERR) {
+ bad_term = 1;
+ } else {
+ _clr_StringGroup(gl->capmem);
+ gl->left = gl_tigetstr(gl, "cub1");
+ gl->right = gl_tigetstr(gl, "cuf1");
+ gl->up = gl_tigetstr(gl, "cuu1");
+ gl->down = gl_tigetstr(gl, "cud1");
+ gl->home = gl_tigetstr(gl, "home");
+ gl->clear_eol = gl_tigetstr(gl, "el");
+ gl->clear_eod = gl_tigetstr(gl, "ed");
+ gl->u_arrow = gl_tigetstr(gl, "kcuu1");
+ gl->d_arrow = gl_tigetstr(gl, "kcud1");
+ gl->l_arrow = gl_tigetstr(gl, "kcub1");
+ gl->r_arrow = gl_tigetstr(gl, "kcuf1");
+ gl->left_n = gl_tigetstr(gl, "cub");
+ gl->right_n = gl_tigetstr(gl, "cuf");
+ gl->sound_bell = gl_tigetstr(gl, "bel");
+ gl->bold = gl_tigetstr(gl, "bold");
+ gl->underline = gl_tigetstr(gl, "smul");
+ gl->standout = gl_tigetstr(gl, "smso");
+ gl->dim = gl_tigetstr(gl, "dim");
+ gl->reverse = gl_tigetstr(gl, "rev");
+ gl->blink = gl_tigetstr(gl, "blink");
+ gl->text_attr_off = gl_tigetstr(gl, "sgr0");
+ };
};
#elif defined(USE_TERMCAP)
if(!term || tgetent(gl->tgetent_buf, (char *)term) < 0) {
@@ -2567,8 +3603,8 @@ static int gl_control_strings(GetLine *gl, const char *term)
* Report term being unusable.
*/
if(bad_term) {
- fprintf(stderr, "Bad terminal type: \"%s\". Will assume vt100.\n",
- term ? term : "(null)");
+ gl_print_info(gl, "Bad terminal type: \"", term ? term : "(null)",
+ "\". Will assume vt100.", GL_END_INFO);
};
/*
* Fill in missing information with ANSI VT100 strings.
@@ -2616,7 +3652,7 @@ static int gl_control_strings(GetLine *gl, const char *term)
/*
* Find out the current terminal size.
*/
- (void) gl_terminal_size(gl, GL_DEF_NCOLUMN, GL_DEF_NLINE);
+ (void) _gl_terminal_size(gl, GL_DEF_NCOLUMN, GL_DEF_NLINE, NULL);
return 0;
}
@@ -2729,7 +3765,7 @@ static KT_KEY_FN(gl_literal_next)
/*
* Get the character to be inserted literally.
*/
- if(gl_read_character(gl, &c))
+ if(gl_read_terminal(gl, 1, &c))
return 1;
/*
* Add the character to the line 'count' times.
@@ -2740,6 +3776,23 @@ static KT_KEY_FN(gl_literal_next)
}
/*.......................................................................
+ * Return the width of a tab character at a given position when
+ * displayed at a given position on the terminal. This is needed
+ * because the width of tab characters depends on where they are,
+ * relative to the preceding tab stops.
+ *
+ * Input:
+ * gl GetLine * The resource object of this library.
+ * term_curpos int The destination terminal location of the character.
+ * Output:
+ * return int The number of terminal charaters needed.
+ */
+static int gl_displayed_tab_width(GetLine *gl, int term_curpos)
+{
+ return TAB_WIDTH - ((term_curpos % gl->ncolumn) % TAB_WIDTH);
+}
+
+/*.......................................................................
* Return the number of characters needed to display a given character
* on the screen. Tab characters require eight spaces, and control
* characters are represented by a caret followed by the modified
@@ -2758,17 +3811,15 @@ static KT_KEY_FN(gl_literal_next)
static int gl_displayed_char_width(GetLine *gl, char c, int term_curpos)
{
if(c=='\t')
- return TAB_WIDTH - ((term_curpos % gl->ncolumn) % TAB_WIDTH);
+ return gl_displayed_tab_width(gl, term_curpos);
if(IS_CTRL_CHAR(c))
return 2;
- if(!isprint((int)(unsigned char) c)) {
- char string[TAB_WIDTH + 4];
- sprintf(string, "\\%o", (int)(unsigned char)c);
- return strlen(string);
- };
+ if(!isprint((int)(unsigned char) c))
+ return gl_octal_width((int)(unsigned char)c) + 1;
return 1;
}
+
/*.......................................................................
* Work out the length of given string of characters on the terminal.
*
@@ -2787,7 +3838,7 @@ static int gl_displayed_char_width(GetLine *gl, char c, int term_curpos)
static int gl_displayed_string_width(GetLine *gl, const char *string, int nc,
int term_curpos)
{
- int slen=0; /* The displayed number of characters */
+ int slen = 0; /* The displayed number of characters */
int i;
/*
* How many characters are to be measured?
@@ -2803,35 +3854,52 @@ static int gl_displayed_string_width(GetLine *gl, const char *string, int nc,
}
/*.......................................................................
- * Write a string directly to the terminal.
+ * Write a string verbatim to the current terminal or output stream.
+ *
+ * Note that when async-signal safety is required, the 'buffered'
+ * argument must be 0, and n must not be -1.
*
* Input:
- * gl GetLine * The resource object of this program.
- * string char * The string to be written.
+ * gl GetLine * The resource object of the gl_get_line().
+ * buffered int If true, used buffered I/O when writing to
+ * the terminal. Otherwise use async-signal-safe
+ * unbuffered I/O.
+ * string const char * The string to be written (this need not be
+ * '\0' terminated unless n<0).
+ * n int The number of characters to write from the
+ * prefix of string[], or -1 to request that
+ * gl_print_raw_string() use strlen() to figure
+ * out the length.
* Output:
- * return int 0 - OK.
- * 1 - Error.
+ * return int 0 - OK.
+ * 1 - Error.
*/
-static int gl_output_raw_string(GetLine *gl, const char *string)
+static int gl_print_raw_string(GetLine *gl, int buffered,
+ const char *string, int n)
{
- if(gl->echo) {
- int ndone = 0; /* The number of characters written so far */
+ GlWriteFn *write_fn = buffered ? gl_write_fn : gl->flush_fn;
/*
- * How long is the string to be written?
+ * Only display output when echoing is turned on.
*/
- int slen = strlen(string);
+ if(gl->echo) {
+ int ndone = 0; /* The number of characters written so far */
/*
- * Attempt to write the string to the terminal, restarting the
- * write if a signal is caught.
+ * When using un-buffered I/O, flush pending output first.
*/
- while(ndone < slen) {
- int nnew = fwrite(string + ndone, sizeof(char), slen-ndone,
- gl->output_fp);
- if(nnew > 0)
- ndone += nnew;
- else if(errno != EINTR)
+ if(!buffered) {
+ if(gl_flush_output(gl))
return 1;
};
+/*
+ * If no length has been provided, measure the length of the string.
+ */
+ if(n < 0)
+ n = strlen(string);
+/*
+ * Write the string.
+ */
+ if(write_fn(gl, string + ndone, n-ndone) != n)
+ return 1;
};
return 0;
}
@@ -2850,22 +3918,41 @@ static int gl_output_raw_string(GetLine *gl, const char *string)
* return int 0 - OK.
* 1 - Error.
*/
-static int gl_output_control_sequence(GetLine *gl, int nline,
- const char *string)
+static int gl_print_control_sequence(GetLine *gl, int nline, const char *string)
{
+ int waserr = 0; /* True if an error occurs */
+/*
+ * Only write characters to the terminal when echoing is enabled.
+ */
if(gl->echo) {
#if defined(USE_TERMINFO) || defined(USE_TERMCAP)
- tputs_fp = gl->output_fp;
+ tputs_gl = gl;
errno = 0;
tputs((char *)string, nline, gl_tputs_putchar);
- return errno != 0;
+ waserr = errno != 0;
#else
- return gl_output_raw_string(gl, string);
+ waserr = gl_print_raw_string(gl, 1, string, -1);
#endif
};
- return 0;
+ return waserr;
}
+#if defined(USE_TERMINFO) || defined(USE_TERMCAP)
+/*.......................................................................
+ * The following callback function is called by tputs() to output a raw
+ * control character to the terminal.
+ */
+static TputsRetType gl_tputs_putchar(TputsArgType c)
+{
+ char ch = c;
+#if TPUTS_RETURNS_VALUE
+ return gl_print_raw_string(tputs_gl, 1, &ch, 1);
+#else
+ (void) gl_print_raw_string(tputs_gl, 1, &ch, 1);
+#endif
+}
+#endif
+
/*.......................................................................
* Move the terminal cursor n characters to the left or right.
*
@@ -2883,6 +3970,13 @@ static int gl_terminal_move_cursor(GetLine *gl, int n)
int new_row, new_col; /* The target terminal row and column index of */
/* the cursor wrt the start of the input line. */
/*
+ * Do nothing if the input line isn't currently displayed. In this
+ * case, the cursor will be moved to the right place when the line
+ * is next redisplayed.
+ */
+ if(!gl->displayed)
+ return 0;
+/*
* How far can we move left?
*/
if(gl->term_curpos + n < 0)
@@ -2898,14 +3992,14 @@ static int gl_terminal_move_cursor(GetLine *gl, int n)
* Move down to the next line.
*/
for(; cur_row < new_row; cur_row++) {
- if(gl_output_control_sequence(gl, 1, gl->down))
+ if(gl_print_control_sequence(gl, 1, gl->down))
return 1;
};
/*
* Move up to the previous line.
*/
for(; cur_row > new_row; cur_row--) {
- if(gl_output_control_sequence(gl, 1, gl->up))
+ if(gl_print_control_sequence(gl, 1, gl->up))
return 1;
};
/*
@@ -2918,14 +4012,14 @@ static int gl_terminal_move_cursor(GetLine *gl, int n)
* characters (guess based on ANSI terminal termcap entry).
*/
if(gl->right_n != NULL && new_col - cur_col > 1) {
- if(gl_output_control_sequence(gl, 1, tparm((char *)gl->right_n,
+ if(gl_print_control_sequence(gl, 1, tparm((char *)gl->right_n,
(long)(new_col - cur_col), 0l, 0l, 0l, 0l, 0l, 0l, 0l, 0l)))
return 1;
} else
#endif
{
for(; cur_col < new_col; cur_col++) {
- if(gl_output_control_sequence(gl, 1, gl->right))
+ if(gl_print_control_sequence(gl, 1, gl->right))
return 1;
};
};
@@ -2939,14 +4033,14 @@ static int gl_terminal_move_cursor(GetLine *gl, int n)
* characters (guess based on ANSI terminal termcap entry).
*/
if(gl->left_n != NULL && cur_col - new_col > 3) {
- if(gl_output_control_sequence(gl, 1, tparm((char *)gl->left_n,
+ if(gl_print_control_sequence(gl, 1, tparm((char *)gl->left_n,
(long)(cur_col - new_col), 0l, 0l, 0l, 0l, 0l, 0l, 0l, 0l)))
return 1;
} else
#endif
{
for(; cur_col > new_col; cur_col--) {
- if(gl_output_control_sequence(gl, 1, gl->left))
+ if(gl_print_control_sequence(gl, 1, gl->left))
return 1;
};
};
@@ -2980,7 +4074,7 @@ static int gl_terminal_move_cursor(GetLine *gl, int n)
* Output:
* return int 0 - OK.
*/
-static int gl_output_char(GetLine *gl, char c, char pad)
+static int gl_print_char(GetLine *gl, char c, char pad)
{
char string[TAB_WIDTH + 4]; /* A work area for composing compound strings */
int nchar; /* The number of terminal characters */
@@ -2993,7 +4087,7 @@ static int gl_output_char(GetLine *gl, char c, char pad)
* How many spaces do we need to represent a tab at the current terminal
* column?
*/
- nchar = gl_displayed_char_width(gl, '\t', gl->term_curpos);
+ nchar = gl_displayed_tab_width(gl, gl->term_curpos);
/*
* Compose the tab string.
*/
@@ -3017,7 +4111,7 @@ static int gl_output_char(GetLine *gl, char c, char pad)
/*
* Write the string to the terminal.
*/
- if(gl_output_raw_string(gl, string))
+ if(gl_print_raw_string(gl, 1, string, -1))
return 1;
/*
* Except for one exception to be described in a moment, the cursor should
@@ -3025,6 +4119,12 @@ static int gl_output_char(GetLine *gl, char c, char pad)
*/
gl->term_curpos += nchar;
/*
+ * Keep a record of the number of characters in the terminal version
+ * of the input line.
+ */
+ if(gl->term_curpos > gl->term_len)
+ gl->term_len = gl->term_curpos;
+/*
* If the new character ended exactly at the end of a line,
* most terminals won't move the cursor onto the next line until we
* have written a character on the next line, so append an extra
@@ -3032,7 +4132,7 @@ static int gl_output_char(GetLine *gl, char c, char pad)
*/
if(gl->term_curpos % gl->ncolumn == 0) {
int term_curpos = gl->term_curpos;
- if(gl_output_char(gl, pad ? pad : ' ', ' ') ||
+ if(gl_print_char(gl, pad ? pad : ' ', ' ') ||
gl_set_term_curpos(gl, term_curpos))
return 1;
};
@@ -3061,35 +4161,18 @@ static int gl_output_char(GetLine *gl, char c, char pad)
* Output:
* return int 0 - OK.
*/
-static int gl_output_string(GetLine *gl, const char *string, char pad)
+static int gl_print_string(GetLine *gl, const char *string, char pad)
{
const char *cptr; /* A pointer into string[] */
for(cptr=string; *cptr; cptr++) {
char nextc = cptr[1];
- if(gl_output_char(gl, *cptr, nextc ? nextc : pad))
+ if(gl_print_char(gl, *cptr, nextc ? nextc : pad))
return 1;
};
return 0;
}
/*.......................................................................
- * Given a character position within gl->line[], work out the
- * corresponding gl->term_curpos position on the terminal.
- *
- * Input:
- * gl GetLine * The resource object of this library.
- * buff_curpos int The position within gl->line[].
- *
- * Output:
- * return int The gl->term_curpos position on the terminal.
- */
-static int gl_buff_curpos_to_term_curpos(GetLine *gl, int buff_curpos)
-{
- return gl->prompt_len + gl_displayed_string_width(gl, gl->line, buff_curpos,
- gl->prompt_len);
-}
-
-/*.......................................................................
* Move the terminal cursor position.
*
* Input:
@@ -3168,8 +4251,7 @@ static KT_KEY_FN(gl_delete_line)
/*
* Clear the buffer.
*/
- gl->ntotal = 0;
- gl->line[0] = '\0';
+ gl_truncate_buffer(gl, 0);
/*
* Move the terminal cursor to just after the prompt.
*/
@@ -3178,7 +4260,7 @@ static KT_KEY_FN(gl_delete_line)
/*
* Clear from the end of the prompt to the end of the terminal.
*/
- if(gl_output_control_sequence(gl, gl->nline, gl->clear_eod))
+ if(gl_truncate_display(gl))
return 1;
return 0;
}
@@ -3201,12 +4283,11 @@ static KT_KEY_FN(gl_kill_line)
/*
* Terminate the buffered line at the current cursor position.
*/
- gl->ntotal = gl->buff_curpos;
- gl->line[gl->ntotal] = '\0';
+ gl_truncate_buffer(gl, gl->buff_curpos);
/*
* Clear the part of the line that follows the cursor.
*/
- if(gl_output_control_sequence(gl, gl->nline, gl->clear_eod))
+ if(gl_truncate_display(gl))
return 1;
/*
* Explicitly reset the cursor position to allow vi command mode
@@ -3312,9 +4393,10 @@ static int gl_delete_chars(GetLine *gl, int nc, int cut)
/*
* Restore any available characters.
*/
- if(nrestore > 0)
- memcpy(gl->line + gl->buff_curpos, gl->vi.undo.line + gl->buff_curpos,
- nrestore);
+ if(nrestore > 0) {
+ gl_buffer_string(gl, gl->vi.undo.line + gl->buff_curpos, nrestore,
+ gl->buff_curpos);
+ };
/*
* If their were insufficient characters in the undo buffer, then this
* implies that we are deleting from the end of the line, so we need
@@ -3323,27 +4405,24 @@ static int gl_delete_chars(GetLine *gl, int nc, int cut)
* cursor position.
*/
if(nc != nrestore) {
- gl->ntotal = gl->vi.undo.ntotal > gl->buff_curpos ? gl->vi.undo.ntotal :
- gl->buff_curpos;
- gl->line[gl->ntotal] = '\0';
+ gl_truncate_buffer(gl, (gl->vi.undo.ntotal > gl->buff_curpos) ?
+ gl->vi.undo.ntotal : gl->buff_curpos);
};
} else {
/*
* Copy the remaining part of the line back over the deleted characters.
*/
- memmove(gl->line + gl->buff_curpos, gl->line + gl->buff_curpos + nc,
- gl->ntotal - gl->buff_curpos - nc + 1);
- gl->ntotal -= nc;
+ gl_remove_from_buffer(gl, gl->buff_curpos, nc);
};
/*
* Redraw the remaining characters following the cursor.
*/
- if(gl_output_string(gl, gl->line + gl->buff_curpos, '\0'))
+ if(gl_print_string(gl, gl->line + gl->buff_curpos, '\0'))
return 1;
/*
* Clear to the end of the terminal.
*/
- if(gl_output_control_sequence(gl, gl->nline, gl->clear_eod))
+ if(gl_truncate_display(gl))
return 1;
/*
* Place the cursor at the start of where the deletion was performed.
@@ -3380,7 +4459,7 @@ static KT_KEY_FN(gl_backward_delete_char)
* use by vi-undo.
*/
gl_save_for_undo(gl);
- return gl_cursor_left(gl, count) ||
+ return gl_cursor_left(gl, count, NULL) ||
gl_delete_chars(gl, count, gl->vi.command);
}
@@ -3390,9 +4469,9 @@ static KT_KEY_FN(gl_backward_delete_char)
static KT_KEY_FN(gl_delete_to_column)
{
if (--count >= gl->buff_curpos)
- return gl_forward_delete_char(gl, count - gl->buff_curpos);
+ return gl_forward_delete_char(gl, count - gl->buff_curpos, NULL);
else
- return gl_backward_delete_char(gl, gl->buff_curpos - count);
+ return gl_backward_delete_char(gl, gl->buff_curpos - count, NULL);
}
/*.......................................................................
@@ -3405,9 +4484,9 @@ static KT_KEY_FN(gl_delete_to_parenthesis)
if(curpos >= 0) {
gl_save_for_undo(gl);
if(curpos >= gl->buff_curpos)
- return gl_forward_delete_char(gl, curpos - gl->buff_curpos + 1);
+ return gl_forward_delete_char(gl, curpos - gl->buff_curpos + 1, NULL);
else
- return gl_backward_delete_char(gl, ++gl->buff_curpos - curpos + 1);
+ return gl_backward_delete_char(gl, ++gl->buff_curpos - curpos + 1, NULL);
};
return 0;
}
@@ -3455,7 +4534,7 @@ static KT_KEY_FN(gl_backward_delete_word)
/*
* Move back 'count' words.
*/
- if(gl_backward_word(gl, count))
+ if(gl_backward_word(gl, count, NULL))
return 1;
/*
* Delete from the new cursor position to the original one.
@@ -3521,7 +4600,7 @@ static int gl_delete_find(GetLine *gl, int count, char c, int forward,
/*
* If this is a change operation, switch the insert mode.
*/
- if(change && gl_vi_insert(gl, 0))
+ if(change && gl_vi_insert(gl, 0, NULL))
return 1;
return 0;
}
@@ -3601,17 +4680,18 @@ static KT_KEY_FN(gl_upcase_word)
* Upcase characters from the current cursor position to 'last'.
*/
while(gl->buff_curpos <= last) {
- char *cptr = gl->line + gl->buff_curpos++;
+ char *cptr = gl->line + gl->buff_curpos;
/*
* Convert the character to upper case?
*/
if(islower((int)(unsigned char) *cptr))
- *cptr = toupper((int) *cptr);
+ gl_buffer_char(gl, toupper((int) *cptr), gl->buff_curpos);
+ gl->buff_curpos++;
/*
* Write the possibly modified character back. Note that for non-modified
* characters we want to do this as well, so as to advance the cursor.
*/
- if(gl_output_char(gl, *cptr, cptr[1]))
+ if(gl_print_char(gl, *cptr, cptr[1]))
return 1;
};
return gl_place_cursor(gl, gl->buff_curpos); /* bounds check */
@@ -3636,17 +4716,18 @@ static KT_KEY_FN(gl_downcase_word)
* Upcase characters from the current cursor position to 'last'.
*/
while(gl->buff_curpos <= last) {
- char *cptr = gl->line + gl->buff_curpos++;
+ char *cptr = gl->line + gl->buff_curpos;
/*
* Convert the character to upper case?
*/
if(isupper((int)(unsigned char) *cptr))
- *cptr = tolower((int) *cptr);
+ gl_buffer_char(gl, tolower((int) *cptr), gl->buff_curpos);
+ gl->buff_curpos++;
/*
* Write the possibly modified character back. Note that for non-modified
* characters we want to do this as well, so as to advance the cursor.
*/
- if(gl_output_char(gl, *cptr, cptr[1]))
+ if(gl_print_char(gl, *cptr, cptr[1]))
return 1;
};
return gl_place_cursor(gl, gl->buff_curpos); /* bounds check */
@@ -3702,17 +4783,17 @@ static KT_KEY_FN(gl_capitalize_word)
*/
if(first) {
if(islower((int)(unsigned char) *cptr))
- *cptr = toupper((int) *cptr);
+ gl_buffer_char(gl, toupper((int) *cptr), cptr - gl->line);
} else {
if(isupper((int)(unsigned char) *cptr))
- *cptr = tolower((int) *cptr);
+ gl_buffer_char(gl, tolower((int) *cptr), cptr - gl->line);
};
first = 0;
/*
* Write the possibly modified character back. Note that for non-modified
* characters we want to do this as well, so as to advance the cursor.
*/
- if(gl_output_char(gl, *cptr, cptr[1]))
+ if(gl_print_char(gl, *cptr, cptr[1]))
return 1;
};
};
@@ -3733,11 +4814,14 @@ static KT_KEY_FN(gl_redisplay)
*/
int buff_curpos = gl->buff_curpos;
/*
- * Move the cursor to the start of the terminal line, and clear from there
- * to the end of the display.
+ * Do nothing if there is no line to be redisplayed.
+ */
+ if(gl->endline)
+ return 0;
+/*
+ * Erase the current input line.
*/
- if(gl_set_term_curpos(gl, 0) ||
- gl_output_control_sequence(gl, gl->nline, gl->clear_eod))
+ if(gl_erase_line(gl))
return 1;
/*
* Display the current prompt.
@@ -3747,7 +4831,7 @@ static KT_KEY_FN(gl_redisplay)
/*
* Render the part of the line that the user has typed in so far.
*/
- if(gl_output_string(gl, gl->line, '\0'))
+ if(gl_print_string(gl, gl->line, '\0'))
return 1;
/*
* Restore the cursor position.
@@ -3755,6 +4839,10 @@ static KT_KEY_FN(gl_redisplay)
if(gl_place_cursor(gl, buff_curpos))
return 1;
/*
+ * Mark the redisplay operation as having been completed.
+ */
+ gl->redisplay = 0;
+/*
* Flush the redisplayed line to the terminal.
*/
return gl_flush_output(gl);
@@ -3767,26 +4855,20 @@ static KT_KEY_FN(gl_redisplay)
static KT_KEY_FN(gl_clear_screen)
{
/*
- * Record the current cursor position.
- */
- int buff_curpos = gl->buff_curpos;
-/*
* Home the cursor and clear from there to the end of the display.
*/
- if(gl_output_control_sequence(gl, gl->nline, gl->home) ||
- gl_output_control_sequence(gl, gl->nline, gl->clear_eod))
+ if(gl_print_control_sequence(gl, gl->nline, gl->home) ||
+ gl_print_control_sequence(gl, gl->nline, gl->clear_eod))
return 1;
/*
- * Redisplay the line.
+ * The input line is no longer displayed.
*/
- gl->term_curpos = 0;
- gl->buff_curpos = 0;
- if(gl_redisplay(gl,1))
- return 1;
+ gl_line_erased(gl);
/*
- * Restore the cursor position.
+ * Arrange for the input line to be redisplayed.
*/
- return gl_place_cursor(gl, buff_curpos);
+ gl_queue_redisplay(gl);
+ return 0;
}
/*.......................................................................
@@ -3825,8 +4907,8 @@ static KT_KEY_FN(gl_transpose_chars)
/*
* Swap the two characters in the buffer.
*/
- gl->line[gl->buff_curpos] = swap[0];
- gl->line[gl->buff_curpos+1] = swap[1];
+ gl_buffer_char(gl, swap[0], gl->buff_curpos);
+ gl_buffer_char(gl, swap[1], gl->buff_curpos+1);
/*
* If the sum of the displayed width of the two characters
* in their current and final positions is the same, swapping can
@@ -3836,8 +4918,8 @@ static KT_KEY_FN(gl_transpose_chars)
gl_displayed_string_width(gl, swap, -1, gl->term_curpos)) {
int insert = gl->insert;
gl->insert = 0;
- if(gl_output_char(gl, swap[0], swap[1]) ||
- gl_output_char(gl, swap[1], gl->line[gl->buff_curpos+2]))
+ if(gl_print_char(gl, swap[0], swap[1]) ||
+ gl_print_char(gl, swap[1], gl->line[gl->buff_curpos+2]))
return 1;
gl->insert = insert;
/*
@@ -3845,8 +4927,8 @@ static KT_KEY_FN(gl_transpose_chars)
* redraw everything after the first of the characters.
*/
} else {
- if(gl_output_string(gl, gl->line + gl->buff_curpos, '\0') ||
- gl_output_control_sequence(gl, gl->nline, gl->clear_eod))
+ if(gl_print_string(gl, gl->line + gl->buff_curpos, '\0') ||
+ gl_truncate_display(gl))
return 1;
};
/*
@@ -3913,7 +4995,7 @@ static KT_KEY_FN(gl_kill_region)
/*
* If the mark is before the cursor, swap the cursor and the mark.
*/
- if(gl->buff_mark < gl->buff_curpos && gl_exchange_point_and_mark(gl,1))
+ if(gl->buff_mark < gl->buff_curpos && gl_exchange_point_and_mark(gl,1,NULL))
return 1;
/*
* Delete the characters.
@@ -3980,7 +5062,7 @@ static KT_KEY_FN(gl_yank)
* Do nothing else if the cut buffer is empty.
*/
if(gl->cutbuf[0] == '\0')
- return gl_ring_bell(gl, 1);
+ return gl_ring_bell(gl, 1, NULL);
/*
* If in vi command mode, preserve the current line for potential
* use by vi-undo.
@@ -3997,7 +5079,7 @@ static KT_KEY_FN(gl_yank)
* gl_add_string_to_line() leaves the cursor after the last character that
* was pasted, whereas vi leaves the cursor over the last character pasted.
*/
- if(gl->editor == GL_VI_MODE && gl_cursor_left(gl, 1))
+ if(gl->editor == GL_VI_MODE && gl_cursor_left(gl, 1, NULL))
return 1;
return 0;
}
@@ -4014,7 +5096,7 @@ static KT_KEY_FN(gl_append_yank)
* If the cut buffer is empty, ring the terminal bell.
*/
if(gl->cutbuf[0] == '\0')
- return gl_ring_bell(gl, 1);
+ return gl_ring_bell(gl, 1, NULL);
/*
* Set the mark at the current location + 1.
*/
@@ -4027,7 +5109,7 @@ static KT_KEY_FN(gl_append_yank)
/*
* Arrange to paste the text in insert mode after the current character.
*/
- if(gl_vi_append(gl, 0))
+ if(gl_vi_append(gl, 0, NULL))
return 1;
/*
* Insert the string count times.
@@ -4044,73 +5126,104 @@ static KT_KEY_FN(gl_append_yank)
return 0;
}
-#ifdef USE_SIGWINCH
/*.......................................................................
- * Respond to the receipt of a window change signal.
+ * Attempt to ask the terminal for its current size. On systems that
+ * don't support the TIOCWINSZ ioctl() for querying the terminal size,
+ * the current values of gl->ncolumn and gl->nrow are returned.
*
* Input:
- * gl GetLine * The resource object of this library.
- * redisplay int If true redisplay the current line after
- * getting the new window size.
- * Output:
- * return int 0 - OK.
- * 1 - Error.
+ * gl GetLine * The resource object of gl_get_line().
+ * Input/Output:
+ * ncolumn int * The number of columns will be assigned to *ncolumn.
+ * nline int * The number of lines will be assigned to *nline.
*/
-static int gl_resize_terminal(GetLine *gl, int redisplay)
+static void gl_query_size(GetLine *gl, int *ncolumn, int *nline)
{
- int lines_used; /* The number of lines currently in use */
- struct winsize size; /* The new size information */
- int i;
-/*
- * Record the fact that the sigwinch signal has been noted.
- */
- if(gl_pending_signal == SIGWINCH)
- gl_pending_signal = -1;
+#ifdef TIOCGWINSZ
/*
* Query the new terminal window size. Ignore invalid responses.
*/
+ struct winsize size;
if(ioctl(gl->output_fd, TIOCGWINSZ, &size) == 0 &&
size.ws_row > 0 && size.ws_col > 0) {
+ *ncolumn = size.ws_col;
+ *nline = size.ws_row;
+ return;
+ };
+#endif
/*
- * Redisplay the input line?
+ * Return the existing values.
+ */
+ *ncolumn = gl->ncolumn;
+ *nline = gl->nline;
+ return;
+}
+
+/*.......................................................................
+ * Query the size of the terminal, and if it has changed, redraw the
+ * current input line accordingly.
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
*/
- if(redisplay) {
+static int _gl_update_size(GetLine *gl)
+{
+ int ncolumn, nline; /* The new size of the terminal */
/*
- * How many lines are currently displayed.
+ * Query the new terminal window size.
*/
- lines_used = (gl_displayed_string_width(gl,gl->line,-1,gl->prompt_len) +
- gl->prompt_len + gl->ncolumn - 1) / gl->ncolumn;
+ gl_query_size(gl, &ncolumn, &nline);
/*
- * Move to the cursor to the start of the line.
+ * Update gl and the displayed line to fit the new dimensions.
*/
- for(i=1; i<lines_used; i++) {
- if(gl_output_control_sequence(gl, 1, gl->up))
- return 1;
- };
- if(gl_output_control_sequence(gl, 1, gl->bol))
- return 1;
+ return gl_handle_tty_resize(gl, ncolumn, nline);
+}
+
+/*.......................................................................
+ * Redraw the current input line to account for a change in the terminal
+ * size. Also install the new size in gl.
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ * ncolumn int The new number of columns.
+ * nline int The new number of lines.
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+static int gl_handle_tty_resize(GetLine *gl, int ncolumn, int nline)
+{
/*
- * Clear to the end of the terminal.
+ * If the input device isn't a terminal, just record the new size.
*/
- if(gl_output_control_sequence(gl, size.ws_row, gl->clear_eod))
- return 1;
+ if(!gl->is_term) {
+ gl->nline = nline;
+ gl->ncolumn = ncolumn;
/*
- * Record the fact that the cursor is now at the beginning of the line.
+ * Has the size actually changed?
*/
- gl->term_curpos = 0;
- };
+ } else if(ncolumn != gl->ncolumn || nline != gl->nline) {
+/*
+ * If we are currently editing a line, erase it.
+ */
+ if(gl_erase_line(gl))
+ return 1;
/*
* Update the recorded window size.
*/
- gl->nline = size.ws_row;
- gl->ncolumn = size.ws_col;
- };
+ gl->nline = nline;
+ gl->ncolumn = ncolumn;
/*
- * Redisplay the line?
+ * Arrange for the input line to be redrawn before the next character
+ * is read from the terminal.
*/
- return redisplay ? gl_redisplay(gl,1) : 0;
+ gl_queue_redisplay(gl);
+ };
+ return 0;
}
-#endif
/*.......................................................................
* This is the action function that recalls the previous line in the
@@ -4128,31 +5241,38 @@ static KT_KEY_FN(gl_up_history)
*/
gl->preload_id = 0;
/*
+ * Record the key sequence number of this search action.
+ */
+ gl->last_search = gl->keyseq_count;
+/*
* We don't want a search prefix for this function.
*/
- if(_glh_search_prefix(gl->glh, gl->line, 0))
+ if(_glh_search_prefix(gl->glh, gl->line, 0)) {
+ _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
return 1;
+ };
/*
* Recall the count'th next older line in the history list. If the first one
- * fails we can return since nothing has changed otherwise we must continue
+ * fails we can return since nothing has changed, otherwise we must continue
* and update the line state.
*/
- if(_glh_find_backwards(gl->glh, gl->line, gl->linelen) == NULL)
+ if(_glh_find_backwards(gl->glh, gl->line, gl->linelen+1) == NULL)
return 0;
- while(--count && _glh_find_backwards(gl->glh, gl->line, gl->linelen))
+ while(--count && _glh_find_backwards(gl->glh, gl->line, gl->linelen+1))
;
/*
- * Record the number of characters in the new string.
+ * Accomodate the new contents of gl->line[].
*/
- gl->ntotal = strlen(gl->line);
+ gl_update_buffer(gl);
/*
* Arrange to have the cursor placed at the end of the new line.
*/
- gl->buff_curpos = strlen(gl->line);
+ gl->buff_curpos = gl->ntotal;
/*
* Erase and display the new line.
*/
- return gl_redisplay(gl,1);
+ gl_queue_redisplay(gl);
+ return 0;
}
/*.......................................................................
@@ -4167,40 +5287,47 @@ static KT_KEY_FN(gl_down_history)
*/
gl_vi_command_mode(gl);
/*
+ * Record the key sequence number of this search action.
+ */
+ gl->last_search = gl->keyseq_count;
+/*
* If no search is currently in progress continue a previous recall
* session from a previous entered line if possible.
*/
if(_glh_line_id(gl->glh, 0) == 0 && gl->preload_id) {
- _glh_recall_line(gl->glh, gl->preload_id, gl->line, gl->linelen);
+ _glh_recall_line(gl->glh, gl->preload_id, gl->line, gl->linelen+1);
gl->preload_id = 0;
} else {
/*
* We don't want a search prefix for this function.
*/
- if(_glh_search_prefix(gl->glh, gl->line, 0))
+ if(_glh_search_prefix(gl->glh, gl->line, 0)) {
+ _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
return 1;
+ };
/*
* Recall the count'th next newer line in the history list. If the first one
* fails we can return since nothing has changed otherwise we must continue
* and update the line state.
*/
- if(_glh_find_forwards(gl->glh, gl->line, gl->linelen) == NULL)
+ if(_glh_find_forwards(gl->glh, gl->line, gl->linelen+1) == NULL)
return 0;
- while(--count && _glh_find_forwards(gl->glh, gl->line, gl->linelen))
+ while(--count && _glh_find_forwards(gl->glh, gl->line, gl->linelen+1))
;
};
/*
- * Record the number of characters in the new string.
+ * Accomodate the new contents of gl->line[].
*/
- gl->ntotal = strlen(gl->line);
+ gl_update_buffer(gl);
/*
* Arrange to have the cursor placed at the end of the new line.
*/
- gl->buff_curpos = strlen(gl->line);
+ gl->buff_curpos = gl->ntotal;
/*
* Erase and display the new line.
*/
- return gl_redisplay(gl,1);
+ gl_queue_redisplay(gl);
+ return 0;
}
/*.......................................................................
@@ -4221,41 +5348,41 @@ static KT_KEY_FN(gl_history_search_backward)
*/
gl->preload_id = 0;
/*
- * If the previous thing that the user did wasn't to execute a history
- * search function, set the search prefix equal to the string that
- * precedes the cursor. In vi command mode include the character that
- * is under the cursor in the string. If count<0 force a repeat search
- * even if the last command wasn't a history command.
+ * Record the key sequence number of this search action.
*/
- if(gl->last_search != gl->keyseq_count - 1 && count>=0 &&
- _glh_search_prefix(gl->glh, gl->line, gl->buff_curpos +
- (gl->editor==GL_VI_MODE && gl->ntotal>0)))
- return 1;
+ gl->last_search = gl->keyseq_count;
/*
- * Record the key sequence number in which this search function is
- * being executed, so that the next call to this function or
- * gl_history_search_forward() knows if any other operations
- * were performed in between.
+ * If a prefix search isn't already in progress, replace the search
+ * prefix to the string that precedes the cursor. In vi command mode
+ * include the character that is under the cursor in the string. If
+ * count<0 keep the previous search prefix regardless, so as to force
+ * a repeat search even if the last command wasn't a history command.
*/
- gl->last_search = gl->keyseq_count;
+ if(count >= 0 && !_glh_search_active(gl->glh) &&
+ _glh_search_prefix(gl->glh, gl->line, gl->buff_curpos +
+ (gl->editor==GL_VI_MODE && gl->ntotal>0))) {
+ _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
+ return 1;
+ };
/*
* Search backwards for a match to the part of the line which precedes the
* cursor.
*/
- if(_glh_find_backwards(gl->glh, gl->line, gl->linelen) == NULL)
+ if(_glh_find_backwards(gl->glh, gl->line, gl->linelen+1) == NULL)
return 0;
/*
- * Record the number of characters in the new string.
+ * Accomodate the new contents of gl->line[].
*/
- gl->ntotal = strlen(gl->line);
+ gl_update_buffer(gl);
/*
* Arrange to have the cursor placed at the end of the new line.
*/
- gl->buff_curpos = strlen(gl->line);
+ gl->buff_curpos = gl->ntotal;
/*
* Erase and display the new line.
*/
- return gl_redisplay(gl,1);
+ gl_queue_redisplay(gl);
+ return 0;
}
/*.......................................................................
@@ -4265,7 +5392,7 @@ static KT_KEY_FN(gl_history_search_backward)
*/
static KT_KEY_FN(gl_history_re_search_backward)
{
- return gl_history_search_backward(gl, -1);
+ return gl_history_search_backward(gl, -1, NULL);
}
/*.......................................................................
@@ -4283,40 +5410,40 @@ static KT_KEY_FN(gl_history_search_forward)
*/
gl_vi_command_mode(gl);
/*
- * If the previous thing that the user did wasn't to execute a history
- * search function, set the search prefix equal to the string that
- * precedes the cursor. In vi command mode include the character that
- * is under the cursor in the string. If count<0 force a repeat search
- * even if the last command wasn't a history command.
+ * Record the key sequence number of this search action.
*/
- if(gl->last_search != gl->keyseq_count - 1 && count>=0 &&
- _glh_search_prefix(gl->glh, gl->line, gl->buff_curpos +
- (gl->editor==GL_VI_MODE && gl->ntotal>0)))
- return 1;
+ gl->last_search = gl->keyseq_count;
/*
- * Record the key sequence number in which this search function is
- * being executed, so that the next call to this function or
- * gl_history_search_backward() knows if any other operations
- * were performed in between.
+ * If a prefix search isn't already in progress, replace the search
+ * prefix to the string that precedes the cursor. In vi command mode
+ * include the character that is under the cursor in the string. If
+ * count<0 keep the previous search prefix regardless, so as to force
+ * a repeat search even if the last command wasn't a history command.
*/
- gl->last_search = gl->keyseq_count;
+ if(count >= 0 && !_glh_search_active(gl->glh) &&
+ _glh_search_prefix(gl->glh, gl->line, gl->buff_curpos +
+ (gl->editor==GL_VI_MODE && gl->ntotal>0))) {
+ _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
+ return 1;
+ };
/*
* Search forwards for the next matching line.
*/
- if(_glh_find_forwards(gl->glh, gl->line, gl->linelen) == NULL)
+ if(_glh_find_forwards(gl->glh, gl->line, gl->linelen+1) == NULL)
return 0;
/*
- * Record the number of characters in the new string.
+ * Accomodate the new contents of gl->line[].
*/
- gl->ntotal = strlen(gl->line);
+ gl_update_buffer(gl);
/*
* Arrange for the cursor to be placed at the end of the new line.
*/
- gl->buff_curpos = strlen(gl->line);
+ gl->buff_curpos = gl->ntotal;
/*
* Erase and display the new line.
*/
- return gl_redisplay(gl,1);
+ gl_queue_redisplay(gl);
+ return 0;
}
/*.......................................................................
@@ -4326,29 +5453,46 @@ static KT_KEY_FN(gl_history_search_forward)
*/
static KT_KEY_FN(gl_history_re_search_forward)
{
- return gl_history_search_forward(gl, -1);
+ return gl_history_search_forward(gl, -1, NULL);
}
+#ifdef HIDE_FILE_SYSTEM
+/*.......................................................................
+ * The following function is used as the default completion handler when
+ * the filesystem is to be hidden. It simply reports no completions.
+ */
+static CPL_MATCH_FN(gl_no_completions)
+{
+ return 0;
+}
+#endif
+
/*.......................................................................
* This is the tab completion function that completes the filename that
- * precedes the cursor position.
+ * precedes the cursor position. Its callback data argument must be a
+ * pointer to a GlCplCallback containing the completion callback function
+ * and its callback data, or NULL to use the builtin filename completer.
*/
static KT_KEY_FN(gl_complete_word)
{
CplMatches *matches; /* The possible completions */
- int redisplay=0; /* True if the whole line needs to be redrawn */
int suffix_len; /* The length of the completion extension */
int cont_len; /* The length of any continuation suffix */
int nextra; /* The number of characters being added to the */
/* total length of the line. */
int buff_pos; /* The buffer index at which the completion is */
/* to be inserted. */
+ int waserr = 0; /* True after errors */
+/*
+ * Get the container of the completion callback and its callback data.
+ */
+ GlCplCallback *cb = data ? (GlCplCallback *) data : &gl->cplfn;
/*
- * In vi command mode, switch to append mode so that the character below
- * the character is included in the completion (otherwise people can't
+ * In vi command mode, switch to append mode so that the character under
+ * the cursor is included in the completion (otherwise people can't
* complete at the end of the line).
*/
- if(gl->vi.command && gl_vi_append(gl, 0))
+ if(gl->vi.command && gl_vi_append(gl, 0, NULL))
return 1;
/*
* Get the cursor position at which the completion is to be inserted.
@@ -4357,14 +5501,13 @@ static KT_KEY_FN(gl_complete_word)
/*
* Perform the completion.
*/
- matches = cpl_complete_word(gl->cpl, gl->line, gl->buff_curpos, gl->cpl_data,
- gl->cpl_fn);
+ matches = cpl_complete_word(gl->cpl, gl->line, gl->buff_curpos, cb->data,
+ cb->fn);
+/*
+ * No matching completions?
+ */
if(!matches) {
- if(gl->echo &&
- fprintf(gl->output_fp, "\r\n%s\n", cpl_last_error(gl->cpl)) < 0)
- return 1;
- gl->term_curpos = 0;
- redisplay = 1;
+ waserr = gl_print_info(gl, cpl_last_error(gl->cpl), GL_END_INFO);
/*
* Are there any completions?
*/
@@ -4373,18 +5516,11 @@ static KT_KEY_FN(gl_complete_word)
* If there any ambiguous matches, report them, starting on a new line.
*/
if(matches->nmatch > 1 && gl->echo) {
- if(fprintf(gl->output_fp, "\r\n") < 0)
- return 1;
- cpl_list_completions(matches, gl->output_fp, gl->ncolumn);
- redisplay = 1;
+ if(_gl_normal_io(gl) ||
+ _cpl_output_completions(matches, gl_write_fn, gl, gl->ncolumn))
+ waserr = 1;
};
/*
- * If the callback called gl_change_prompt(), we will need to redisplay
- * the whole line.
- */
- if(gl->prompt_changed)
- redisplay = 1;
-/*
* Get the length of the suffix and any continuation suffix to add to it.
*/
suffix_len = strlen(matches->suffix);
@@ -4397,8 +5533,8 @@ static KT_KEY_FN(gl_complete_word)
if(matches->nmatch==1 && cont_len > 0 &&
matches->cont_suffix[cont_len - 1] == '\n') {
cont_len--;
- if(gl_newline(gl, 1))
- return 1;
+ if(gl_newline(gl, 1, NULL))
+ waserr = 1;
};
/*
* Work out the number of characters that are to be added.
@@ -4407,7 +5543,7 @@ static KT_KEY_FN(gl_complete_word)
/*
* Is there anything to be added?
*/
- if(nextra) {
+ if(!waserr && nextra) {
/*
* Will there be space for the expansion in the line buffer?
*/
@@ -4415,58 +5551,50 @@ static KT_KEY_FN(gl_complete_word)
/*
* Make room to insert the filename extension.
*/
- memmove(gl->line + gl->buff_curpos + nextra, gl->line + gl->buff_curpos,
- gl->ntotal - gl->buff_curpos);
+ gl_make_gap_in_buffer(gl, gl->buff_curpos, nextra);
/*
* Insert the filename extension.
*/
- memcpy(gl->line + gl->buff_curpos, matches->suffix, suffix_len);
+ gl_buffer_string(gl, matches->suffix, suffix_len, gl->buff_curpos);
/*
* Add the terminating characters.
*/
- memcpy(gl->line + gl->buff_curpos + suffix_len, matches->cont_suffix,
- cont_len);
-/*
- * Record the increased length of the line.
- */
- gl->ntotal += nextra;
+ gl_buffer_string(gl, matches->cont_suffix, cont_len,
+ gl->buff_curpos + suffix_len);
/*
* Place the cursor position at the end of the completion.
*/
gl->buff_curpos += nextra;
/*
- * Terminate the extended line.
- */
- gl->line[gl->ntotal] = '\0';
-/*
* If we don't have to redisplay the whole line, redisplay the part
* of the line which follows the original cursor position, and place
* the cursor at the end of the completion.
*/
- if(!redisplay) {
- if(gl_output_control_sequence(gl, gl->nline, gl->clear_eod) ||
- gl_output_string(gl, gl->line + buff_pos, '\0') ||
+ if(gl->displayed) {
+ if(gl_truncate_display(gl) ||
+ gl_print_string(gl, gl->line + buff_pos, '\0') ||
gl_place_cursor(gl, gl->buff_curpos))
- return 1;
+ waserr = 1;
};
} else {
- fprintf(stderr,
- "\r\nInsufficient room in line for file completion.\r\n");
- redisplay = 1;
+ (void) gl_print_info(gl,
+ "Insufficient room in line for file completion.",
+ GL_END_INFO);
+ waserr = 1;
};
};
};
/*
- * Redisplay the whole line?
+ * If any output had to be written to the terminal, then editing will
+ * have been suspended, make sure that we are back in raw line editing
+ * mode before returning.
*/
- if(redisplay) {
- gl->term_curpos = 0;
- if(gl_redisplay(gl,1))
- return 1;
- };
+ if(_gl_raw_io(gl, 1))
+ waserr = 1;
return 0;
}
+#ifndef HIDE_FILE_SYSTEM
/*.......................................................................
* This is the function that expands the filename that precedes the
* cursor position. It expands ~user/ expressions, $envvar expressions,
@@ -4478,23 +5606,21 @@ static KT_KEY_FN(gl_expand_filename)
/* gl->line[]. */
FileExpansion *result; /* The results of the filename expansion */
int pathlen; /* The length of the pathname being expanded */
- int redisplay=0; /* True if the whole line needs to be redrawn */
int length; /* The number of characters needed to display the */
/* expanded files. */
int nextra; /* The number of characters to be added */
int i,j;
/*
- * In vi command mode, switch to append mode so that the character below
- * the character is included in the completion (otherwise people can't
+ * In vi command mode, switch to append mode so that the character under
+ * the cursor is included in the completion (otherwise people can't
* complete at the end of the line).
*/
- if(gl->vi.command && gl_vi_append(gl, 0))
+ if(gl->vi.command && gl_vi_append(gl, 0, NULL))
return 1;
/*
* Locate the start of the filename that precedes the cursor position.
*/
- start_path = _pu_start_of_path(gl->line,
- gl->buff_curpos > 0 ? gl->buff_curpos : 0);
+ start_path = _pu_start_of_path(gl->line, gl->buff_curpos);
if(!start_path)
return 1;
/*
@@ -4506,25 +5632,15 @@ static KT_KEY_FN(gl_expand_filename)
*/
result = ef_expand_file(gl->ef, start_path, pathlen);
/*
- * If there was an error, report the error on a new line, then redraw
- * the original line.
+ * If there was an error, report the error on a new line.
*/
- if(!result) {
- if(gl->echo &&
- fprintf(gl->output_fp, "\r\n%s\n", ef_last_error(gl->ef)) < 0)
- return 1;
- gl->term_curpos = 0;
- return gl_redisplay(gl,1);
- };
+ if(!result)
+ return gl_print_info(gl, ef_last_error(gl->ef), GL_END_INFO);
/*
* If no files matched, report this as well.
*/
- if(result->nfile == 0 || !result->exists) {
- if(gl->echo && fprintf(gl->output_fp, "\r\nNo files match.\n") < 0)
- return 1;
- gl->term_curpos = 0;
- return gl_redisplay(gl,1);
- };
+ if(result->nfile == 0 || !result->exists)
+ return gl_print_info(gl, "No files match.", GL_END_INFO);
/*
* If in vi command mode, preserve the current line for potential use by
* vi-undo.
@@ -4557,16 +5673,18 @@ static KT_KEY_FN(gl_expand_filename)
* Will there be space for the expansion in the line buffer?
*/
if(gl->ntotal + nextra >= gl->linelen) {
- fprintf(stderr, "\r\nInsufficient room in line for file expansion.\r\n");
- redisplay = 1;
+ return gl_print_info(gl, "Insufficient room in line for file expansion.",
+ GL_END_INFO);
} else {
/*
* Do we need to move the part of the line that followed the unexpanded
* filename?
*/
- if(nextra != 0) {
- memmove(gl->line + gl->buff_curpos + nextra, gl->line + gl->buff_curpos,
- gl->ntotal - gl->buff_curpos);
+ if(nextra > 0) {
+ gl_make_gap_in_buffer(gl, gl->buff_curpos, nextra);
+ } else if(nextra < 0) {
+ gl->buff_curpos += nextra;
+ gl_remove_from_buffer(gl, gl->buff_curpos, -nextra);
};
/*
* Insert the filenames, separated by spaces, and with internal spaces,
@@ -4578,46 +5696,29 @@ static KT_KEY_FN(gl_expand_filename)
int c = *file++;
switch(c) {
case ' ': case '\t': case '\\': case '*': case '?': case '[':
- gl->line[j++] = '\\';
+ gl_buffer_char(gl, '\\', j++);
};
- gl->line[j++] = c;
+ gl_buffer_char(gl, c, j++);
};
- gl->line[j++] = ' ';
+ gl_buffer_char(gl, ' ', j++);
};
-/*
- * Record the increased length of the line.
- */
- gl->ntotal += nextra;
-/*
- * Place the cursor position at the end of the expansion.
- */
- gl->buff_curpos += nextra;
-/*
- * Terminate the extended line.
- */
- gl->line[gl->ntotal] = '\0';
};
/*
- * Display the whole line on a new line?
- */
- if(redisplay) {
- gl->term_curpos = 0;
- return gl_redisplay(gl,1);
- };
-/*
- * Otherwise redisplay the part of the line which follows the start of
+ * Redisplay the part of the line which follows the start of
* the original filename.
*/
- if(gl_set_term_curpos(gl, gl_buff_curpos_to_term_curpos(gl, start_path - gl->line)) ||
- gl_output_control_sequence(gl, gl->nline, gl->clear_eod) ||
- gl_output_string(gl, start_path, gl->line[gl->buff_curpos]))
+ if(gl_place_cursor(gl, start_path - gl->line) ||
+ gl_truncate_display(gl) ||
+ gl_print_string(gl, start_path, start_path[length]))
return 1;
/*
- * Restore the cursor position to the end of the expansion.
+ * Move the cursor to the end of the expansion.
*/
- return gl_place_cursor(gl, gl->buff_curpos);
+ return gl_place_cursor(gl, (start_path - gl->line) + length);
}
+#endif
+#ifndef HIDE_FILE_SYSTEM
/*.......................................................................
* This is the action function that lists glob expansions of the
* filename that precedes the cursor position. It expands ~user/
@@ -4632,8 +5733,7 @@ static KT_KEY_FN(gl_list_glob)
/*
* Locate the start of the filename that precedes the cursor position.
*/
- start_path = _pu_start_of_path(gl->line,
- gl->buff_curpos > 0 ? gl->buff_curpos : 0);
+ start_path = _pu_start_of_path(gl->line, gl->buff_curpos);
if(!start_path)
return 1;
/*
@@ -4645,32 +5745,27 @@ static KT_KEY_FN(gl_list_glob)
*/
result = ef_expand_file(gl->ef, start_path, pathlen);
/*
- * If there was an error, report the error.
+ * If there was an error, report it.
*/
if(!result) {
- if(gl->echo &&
- fprintf(gl->output_fp, "\r\n%s\n", ef_last_error(gl->ef)) < 0)
- return 1;
+ return gl_print_info(gl, ef_last_error(gl->ef), GL_END_INFO);
/*
* If no files matched, report this as well.
*/
} else if(result->nfile == 0 || !result->exists) {
- if(gl->echo && fprintf(gl->output_fp, "\r\nNo files match.\n") < 0)
- return 1;
+ return gl_print_info(gl, "No files match.", GL_END_INFO);
/*
* List the matching expansions.
*/
} else if(gl->echo) {
- if(fprintf(gl->output_fp, "\r\n") < 0)
+ if(gl_start_newline(gl, 1) ||
+ _ef_output_expansions(result, gl_write_fn, gl, gl->ncolumn))
return 1;
- ef_list_expansions(result, gl->output_fp, gl->ncolumn);
+ gl_queue_redisplay(gl);
};
-/*
- * Redisplay the line being edited.
- */
- gl->term_curpos = 0;
- return gl_redisplay(gl,1);
+ return 0;
}
+#endif
/*.......................................................................
* Return non-zero if a character should be considered a part of a word.
@@ -4705,18 +5800,29 @@ static int gl_is_word_char(int c)
*/
int gl_customize_completion(GetLine *gl, void *data, CplMatchFn *match_fn)
{
+ sigset_t oldset; /* The signals that were blocked on entry to this function */
/*
* Check the arguments.
*/
if(!gl || !match_fn) {
- fprintf(stderr, "gl_customize_completion: NULL argument(s).\n");
+ if(gl)
+ _err_record_msg(gl->err, "NULL argument", END_ERR_MSG);
+ errno = EINVAL;
return 1;
};
/*
+ * Temporarily block all signals.
+ */
+ gl_mask_signals(gl, &oldset);
+/*
* Record the new completion function and its callback data.
*/
- gl->cpl_fn = match_fn;
- gl->cpl_data = data;
+ gl->cplfn.fn = match_fn;
+ gl->cplfn.data = data;
+/*
+ * Restore the process signal mask before returning.
+ */
+ gl_unmask_signals(gl, &oldset);
return 0;
}
@@ -4739,23 +5845,66 @@ int gl_customize_completion(GetLine *gl, void *data, CplMatchFn *match_fn)
int gl_change_terminal(GetLine *gl, FILE *input_fp, FILE *output_fp,
const char *term)
{
+ sigset_t oldset; /* The signals that were blocked on entry to this function */
+ int status; /* The return status of _gl_change_terminal() */
+/*
+ * Check the arguments.
+ */
+ if(!gl) {
+ errno = EINVAL;
+ return 1;
+ };
+/*
+ * Block all signals.
+ */
+ if(gl_mask_signals(gl, &oldset))
+ return 1;
+/*
+ * Execute the private body of the function while signals are blocked.
+ */
+ status = _gl_change_terminal(gl, input_fp, output_fp, term);
+/*
+ * Restore the process signal mask.
+ */
+ gl_unmask_signals(gl, &oldset);
+ return status;
+}
+
+/*.......................................................................
+ * This is the private body of the gl_change_terminal() function. It
+ * assumes that the caller has checked its arguments and blocked the
+ * delivery of signals.
+ */
+static int _gl_change_terminal(GetLine *gl, FILE *input_fp, FILE *output_fp,
+ const char *term)
+{
int is_term = 0; /* True if both input_fd and output_fd are associated */
/* with a terminal. */
/*
* Require that input_fp and output_fp both be valid.
*/
if(!input_fp || !output_fp) {
- fprintf(stderr, "\r\ngl_change_terminal: Bad input/output stream(s).\n");
+ gl_print_info(gl, "Can't change terminal. Bad input/output stream(s).",
+ GL_END_INFO);
return 1;
};
/*
- * If we are displacing a previous terminal, remove it from the list
- * of fds being watched.
+ * Are we displacing an existing terminal (as opposed to setting the
+ * initial terminal)?
+ */
+ if(gl->input_fd >= 0) {
+/*
+ * Make sure to leave the previous terminal in a usable state.
+ */
+ if(_gl_normal_io(gl))
+ return 1;
+/*
+ * Remove the displaced terminal from the list of fds to watch.
*/
#ifdef HAVE_SELECT
- if(gl->input_fd >= 0)
FD_CLR(gl->input_fd, &gl->rfds);
#endif
+ };
/*
* Record the file descriptors and streams.
*/
@@ -4764,11 +5913,10 @@ int gl_change_terminal(GetLine *gl, FILE *input_fp, FILE *output_fp,
gl->output_fp = output_fp;
gl->output_fd = fileno(output_fp);
/*
- * Make sure that the file descriptor will be visible in the set to
- * be watched.
+ * If needed, expand the record of the maximum file-descriptor that might
+ * need to be monitored with select().
*/
#ifdef HAVE_SELECT
- FD_SET(gl->input_fd, &gl->rfds);
if(gl->input_fd > gl->max_fd)
gl->max_fd = gl->input_fd;
#endif
@@ -4780,9 +5928,12 @@ int gl_change_terminal(GetLine *gl, FILE *input_fp, FILE *output_fp,
/*
* For terminal editing, we need both output_fd and input_fd to refer to
* a terminal. While we can't verify that they both point to the same
- * terminal, we can verify that they point to terminals.
+ * terminal, we can verify that they point to terminals. If the user
+ * sets the TERM environment variable to "dumb", treat a terminal as
+ * a non-interactive I/O stream.
*/
- is_term = isatty(gl->input_fd) && isatty(gl->output_fd);
+ is_term = (isatty(gl->input_fd) && isatty(gl->output_fd)) &&
+ !(term && strcmp(term, "dumb")==0);
/*
* If we are interacting with a terminal and no terminal type has been
* specified, treat it as a generic ANSI terminal.
@@ -4822,25 +5973,36 @@ int gl_change_terminal(GetLine *gl, FILE *input_fp, FILE *output_fp,
* Get the current settings of the terminal.
*/
if(tcgetattr(gl->input_fd, &gl->oldattr)) {
- fprintf(stderr, "\r\ngl_change_terminal: tcgetattr error: %s\n",
- strerror(errno));
+ _err_record_msg(gl->err, "tcgetattr error", END_ERR_MSG);
return 1;
};
/*
- * Lookup the terminal control string and size information.
+ * If we don't set this now, gl_control_strings() won't know
+ * that it is talking to a terminal.
*/
- if(gl_control_strings(gl, term))
- return 1;
+ gl->is_term = 1;
/*
- * We now have enough info to interact with the terminal.
+ * Lookup the terminal control string and size information.
*/
- gl->is_term = 1;
+ if(gl_control_strings(gl, term)) {
+ gl->is_term = 0;
+ return 1;
+ };
/*
* Bind terminal-specific keys.
*/
if(gl_bind_terminal_keys(gl))
return 1;
};
+/*
+ * Assume that the caller has given us a terminal in a sane state.
+ */
+ gl->io_mode = GL_NORMAL_MODE;
+/*
+ * Switch into the currently configured I/O mode.
+ */
+ if(_gl_io_mode(gl, gl->io_mode))
+ return 1;
return 0;
}
@@ -4885,8 +6047,10 @@ static int gl_bind_terminal_keys(GetLine *gl)
"literal-next"))
return 1;
#else
- if(_kt_set_keybinding(gl->bindings, KTB_TERM, "^V", "literal-next"))
+ if(_kt_set_keybinding(gl->bindings, KTB_TERM, "^V", "literal-next")) {
+ _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG);
return 1;
+ };
#endif
/*
* Bind action functions to the terminal-specific arrow keys
@@ -4910,33 +6074,13 @@ static KT_KEY_FN(gl_del_char_or_list_or_eof)
* If we have an empty line arrange to return EOF.
*/
if(gl->ntotal < 1) {
+ gl_record_status(gl, GLR_EOF, 0);
return 1;
/*
* If we are at the end of the line list possible completions.
*/
} else if(gl->buff_curpos >= gl->ntotal) {
-/*
- * Get the list of possible completions.
- */
- CplMatches *matches = cpl_complete_word(gl->cpl, gl->line, gl->buff_curpos,
- gl->cpl_data, gl->cpl_fn);
- if(!matches) {
- if(gl->echo &&
- fprintf(gl->output_fp, "\r\n%s\n", cpl_last_error(gl->cpl)) < 0)
- return 1;
- gl->term_curpos = 0;
-/*
- * List the matches.
- */
- } else if(matches->nmatch > 0 && gl->echo) {
- if(fprintf(gl->output_fp, "\r\n") < 0)
- return 1;
- cpl_list_completions(matches, gl->output_fp, gl->ncolumn);
- };
-/*
- * Redisplay the line unchanged.
- */
- return gl_redisplay(gl,1);
+ return gl_list_completions(gl, 1, NULL);
/*
* Within the line delete the character that follows the cursor.
*/
@@ -4949,7 +6093,7 @@ static KT_KEY_FN(gl_del_char_or_list_or_eof)
/*
* Delete 'count' characters.
*/
- return gl_forward_delete_char(gl, count);
+ return gl_forward_delete_char(gl, count, NULL);
};
}
@@ -4965,34 +6109,55 @@ static KT_KEY_FN(gl_list_or_eof)
* If we have an empty line arrange to return EOF.
*/
if(gl->ntotal < 1) {
+ gl_record_status(gl, GLR_EOF, 0);
return 1;
/*
* Otherwise list possible completions.
*/
} else {
+ return gl_list_completions(gl, 1, NULL);
+ };
+}
+
+/*.......................................................................
+ * List possible completions of the word that precedes the cursor. The
+ * callback data argument must either be NULL to select the default
+ * file completion callback, or be a GlCplCallback object containing the
+ * completion callback function to call.
+ */
+static KT_KEY_FN(gl_list_completions)
+{
+ int waserr = 0; /* True after errors */
+/*
+ * Get the container of the completion callback and its callback data.
+ */
+ GlCplCallback *cb = data ? (GlCplCallback *) data : &gl->cplfn;
/*
* Get the list of possible completions.
*/
- CplMatches *matches = cpl_complete_word(gl->cpl, gl->line, gl->buff_curpos,
- gl->cpl_data, gl->cpl_fn);
- if(!matches) {
- if(gl->echo &&
- fprintf(gl->output_fp, "\r\n%s\n", cpl_last_error(gl->cpl)) < 0)
- return 1;
- gl->term_curpos = 0;
+ CplMatches *matches = cpl_complete_word(gl->cpl, gl->line, gl->buff_curpos,
+ cb->data, cb->fn);
/*
- * List the matches.
+ * No matching completions?
*/
- } else if(matches->nmatch > 0 && gl->echo) {
- if(fprintf(gl->output_fp, "\r\n") < 0)
- return 1;
- cpl_list_completions(matches, gl->output_fp, gl->ncolumn);
- };
+ if(!matches) {
+ waserr = gl_print_info(gl, cpl_last_error(gl->cpl), GL_END_INFO);
/*
- * Redisplay the line unchanged.
+ * List the matches.
*/
- return gl_redisplay(gl,1);
+ } else if(matches->nmatch > 0 && gl->echo) {
+ if(_gl_normal_io(gl) ||
+ _cpl_output_completions(matches, gl_write_fn, gl, gl->ncolumn))
+ waserr = 1;
};
+/*
+ * If any output had to be written to the terminal, then editing will
+ * have been suspended, make sure that we are back in raw line editing
+ * mode before returning.
+ */
+ if(_gl_raw_io(gl, 1))
+ waserr = 1;
+ return waserr;
}
/*.......................................................................
@@ -5011,10 +6176,10 @@ static int _gl_bind_arrow_keys(GetLine *gl)
/*
* Process each of the arrow keys.
*/
- if(_gl_rebind_arrow_key(gl->bindings, "up", gl->u_arrow, "^[[A", "^[OA") ||
- _gl_rebind_arrow_key(gl->bindings, "down", gl->d_arrow, "^[[B", "^[OB") ||
- _gl_rebind_arrow_key(gl->bindings, "left", gl->l_arrow, "^[[D", "^[OD") ||
- _gl_rebind_arrow_key(gl->bindings, "right", gl->r_arrow, "^[[C", "^[OC"))
+ if(_gl_rebind_arrow_key(gl, "up", gl->u_arrow, "^[[A", "^[OA") ||
+ _gl_rebind_arrow_key(gl, "down", gl->d_arrow, "^[[B", "^[OB") ||
+ _gl_rebind_arrow_key(gl, "left", gl->l_arrow, "^[[D", "^[OD") ||
+ _gl_rebind_arrow_key(gl, "right", gl->r_arrow, "^[[C", "^[OC"))
return 1;
return 0;
}
@@ -5030,7 +6195,7 @@ static int _gl_bind_arrow_keys(GetLine *gl)
* of default key sequences.
*
* Input:
- * bindings KeyTab * The table of key bindings.
+ * gl GetLine * The resource object of gl_get_line().
* name char * The symbolic name of the arrow key.
* term_seq char * The terminal-specific arrow-key sequence.
* def_seq1 char * The first default arrow-key sequence.
@@ -5039,28 +6204,36 @@ static int _gl_bind_arrow_keys(GetLine *gl)
* return int 0 - OK.
* 1 - Error.
*/
-static int _gl_rebind_arrow_key(KeyTab *bindings, const char *name,
+static int _gl_rebind_arrow_key(GetLine *gl, const char *name,
const char *term_seq, const char *def_seq1,
const char *def_seq2)
{
- int first,last; /* The indexes of the first and last matching entries */
+ KeySym *keysym; /* The binding-table entry matching the arrow-key name */
+ int nsym; /* The number of ambiguous matches */
/*
* Lookup the key binding for the symbolic name of the arrow key. This
* will either be the default action, or a user provided one.
*/
- if(_kt_lookup_keybinding(bindings, name, strlen(name), &first, &last)
+ if(_kt_lookup_keybinding(gl->bindings, name, strlen(name), &keysym, &nsym)
== KT_EXACT_MATCH) {
/*
* Get the action function.
*/
- KtKeyFn *key_fn = bindings->table[first].keyfn;
+ KtAction *action = keysym->actions + keysym->binder;
+ KtKeyFn *fn = action->fn;
+ void *data = action->data;
/*
* Bind this to each of the specified key sequences.
*/
- if((term_seq && _kt_set_keyfn(bindings, KTB_TERM, term_seq, key_fn)) ||
- (def_seq1 && _kt_set_keyfn(bindings, KTB_NORM, def_seq1, key_fn)) ||
- (def_seq2 && _kt_set_keyfn(bindings, KTB_NORM, def_seq2, key_fn)))
+ if((term_seq &&
+ _kt_set_keyfn(gl->bindings, KTB_TERM, term_seq, fn, data)) ||
+ (def_seq1 &&
+ _kt_set_keyfn(gl->bindings, KTB_NORM, def_seq1, fn, data)) ||
+ (def_seq2 &&
+ _kt_set_keyfn(gl->bindings, KTB_NORM, def_seq2, fn, data))) {
+ _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG);
return 1;
+ };
};
return 0;
}
@@ -5082,6 +6255,17 @@ static int _gl_rebind_arrow_key(KeyTab *bindings, const char *name,
*/
static int _gl_read_config_file(GetLine *gl, const char *filename, KtBinder who)
{
+/*
+ * If filesystem access is to be excluded, configuration files can't
+ * be read.
+ */
+#ifdef WITHOUT_FILE_SYSTEM
+ _err_record_msg(gl->err,
+ "Can't read configuration files without filesystem access",
+ END_ERR_MSG);
+ errno = EINVAL;
+ return 1;
+#else
FileExpansion *expansion; /* The expansion of the filename */
FILE *fp; /* The opened file */
int waserr = 0; /* True if an error occurred while reading */
@@ -5090,7 +6274,9 @@ static int _gl_read_config_file(GetLine *gl, const char *filename, KtBinder who)
* Check the arguments.
*/
if(!gl || !filename) {
- fprintf(stderr, "_gl_read_config_file: Invalid arguments.\n");
+ if(gl)
+ _err_record_msg(gl->err, "NULL argument(s)", END_ERR_MSG);
+ errno = EINVAL;
return 1;
};
/*
@@ -5098,8 +6284,8 @@ static int _gl_read_config_file(GetLine *gl, const char *filename, KtBinder who)
*/
expansion = ef_expand_file(gl->ef, filename, -1);
if(!expansion) {
- fprintf(stderr, "Unable to expand %s (%s).\n", filename,
- ef_last_error(gl->ef));
+ gl_print_info(gl, "Unable to expand ", filename, " (",
+ ef_last_error(gl->ef), ").", GL_END_INFO);
return 1;
};
/*
@@ -5127,6 +6313,7 @@ static int _gl_read_config_file(GetLine *gl, const char *filename, KtBinder who)
*/
(void) fclose(fp);
return waserr;
+#endif
}
/*.......................................................................
@@ -5143,7 +6330,9 @@ static int _gl_read_config_string(GetLine *gl, const char *buffer, KtBinder who)
* Check the arguments.
*/
if(!gl || !buffer) {
- fprintf(stderr, "_gl_read_config_string: Invalid arguments.\n");
+ if(gl)
+ _err_record_msg(gl->err, "NULL argument(s)", END_ERR_MSG);
+ errno = EINVAL;
return 1;
};
/*
@@ -5242,8 +6431,8 @@ static int _gl_parse_config_line(GetLine *gl, void *stream, GlcGetcFn *getc_fn,
* Start recording the next argument.
*/
if(argc >= GL_CONF_MAXARG) {
- fprintf(stderr, "%s:%d: Too many arguments.\n", origin, *lineno);
- do c = getc_fn(stream); while(c != '\n' && c != EOF); /* Skip past eol */
+ gl_report_config_error(gl, origin, *lineno, "Too many arguments.");
+ do c = getc_fn(stream); while(c!='\n' && c!=EOF); /* Skip past eol */
return 0;
};
argv[argc] = buffer + i;
@@ -5284,7 +6473,7 @@ static int _gl_parse_config_line(GetLine *gl, void *stream, GlcGetcFn *getc_fn,
* Did the buffer overflow?
*/
if(i>=GL_CONF_BUFLEN) {
- fprintf(stderr, "%s:%d: Line too long.\n", origin, *lineno);
+ gl_report_config_error(gl, origin, *lineno, "Line too long.");
return 0;
};
/*
@@ -5302,12 +6491,12 @@ static int _gl_parse_config_line(GetLine *gl, void *stream, GlcGetcFn *getc_fn,
* Attempt to record the new keybinding.
*/
if(_kt_set_keybinding(gl->bindings, who, keyseq, action)) {
- fprintf(stderr, "The error occurred at line %d of %s.\n", *lineno,
- origin);
+ gl_report_config_error(gl, origin, *lineno,
+ _kt_last_error(gl->bindings));
};
break;
default:
- fprintf(stderr, "%s:%d: Wrong number of arguments.\n", origin, *lineno);
+ gl_report_config_error(gl, origin, *lineno, "Wrong number of arguments.");
};
} else if(strcmp(argv[0], "edit-mode") == 0) {
if(argc == 2 && strcmp(argv[1], "emacs") == 0) {
@@ -5317,14 +6506,13 @@ static int _gl_parse_config_line(GetLine *gl, void *stream, GlcGetcFn *getc_fn,
} else if(argc == 2 && strcmp(argv[1], "none") == 0) {
gl_change_editor(gl, GL_NO_EDITOR);
} else {
- fprintf(stderr, "%s:%d: The argument of editor should be vi or emacs.\n",
- origin, *lineno);
+ gl_report_config_error(gl, origin, *lineno,
+ "The argument of editor should be vi or emacs.");
};
} else if(strcmp(argv[0], "nobeep") == 0) {
gl->silence_bell = 1;
} else {
- fprintf(stderr, "%s:%d: Unknown command name '%s'.\n", origin, *lineno,
- argv[0]);
+ gl_report_config_error(gl, origin, *lineno, "Unknown command name.");
};
/*
* Skip any trailing comment.
@@ -5336,6 +6524,35 @@ static int _gl_parse_config_line(GetLine *gl, void *stream, GlcGetcFn *getc_fn,
}
/*.......................................................................
+ * This is a private function of _gl_parse_config_line() which prints
+ * out an error message about the contents of the line, prefixed by the
+ * name of the origin of the line and its line number.
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ * origin const char * The name of the entity being read (eg. a
+ * file name).
+ * lineno int The line number at which the error occurred.
+ * errmsg const char * The error message.
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+static int gl_report_config_error(GetLine *gl, const char *origin, int lineno,
+ const char *errmsg)
+{
+ char lnum[20]; /* A buffer in which to render a single integer */
+/*
+ * Convert the line number into a string.
+ */
+ sprintf(lnum, "%d", lineno);
+/*
+ * Have the string printed on the terminal.
+ */
+ return gl_print_info(gl, origin, ":", lnum, ": ", errmsg, GL_END_INFO);
+}
+
+/*.......................................................................
* This is the _gl_parse_config_line() callback function which reads the
* next character from a configuration file.
*/
@@ -5355,6 +6572,7 @@ static GLC_GETC_FN(glc_buff_getc)
return **lptr ? *(*lptr)++ : EOF;
}
+#ifndef HIDE_FILE_SYSTEM
/*.......................................................................
* When this action is triggered, it arranges to temporarily read command
* lines from the regular file whos name precedes the cursor.
@@ -5366,12 +6584,10 @@ static KT_KEY_FN(gl_read_from_file)
/* gl->line[]. */
FileExpansion *result; /* The results of the filename expansion */
int pathlen; /* The length of the pathname being expanded */
- int error_reported = 0; /* True after an error has been reported */
/*
* Locate the start of the filename that precedes the cursor position.
*/
- start_path = _pu_start_of_path(gl->line,
- gl->buff_curpos > 0 ? gl->buff_curpos : 0);
+ start_path = _pu_start_of_path(gl->line, gl->buff_curpos);
if(!start_path)
return 1;
/*
@@ -5383,29 +6599,20 @@ static KT_KEY_FN(gl_read_from_file)
*/
result = ef_expand_file(gl->ef, start_path, pathlen);
/*
- * If there was an error, report the error on a new line, then redraw
- * the original line.
+ * If there was an error, report the error on a new line.
*/
if(!result) {
- if(gl->echo &&
- fprintf(gl->output_fp, "\r\n%s\n", ef_last_error(gl->ef)) < 0)
- return 1;
- error_reported = 1;
+ return gl_print_info(gl, ef_last_error(gl->ef), GL_END_INFO);
/*
* If no files matched, report this as well.
*/
} else if(result->nfile == 0 || !result->exists) {
- if(gl->echo && fprintf(gl->output_fp, "\r\nNo files match.\n") < 0)
- return 1;
- error_reported = 1;
+ return gl_print_info(gl, "No files match.", GL_END_INFO);
/*
* Complain if more than one file matches.
*/
} else if(result->nfile > 1) {
- if(gl->echo &&
- fprintf(gl->output_fp, "\r\nMore than one file matches.\n") < 0)
- return 1;
- error_reported = 1;
+ return gl_print_info(gl, "More than one file matches.", GL_END_INFO);
/*
* Disallow input from anything but normal files. In principle we could
* also support input from named pipes. Terminal files would be a problem
@@ -5413,36 +6620,43 @@ static KT_KEY_FN(gl_read_from_file)
* might cause the library to lock up.
*/
} else if(!_pu_path_is_file(result->files[0])) {
- if(gl->echo && fprintf(gl->output_fp, "\r\nNot a normal file.\n") < 0)
- return 1;
- error_reported = 1;
+ return gl_print_info(gl, "Not a normal file.", GL_END_INFO);
} else {
/*
* Attempt to open and install the specified file for reading.
*/
gl->file_fp = fopen(result->files[0], "r");
if(!gl->file_fp) {
- if(gl->echo && fprintf(gl->output_fp, "\r\nUnable to open: %s\n",
- result->files[0]) < 0)
- return 1;
- error_reported = 1;
+ return gl_print_info(gl, "Unable to open: ", result->files[0],
+ GL_END_INFO);
};
/*
- * Inform the user what is happening.
+ * If needed, expand the record of the maximum file-descriptor that might
+ * need to be monitored with select().
*/
- if(gl->echo && fprintf(gl->output_fp, "\r\n<Taking input from %s>\n",
- result->files[0]) < 0)
- return 1;
- };
+#ifdef HAVE_SELECT
+ if(fileno(gl->file_fp) > gl->max_fd)
+ gl->max_fd = fileno(gl->file_fp);
+#endif
/*
- * If an error was reported, redisplay the current line.
+ * Is non-blocking I/O needed?
*/
- if(error_reported) {
- gl->term_curpos = 0;
- return gl_redisplay(gl,1);
+ if(gl->raw_mode && gl->io_mode==GL_SERVER_MODE &&
+ gl_nonblocking_io(gl, fileno(gl->file_fp))) {
+ gl_revert_input(gl);
+ return gl_print_info(gl, "Can't read file %s with non-blocking I/O",
+ result->files[0]);
+ };
+/*
+ * Inform the user what is happening.
+ */
+ if(gl_print_info(gl, "<Taking input from ", result->files[0], ">",
+ GL_END_INFO))
+ return 1;
};
return 0;
}
+#endif
/*.......................................................................
* Close any temporary file that is being used for input.
@@ -5455,6 +6669,7 @@ static void gl_revert_input(GetLine *gl)
if(gl->file_fp)
fclose(gl->file_fp);
gl->file_fp = NULL;
+ gl->endline = 1;
}
/*.......................................................................
@@ -5473,22 +6688,27 @@ static KT_KEY_FN(gl_beginning_of_history)
*/
gl->preload_id = 0;
/*
+ * Record the key sequence number of this search action.
+ */
+ gl->last_search = gl->keyseq_count;
+/*
* Recall the next oldest line in the history list.
*/
- if(_glh_oldest_line(gl->glh, gl->line, gl->linelen) == NULL)
+ if(_glh_oldest_line(gl->glh, gl->line, gl->linelen+1) == NULL)
return 0;
/*
- * Record the number of characters in the new string.
+ * Accomodate the new contents of gl->line[].
*/
- gl->ntotal = strlen(gl->line);
+ gl_update_buffer(gl);
/*
* Arrange to have the cursor placed at the end of the new line.
*/
- gl->buff_curpos = strlen(gl->line);
+ gl->buff_curpos = gl->ntotal;
/*
* Erase and display the new line.
*/
- return gl_redisplay(gl,1);
+ gl_queue_redisplay(gl);
+ return 0;
}
/*.......................................................................
@@ -5508,22 +6728,27 @@ static KT_KEY_FN(gl_end_of_history)
*/
gl->preload_id = 0;
/*
+ * Record the key sequence number of this search action.
+ */
+ gl->last_search = gl->keyseq_count;
+/*
* Recall the next oldest line in the history list.
*/
- if(_glh_current_line(gl->glh, gl->line, gl->linelen) == NULL)
+ if(_glh_current_line(gl->glh, gl->line, gl->linelen+1) == NULL)
return 0;
/*
- * Record the number of characters in the new string.
+ * Accomodate the new contents of gl->line[].
*/
- gl->ntotal = strlen(gl->line);
+ gl_update_buffer(gl);
/*
* Arrange to have the cursor placed at the end of the new line.
*/
- gl->buff_curpos = strlen(gl->line);
+ gl->buff_curpos = gl->ntotal;
/*
* Erase and display the new line.
*/
- return gl_redisplay(gl,1);
+ gl_queue_redisplay(gl);
+ return 0;
}
/*.......................................................................
@@ -5542,7 +6767,7 @@ static KT_KEY_FN(gl_digit_argument)
* In vi command mode, a lone '0' means goto-start-of-line.
*/
if(gl->vi.command && gl->number < 0 && count == '0')
- return gl_beginning_of_line(gl, count);
+ return gl_beginning_of_line(gl, count, NULL);
/*
* Are we starting to accumulate a new number?
*/
@@ -5608,19 +6833,92 @@ static KT_KEY_FN(gl_repeat_history)
* gl GetLine * The getline resource object.
* Output:
* return int 0 - OK.
- * 1 - Error.
+ * 1 - Either an error occured, or the output
+ * blocked and non-blocking I/O is being used.
+ * See gl->rtn_status for details.
*/
static int gl_flush_output(GetLine *gl)
{
/*
- * Attempt to flush output to the terminal, restarting the output
- * if a signal is caught.
+ * Record the fact that we are about to write to the terminal.
*/
- while(fflush(gl->output_fp) != 0) {
- if(errno!=EINTR)
- return 1;
+ gl->pending_io = GLP_WRITE;
+/*
+ * Attempt to flush the output to the terminal.
+ */
+ errno = 0;
+ switch(_glq_flush_queue(gl->cq, gl->flush_fn, gl)) {
+ case GLQ_FLUSH_DONE:
+ return gl->redisplay && !gl->postpone && gl_redisplay(gl, 1, NULL);
+ break;
+ case GLQ_FLUSH_AGAIN: /* Output blocked */
+ gl_record_status(gl, GLR_BLOCKED, BLOCKED_ERRNO);
+ return 1;
+ break;
+ default: /* Abort the line if an error occurs */
+ gl_record_status(gl, errno==EINTR ? GLR_SIGNAL : GLR_ERROR, errno);
+ return 1;
+ break;
};
- return 0;
+}
+
+/*.......................................................................
+ * This is the callback which _glq_flush_queue() uses to write buffered
+ * characters to the terminal.
+ */
+static GL_WRITE_FN(gl_flush_terminal)
+{
+ int ndone = 0; /* The number of characters written so far */
+/*
+ * Get the line-editor resource object.
+ */
+ GetLine *gl = (GetLine *) data;
+/*
+ * Transfer the latest array of characters to stdio.
+ */
+ while(ndone < n) {
+ int nnew = write(gl->output_fd, s, n-ndone);
+/*
+ * If the write was successful, add to the recorded number of bytes
+ * that have now been written.
+ */
+ if(nnew > 0) {
+ ndone += nnew;
+/*
+ * If a signal interrupted the call, restart the write(), since all of
+ * the signals that gl_get_line() has been told to watch for are
+ * currently blocked.
+ */
+ } else if(errno == EINTR) {
+ continue;
+/*
+ * If we managed to write something before an I/O error occurred, or
+ * output blocked before anything was written, report the number of
+ * bytes that were successfully written before this happened.
+ */
+ } else if(ndone > 0
+#if defined(EAGAIN)
+ || errno==EAGAIN
+#endif
+#if defined(EWOULDBLOCK)
+ || errno==EWOULDBLOCK
+#endif
+ ) {
+ return ndone;
+
+/*
+ * To get here, an error must have occurred before anything new could
+ * be written.
+ */
+ } else {
+ return -1;
+ };
+ };
+/*
+ * To get here, we must have successfully written the number of
+ * bytes that was specified.
+ */
+ return n;
}
/*.......................................................................
@@ -5654,7 +6952,8 @@ static int gl_change_editor(GetLine *gl, GlEditor editor)
case GL_NO_EDITOR:
break;
default:
- fprintf(stderr, "gl_change_editor: Unknown editor.\n");
+ _err_record_msg(gl->err, "Unknown editor", END_ERR_MSG);
+ errno = EINVAL;
return 1;
};
/*
@@ -5754,14 +7053,14 @@ static KT_KEY_FN(gl_change_case)
* Convert the character to upper case?
*/
if(islower((int)(unsigned char) *cptr))
- *cptr = toupper((int) *cptr);
+ gl_buffer_char(gl, toupper((int) *cptr), cptr - gl->line);
else if(isupper((int)(unsigned char) *cptr))
- *cptr = tolower((int) *cptr);
+ gl_buffer_char(gl, tolower((int) *cptr), cptr - gl->line);
/*
* Write the possibly modified character back. Note that for non-modified
* characters we want to do this as well, so as to advance the cursor.
*/
- if(gl_output_char(gl, *cptr, cptr[1]))
+ if(gl_print_char(gl, *cptr, cptr[1]))
return 1;
};
/*
@@ -5778,8 +7077,8 @@ static KT_KEY_FN(gl_change_case)
static KT_KEY_FN(gl_vi_insert_at_bol)
{
gl_save_for_undo(gl);
- return gl_beginning_of_line(gl, 0) ||
- gl_vi_insert(gl, 0);
+ return gl_beginning_of_line(gl, 0, NULL) ||
+ gl_vi_insert(gl, 0, NULL);
}
@@ -5792,8 +7091,8 @@ static KT_KEY_FN(gl_vi_append_at_eol)
{
gl_save_for_undo(gl);
gl->vi.command = 0; /* Allow cursor at EOL */
- return gl_end_of_line(gl, 0) ||
- gl_vi_insert(gl, 0);
+ return gl_end_of_line(gl, 0, NULL) ||
+ gl_vi_insert(gl, 0, NULL);
}
/*.......................................................................
@@ -5805,8 +7104,8 @@ static KT_KEY_FN(gl_vi_append)
{
gl_save_for_undo(gl);
gl->vi.command = 0; /* Allow cursor at EOL */
- return gl_cursor_right(gl, 1) ||
- gl_vi_insert(gl, 0);
+ return gl_cursor_right(gl, 1, NULL) ||
+ gl_vi_insert(gl, 0, NULL);
}
/*.......................................................................
@@ -5836,7 +7135,7 @@ static KT_KEY_FN(gl_vi_replace_char)
if(gl->vi.repeat.active) {
c = gl->vi.repeat.input_char;
} else {
- if(gl_read_character(gl, &c))
+ if(gl_read_terminal(gl, 1, &c))
return 1;
gl->vi.repeat.input_char = c;
};
@@ -5875,7 +7174,7 @@ static KT_KEY_FN(gl_vi_change_rest_of_line)
{
gl_save_for_undo(gl);
gl->vi.command = 0; /* Allow cursor at EOL */
- return gl_kill_line(gl, count) || gl_vi_insert(gl, 0);
+ return gl_kill_line(gl, count, NULL) || gl_vi_insert(gl, 0, NULL);
}
/*.......................................................................
@@ -5884,7 +7183,7 @@ static KT_KEY_FN(gl_vi_change_rest_of_line)
*/
static KT_KEY_FN(gl_vi_change_to_bol)
{
- return gl_backward_kill_line(gl, count) || gl_vi_insert(gl, 0);
+ return gl_backward_kill_line(gl,count,NULL) || gl_vi_insert(gl,0,NULL);
}
/*.......................................................................
@@ -5893,7 +7192,7 @@ static KT_KEY_FN(gl_vi_change_to_bol)
*/
static KT_KEY_FN(gl_vi_change_line)
{
- return gl_delete_line(gl, count) || gl_vi_insert(gl, 0);
+ return gl_delete_line(gl,count,NULL) || gl_vi_insert(gl,0,NULL);
}
/*.......................................................................
@@ -5947,9 +7246,9 @@ static KT_KEY_FN(gl_backward_copy_char)
static KT_KEY_FN(gl_copy_to_column)
{
if (--count >= gl->buff_curpos)
- return gl_forward_copy_char(gl, count - gl->buff_curpos);
+ return gl_forward_copy_char(gl, count - gl->buff_curpos, NULL);
else
- return gl_backward_copy_char(gl, gl->buff_curpos - count);
+ return gl_backward_copy_char(gl, gl->buff_curpos - count, NULL);
}
/*.......................................................................
@@ -5962,9 +7261,9 @@ static KT_KEY_FN(gl_copy_to_parenthesis)
if(curpos >= 0) {
gl_save_for_undo(gl);
if(curpos >= gl->buff_curpos)
- return gl_forward_copy_char(gl, curpos - gl->buff_curpos + 1);
+ return gl_forward_copy_char(gl, curpos - gl->buff_curpos + 1, NULL);
else
- return gl_backward_copy_char(gl, ++gl->buff_curpos - curpos + 1);
+ return gl_backward_copy_char(gl, ++gl->buff_curpos - curpos + 1, NULL);
};
return 0;
}
@@ -6083,7 +7382,7 @@ static int gl_find_char(GetLine *gl, int count, int forward, int onto, char c)
if(gl->vi.repeat.active) {
c = gl->vi.find_char;
} else {
- if(gl_read_character(gl, &c))
+ if(gl_read_terminal(gl, 1, &c))
return -1;
/*
* Record the details of the new search, for use by repeat finds.
@@ -6152,7 +7451,7 @@ static int gl_find_char(GetLine *gl, int count, int forward, int onto, char c)
if(pos >= gl->insert_curpos && pos < gl->ntotal) {
return pos;
} else {
- (void) gl_ring_bell(gl, 1);
+ (void) gl_ring_bell(gl, 1, NULL);
return -1;
}
}
@@ -6496,7 +7795,8 @@ static int gl_place_cursor(GetLine *gl, int buff_curpos)
/*
* Move the terminal cursor to the corresponding character.
*/
- return gl_set_term_curpos(gl, gl_buff_curpos_to_term_curpos(gl, buff_curpos));
+ return gl_set_term_curpos(gl, gl->prompt_len +
+ gl_displayed_string_width(gl, gl->line, buff_curpos, gl->prompt_len));
}
/*.......................................................................
@@ -6519,8 +7819,8 @@ static void gl_save_for_undo(GetLine *gl)
gl->vi.undo.saved = 1;
};
if(gl->vi.command && !gl->vi.repeat.saved &&
- gl->current_fn != gl_vi_repeat_change) {
- gl->vi.repeat.fn = gl->current_fn;
+ gl->current_action.fn != gl_vi_repeat_change) {
+ gl->vi.repeat.action = gl->current_action;
gl->vi.repeat.count = gl->current_count;
gl->vi.repeat.saved = 1;
};
@@ -6559,13 +7859,13 @@ static KT_KEY_FN(gl_vi_undo)
*undo_ptr = '\0';
};
/*
- * Swap the length information.
+ * Record the length of the stored string.
*/
- {
- int ntotal = gl->ntotal;
- gl->ntotal = gl->vi.undo.ntotal;
- gl->vi.undo.ntotal = ntotal;
- };
+ gl->vi.undo.ntotal = gl->ntotal;
+/*
+ * Accomodate the new contents of gl->line[].
+ */
+ gl_update_buffer(gl);
/*
* Set both cursor positions to the leftmost of the saved and current
* cursor positions to emulate what vi does.
@@ -6578,12 +7878,14 @@ static KT_KEY_FN(gl_vi_undo)
* Since we have bipassed calling gl_save_for_undo(), record repeat
* information inline.
*/
- gl->vi.repeat.fn = gl_vi_undo;
+ gl->vi.repeat.action.fn = gl_vi_undo;
+ gl->vi.repeat.action.data = NULL;
gl->vi.repeat.count = 1;
/*
* Display the restored line.
*/
- return gl_redisplay(gl,1);
+ gl_queue_redisplay(gl);
+ return 0;
}
/*.......................................................................
@@ -6593,7 +7895,7 @@ static KT_KEY_FN(gl_vi_forward_change_word)
{
gl_save_for_undo(gl);
gl->vi.command = 0; /* Allow cursor at EOL */
- return gl_forward_delete_word(gl, count) || gl_vi_insert(gl, 0);
+ return gl_forward_delete_word(gl, count, NULL) || gl_vi_insert(gl, 0, NULL);
}
/*.......................................................................
@@ -6601,7 +7903,7 @@ static KT_KEY_FN(gl_vi_forward_change_word)
*/
static KT_KEY_FN(gl_vi_backward_change_word)
{
- return gl_backward_delete_word(gl, count) || gl_vi_insert(gl, 0);
+ return gl_backward_delete_word(gl, count, NULL) || gl_vi_insert(gl, 0, NULL);
}
/*.......................................................................
@@ -6663,7 +7965,7 @@ static KT_KEY_FN(gl_vi_forward_change_char)
{
gl_save_for_undo(gl);
gl->vi.command = 0; /* Allow cursor at EOL */
- return gl_delete_chars(gl, count, 1) || gl_vi_insert(gl, 0);
+ return gl_delete_chars(gl, count, 1) || gl_vi_insert(gl, 0, NULL);
}
/*.......................................................................
@@ -6671,7 +7973,7 @@ static KT_KEY_FN(gl_vi_forward_change_char)
*/
static KT_KEY_FN(gl_vi_backward_change_char)
{
- return gl_backward_delete_char(gl, count) || gl_vi_insert(gl, 0);
+ return gl_backward_delete_char(gl, count, NULL) || gl_vi_insert(gl, 0, NULL);
}
/*.......................................................................
@@ -6680,9 +7982,9 @@ static KT_KEY_FN(gl_vi_backward_change_char)
static KT_KEY_FN(gl_vi_change_to_column)
{
if (--count >= gl->buff_curpos)
- return gl_vi_forward_change_char(gl, count - gl->buff_curpos);
+ return gl_vi_forward_change_char(gl, count - gl->buff_curpos, NULL);
else
- return gl_vi_backward_change_char(gl, gl->buff_curpos - count);
+ return gl_vi_backward_change_char(gl, gl->buff_curpos - count, NULL);
}
/*.......................................................................
@@ -6695,9 +7997,10 @@ static KT_KEY_FN(gl_vi_change_to_parenthesis)
if(curpos >= 0) {
gl_save_for_undo(gl);
if(curpos >= gl->buff_curpos)
- return gl_vi_forward_change_char(gl, curpos - gl->buff_curpos + 1);
+ return gl_vi_forward_change_char(gl, curpos - gl->buff_curpos + 1, NULL);
else
- return gl_vi_backward_change_char(gl, ++gl->buff_curpos - curpos + 1);
+ return gl_vi_backward_change_char(gl, ++gl->buff_curpos - curpos + 1,
+ NULL);
};
return 0;
}
@@ -6715,8 +8018,8 @@ static void gl_vi_command_mode(GetLine *gl)
gl->vi.command = 1;
gl->vi.repeat.input_curpos = gl->insert_curpos;
gl->vi.repeat.command_curpos = gl->buff_curpos;
- gl->insert_curpos = 0; /* unrestrict left motion boundary */
- gl_cursor_left(gl, 1); /* Vi moves left one on entering command mode */
+ gl->insert_curpos = 0; /* unrestrict left motion boundary */
+ gl_cursor_left(gl, 1, NULL); /* Vi moves 1 left on entering command mode */
};
}
@@ -6726,7 +8029,7 @@ static void gl_vi_command_mode(GetLine *gl)
static KT_KEY_FN(gl_ring_bell)
{
return gl->silence_bell ? 0 :
- gl_output_control_sequence(gl, 1, gl->sound_bell);
+ gl_print_control_sequence(gl, 1, gl->sound_bell);
}
/*.......................................................................
@@ -6740,8 +8043,8 @@ static KT_KEY_FN(gl_vi_repeat_change)
/*
* Nothing to repeat?
*/
- if(!gl->vi.repeat.fn)
- return gl_ring_bell(gl, 1);
+ if(!gl->vi.repeat.action.fn)
+ return gl_ring_bell(gl, 1, NULL);
/*
* Provide a way for action functions to know whether they are being
* called by us.
@@ -6750,7 +8053,8 @@ static KT_KEY_FN(gl_vi_repeat_change)
/*
* Re-run the recorded function.
*/
- status = gl->vi.repeat.fn(gl, gl->vi.repeat.count);
+ status = gl->vi.repeat.action.fn(gl, gl->vi.repeat.count,
+ gl->vi.repeat.action.data);
/*
* Mark the repeat as completed.
*/
@@ -6854,7 +8158,7 @@ static int gl_index_of_matching_paren(GetLine *gl)
/*
* Not found.
*/
- (void) gl_ring_bell(gl, 1);
+ (void) gl_ring_bell(gl, 1, NULL);
return -1;
}
@@ -6883,7 +8187,6 @@ static KT_KEY_FN(gl_find_parenthesis)
*/
static int gl_interpret_char(GetLine *gl, char first_char)
{
- KtKeyFn *keyfn; /* An action function */
char keyseq[GL_KEY_MAX+1]; /* A special key sequence being read */
int nkey=0; /* The number of characters in the key sequence */
int count; /* The repeat count of an action function */
@@ -6894,28 +8197,30 @@ static int gl_interpret_char(GetLine *gl, char first_char)
*/
char c = first_char;
/*
- * If editting is disabled, just add newly entered characters to the
+ * If editing is disabled, just add newly entered characters to the
* input line buffer, and watch for the end of the line.
*/
if(gl->editor == GL_NO_EDITOR) {
+ gl_discard_chars(gl, 1);
if(gl->ntotal >= gl->linelen)
return 0;
if(c == '\n' || c == '\r')
- return gl_newline(gl, 1);
- gl->line[gl->ntotal++] = c;
+ return gl_newline(gl, 1, NULL);
+ gl_buffer_char(gl, c, gl->ntotal);
return 0;
};
/*
* If the user is in the process of specifying a repeat count and the
* new character is a digit, increment the repeat count accordingly.
*/
- if(gl->number >= 0 && isdigit((int)(unsigned char) c))
- return gl_digit_argument(gl, c);
+ if(gl->number >= 0 && isdigit((int)(unsigned char) c)) {
+ gl_discard_chars(gl, 1);
+ return gl_digit_argument(gl, c, NULL);
/*
* In vi command mode, all key-sequences entered need to be
* either implicitly or explicitly prefixed with an escape character.
*/
- else if(gl->vi.command && c != GL_ESC_CHAR)
+ } else if(gl->vi.command && c != GL_ESC_CHAR) {
keyseq[nkey++] = GL_ESC_CHAR;
/*
* If the first character of the sequence is a printable character,
@@ -6923,13 +8228,16 @@ static int gl_interpret_char(GetLine *gl, char first_char)
* or "right" cursor key bindings, we need to prefix the
* printable character with a backslash escape before looking it up.
*/
- else if(!IS_META_CHAR(c) && !IS_CTRL_CHAR(c))
+ } else if(!IS_META_CHAR(c) && !IS_CTRL_CHAR(c)) {
keyseq[nkey++] = '\\';
+ };
/*
* Compose a potentially multiple key-sequence in gl->keyseq.
*/
while(nkey < GL_KEY_MAX) {
- int first, last; /* The matching entries in gl->keys */
+ KtAction *action; /* An action function */
+ KeySym *keysym; /* The symbol-table entry of a key-sequence */
+ int nsym; /* The number of ambiguously matching key-sequences */
/*
* If the character is an unprintable meta character, split it
* into two characters, an escape character and the character
@@ -6953,17 +8261,17 @@ static int gl_interpret_char(GetLine *gl, char first_char)
/*
* Lookup the key sequence.
*/
- switch(_kt_lookup_keybinding(gl->bindings, keyseq, nkey, &first, &last)) {
+ switch(_kt_lookup_keybinding(gl->bindings, keyseq, nkey, &keysym, &nsym)) {
case KT_EXACT_MATCH:
/*
* Get the matching action function.
*/
- keyfn = gl->bindings->table[first].keyfn;
+ action = keysym->actions + keysym->binder;
/*
* Get the repeat count, passing the last keystroke if executing the
* digit-argument action.
*/
- if(keyfn == gl_digit_argument) {
+ if(action->fn == gl_digit_argument) {
count = c;
} else {
count = gl->number >= 0 ? gl->number : 1;
@@ -6971,7 +8279,7 @@ static int gl_interpret_char(GetLine *gl, char first_char)
/*
* Record the function that is being invoked.
*/
- gl->current_fn = keyfn;
+ gl->current_action = *action;
gl->current_count = count;
/*
* Mark the current line as not yet preserved for use by the vi undo command.
@@ -6984,19 +8292,35 @@ static int gl_interpret_char(GetLine *gl, char first_char)
* explicitly by looking at whether gl->number is -1 or not. If
* it is negative, then no repeat count was specified by the user.
*/
- ret = keyfn(gl, count);
+ ret = action->fn(gl, count, action->data);
/*
- * Reset the repeat count after running action functions (other
- * than digit-argument).
+ * In server mode, the action will return immediately if it tries to
+ * read input from the terminal, and no input is currently available.
+ * If this happens, abort. Note that gl_get_input_line() will rewind
+ * the read-ahead buffer to allow the next call to redo the function
+ * from scratch.
*/
- if(keyfn != gl_digit_argument)
- gl->number = -1;
- if(ret)
+ if(gl->rtn_status == GLR_BLOCKED && gl->pending_io==GLP_READ)
return 1;
- return 0;
+/*
+ * Discard the now processed characters from the key sequence buffer.
+ */
+ gl_discard_chars(gl, gl->nread);
+/*
+ * If the latest action function wasn't a history action, cancel any
+ * current history search.
+ */
+ if(gl->last_search != gl->keyseq_count)
+ _glh_cancel_search(gl->glh);
+/*
+ * Reset the repeat count after running action functions.
+ */
+ if(action->fn != gl_digit_argument)
+ gl->number = -1;
+ return ret ? 1 : 0;
break;
- case KT_AMBIG_MATCH: /* Ambiguous match - so look ahead */
- if(gl_read_character(gl, &c)) /* Get the next character */
+ case KT_AMBIG_MATCH: /* Ambiguous match - so read the next character */
+ if(gl_read_terminal(gl, 1, &c))
return 1;
break;
case KT_NO_MATCH:
@@ -7006,7 +8330,7 @@ static int gl_interpret_char(GetLine *gl, char first_char)
* wasn't recognised.
*/
if(keyseq[0] != '\\' && keyseq[0] != '\t') {
- gl_ring_bell(gl, 0);
+ gl_ring_bell(gl, 1, NULL);
} else {
/*
* The user typed a single printable character that doesn't match
@@ -7018,16 +8342,27 @@ static int gl_interpret_char(GetLine *gl, char first_char)
gl_add_char_to_line(gl, first_char);
gl->number = -1;
};
+ gl_discard_chars(gl, 1);
+ _glh_cancel_search(gl->glh);
return 0;
break;
case KT_BAD_MATCH:
+ gl_ring_bell(gl, 1, NULL);
+ gl_discard_chars(gl, gl->nread);
+ _glh_cancel_search(gl->glh);
return 1;
break;
};
};
/*
- * Key sequence too long to match.
+ * If the key sequence was too long to match, ring the bell, then
+ * discard the first character, so that the next attempt to match a
+ * key-sequence continues with the next key press. In practice this
+ * shouldn't happen, since one isn't allowed to bind action functions
+ * to keysequences that are longer than GL_KEY_MAX.
*/
+ gl_ring_bell(gl, 1, NULL);
+ gl_discard_chars(gl, 1);
return 0;
}
@@ -7036,7 +8371,7 @@ static int gl_interpret_char(GetLine *gl, char first_char)
* gl_get_line().
*
* Note that calling this function between calling new_GetLine() and
- * the first call to new_GetLine(), disables the otherwise automatic
+ * the first call to gl_get_line(), disables the otherwise automatic
* reading of ~/.teclarc on the first call to gl_get_line().
*
* Input:
@@ -7063,14 +8398,40 @@ static int gl_interpret_char(GetLine *gl, char first_char)
int gl_configure_getline(GetLine *gl, const char *app_string,
const char *app_file, const char *user_file)
{
+ sigset_t oldset; /* The signals that were blocked on entry to this function */
+ int status; /* The return status of _gl_configure_getline() */
/*
* Check the arguments.
*/
if(!gl) {
- fprintf(stderr, "gl_configure_getline: NULL gl argument.\n");
+ errno = EINVAL;
return 1;
};
/*
+ * Block all signals.
+ */
+ if(gl_mask_signals(gl, &oldset))
+ return 1;
+/*
+ * Execute the private body of the function while signals are blocked.
+ */
+ status = _gl_configure_getline(gl, app_string, app_file, user_file);
+/*
+ * Restore the process signal mask.
+ */
+ gl_unmask_signals(gl, &oldset);
+ return status;
+}
+
+/*.......................................................................
+ * This is the private body of the gl_configure_getline() function. It
+ * assumes that the caller has checked its arguments and blocked the
+ * delivery of signals.
+ */
+static int _gl_configure_getline(GetLine *gl, const char *app_string,
+ const char *app_file, const char *user_file)
+{
+/*
* Mark getline as having been explicitly configured.
*/
gl->configured = 1;
@@ -7095,8 +8456,10 @@ int gl_configure_getline(GetLine *gl, const char *app_string,
*/
if(gl_record_string(&gl->app_file, app_file) ||
gl_record_string(&gl->user_file, user_file)) {
- fprintf(stderr,
- "Insufficient memory to record tecla configuration file names.\n");
+ errno = ENOMEM;
+ _err_record_msg(gl->err,
+ "Insufficient memory to record tecla configuration file names",
+ END_ERR_MSG);
return 1;
};
return 0;
@@ -7146,14 +8509,16 @@ static int gl_record_string(char **sptr, const char *string)
return 0;
}
+#ifndef HIDE_FILE_SYSTEM
/*.......................................................................
* Re-read any application-specific and user-specific files previously
* specified via the gl_configure_getline() function.
*/
static KT_KEY_FN(gl_read_init_files)
{
- return gl_configure_getline(gl, NULL, gl->app_file, gl->user_file);
+ return _gl_configure_getline(gl, NULL, gl->app_file, gl->user_file);
}
+#endif
/*.......................................................................
* Save the contents of the history buffer to a given new file.
@@ -7176,27 +8541,70 @@ static KT_KEY_FN(gl_read_init_files)
int gl_save_history(GetLine *gl, const char *filename, const char *comment,
int max_lines)
{
- FileExpansion *expansion; /* The expansion of the filename */
+ sigset_t oldset; /* The signals that were blocked on entry to this function */
+ int status; /* The return status of _gl_save_history() */
/*
* Check the arguments.
*/
if(!gl || !filename || !comment) {
- fprintf(stderr, "gl_save_history: NULL argument(s).\n");
+ if(gl)
+ _err_record_msg(gl->err, "NULL argument(s)", END_ERR_MSG);
+ errno = EINVAL;
return 1;
};
/*
+ * Block all signals.
+ */
+ if(gl_mask_signals(gl, &oldset))
+ return 1;
+/*
+ * Execute the private body of the function while signals are blocked.
+ */
+ status = _gl_save_history(gl, filename, comment, max_lines);
+/*
+ * Restore the process signal mask.
+ */
+ gl_unmask_signals(gl, &oldset);
+ return status;
+}
+
+/*.......................................................................
+ * This is the private body of the gl_save_history() function. It
+ * assumes that the caller has checked its arguments and blocked the
+ * delivery of signals.
+ */
+static int _gl_save_history(GetLine *gl, const char *filename,
+ const char *comment, int max_lines)
+{
+/*
+ * If filesystem access is to be excluded, then history files can't
+ * be written.
+ */
+#ifdef WITHOUT_FILE_SYSTEM
+ _err_record_msg(gl->err, "Can't save history without filesystem access",
+ END_ERR_MSG);
+ errno = EINVAL;
+ return 1;
+#else
+ FileExpansion *expansion; /* The expansion of the filename */
+/*
* Expand the filename.
*/
expansion = ef_expand_file(gl->ef, filename, -1);
if(!expansion) {
- fprintf(stderr, "Unable to expand %s (%s).\n", filename,
- ef_last_error(gl->ef));
+ gl_print_info(gl, "Unable to expand ", filename, " (",
+ ef_last_error(gl->ef), ").", GL_END_INFO);
return 1;
};
/*
* Attempt to save to the specified file.
*/
- return _glh_save_history(gl->glh, expansion->files[0], comment, max_lines);
+ if(_glh_save_history(gl->glh, expansion->files[0], comment, max_lines)) {
+ _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
+ return 1;
+ };
+ return 0;
+#endif
}
/*.......................................................................
@@ -7214,33 +8622,73 @@ int gl_save_history(GetLine *gl, const char *filename, const char *comment,
*/
int gl_load_history(GetLine *gl, const char *filename, const char *comment)
{
- FileExpansion *expansion; /* The expansion of the filename */
+ sigset_t oldset; /* The signals that were blocked on entry to this function */
+ int status; /* The return status of _gl_load_history() */
/*
* Check the arguments.
*/
if(!gl || !filename || !comment) {
- fprintf(stderr, "gl_load_history: NULL argument(s).\n");
+ if(gl)
+ _err_record_msg(gl->err, "NULL argument(s)", END_ERR_MSG);
+ errno = EINVAL;
return 1;
};
/*
+ * Block all signals.
+ */
+ if(gl_mask_signals(gl, &oldset))
+ return 1;
+/*
+ * Execute the private body of the function while signals are blocked.
+ */
+ status = _gl_load_history(gl, filename, comment);
+/*
+ * Restore the process signal mask.
+ */
+ gl_unmask_signals(gl, &oldset);
+ return status;
+}
+
+/*.......................................................................
+ * This is the private body of the gl_load_history() function. It
+ * assumes that the caller has checked its arguments and blocked the
+ * delivery of signals.
+ */
+static int _gl_load_history(GetLine *gl, const char *filename,
+ const char *comment)
+{
+/*
+ * If filesystem access is to be excluded, then history files can't
+ * be read.
+ */
+#ifdef WITHOUT_FILE_SYSTEM
+ _err_record_msg(gl->err, "Can't load history without filesystem access",
+ END_ERR_MSG);
+ errno = EINVAL;
+ return 1;
+#else
+ FileExpansion *expansion; /* The expansion of the filename */
+/*
* Expand the filename.
*/
expansion = ef_expand_file(gl->ef, filename, -1);
if(!expansion) {
- fprintf(stderr, "Unable to expand %s (%s).\n", filename,
- ef_last_error(gl->ef));
+ gl_print_info(gl, "Unable to expand ", filename, " (",
+ ef_last_error(gl->ef), ").", GL_END_INFO);
return 1;
};
/*
* Attempt to load from the specified file.
*/
if(_glh_load_history(gl->glh, expansion->files[0], comment,
- gl->cutbuf, gl->linelen)) {
+ gl->cutbuf, gl->linelen+1)) {
+ _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
gl->cutbuf[0] = '\0';
return 1;
};
gl->cutbuf[0] = '\0';
return 0;
+#endif
}
/*.......................................................................
@@ -7267,24 +8715,51 @@ int gl_load_history(GetLine *gl, const char *filename, const char *comment)
*/
int gl_watch_fd(GetLine *gl, int fd, GlFdEvent event,
GlFdEventFn *callback, void *data)
-#if !defined(HAVE_SELECT)
-{return 1;} /* The facility isn't supported on this system */
-#else
{
- GlFdNode *prev; /* The node that precedes 'node' in gl->fd_nodes */
- GlFdNode *node; /* The file-descriptor node being checked */
+ sigset_t oldset; /* The signals that were blocked on entry to this function */
+ int status; /* The return status of _gl_watch_fd() */
/*
* Check the arguments.
*/
if(!gl) {
- fprintf(stderr, "gl_watch_fd: NULL gl argument.\n");
+ errno = EINVAL;
return 1;
};
if(fd < 0) {
- fprintf(stderr, "gl_watch_fd: Error fd < 0.\n");
+ _err_record_msg(gl->err, "Error: fd < 0", END_ERR_MSG);
+ errno = EINVAL;
return 1;
};
/*
+ * Block all signals.
+ */
+ if(gl_mask_signals(gl, &oldset))
+ return 1;
+/*
+ * Execute the private body of the function while signals are blocked.
+ */
+ status = _gl_watch_fd(gl, fd, event, callback, data);
+/*
+ * Restore the process signal mask.
+ */
+ gl_unmask_signals(gl, &oldset);
+ return status;
+}
+
+/*.......................................................................
+ * This is the private body of the gl_watch_fd() function. It
+ * assumes that the caller has checked its arguments and blocked the
+ * delivery of signals.
+ */
+static int _gl_watch_fd(GetLine *gl, int fd, GlFdEvent event,
+ GlFdEventFn *callback, void *data)
+#if !defined(HAVE_SELECT)
+{return 1;} /* The facility isn't supported on this system */
+#else
+{
+ GlFdNode *prev; /* The node that precedes 'node' in gl->fd_nodes */
+ GlFdNode *node; /* The file-descriptor node being checked */
+/*
* Search the list of already registered fd activity nodes for the specified
* file descriptor.
*/
@@ -7305,7 +8780,8 @@ int gl_watch_fd(GetLine *gl, int fd, GlFdEvent event,
*/
node = (GlFdNode *) _new_FreeListNode(gl->fd_node_mem);
if(!node) {
- fprintf(stderr, "gl_watch_fd: Insufficient memory.\n");
+ errno = ENOMEM;
+ _err_record_msg(gl->err, "Insufficient memory", END_ERR_MSG);
return 1;
};
/*
@@ -7370,29 +8846,117 @@ int gl_watch_fd(GetLine *gl, int fd, GlFdEvent event,
};
return 0;
}
+#endif
+
+/*.......................................................................
+ * On systems with the select() system call, the gl_inactivity_timeout()
+ * function provides the option of setting (or cancelling) an
+ * inactivity timeout. Inactivity, in this case, refers both to
+ * terminal input received from the user, and to I/O on any file
+ * descriptors registered by calls to gl_watch_fd(). If at any time,
+ * no activity is seen for the requested time period, the specified
+ * timeout callback function is called. On returning, this callback
+ * returns a code which tells gl_get_line() what to do next. Note that
+ * each call to gl_inactivity_timeout() replaces any previously installed
+ * timeout callback, and that specifying a callback of 0, turns off
+ * inactivity timing.
+ *
+ * Beware that although the timeout argument includes a nano-second
+ * component, few computer clocks presently have resolutions finer
+ * than a few milliseconds, so asking for less than a few milliseconds
+ * is equivalent to zero on a lot of systems.
+ *
+ * Input:
+ * gl GetLine * The resource object of the command-line input
+ * module.
+ * callback GlTimeoutFn * The function to call when the inactivity
+ * timeout is exceeded. To turn off
+ * inactivity timeouts altogether, send 0.
+ * data void * A pointer to arbitrary data to pass to the
+ * callback function.
+ * sec unsigned long The number of whole seconds in the timeout.
+ * nsec unsigned long The fractional number of seconds in the
+ * timeout, expressed in nano-seconds (see
+ * the caveat above).
+ * Output:
+ * return int 0 - OK.
+ * 1 - Either gl==NULL, or this facility isn't
+ * available on the the host system
+ * (ie. select() isn't available). No
+ * error message is generated in the latter
+ * case.
+ */
+int gl_inactivity_timeout(GetLine *gl, GlTimeoutFn *timeout_fn, void *data,
+ unsigned long sec, unsigned long nsec)
+#if !defined(HAVE_SELECT)
+{return 1;} /* The facility isn't supported on this system */
+#else
+{
+ sigset_t oldset; /* The signals that were blocked on entry to this function */
+/*
+ * Check the arguments.
+ */
+ if(!gl) {
+ errno = EINVAL;
+ return 1;
+ };
+/*
+ * Block all signals.
+ */
+ if(gl_mask_signals(gl, &oldset))
+ return 1;
+/*
+ * Install a new timeout?
+ */
+ if(timeout_fn) {
+ gl->timer.dt.tv_sec = sec;
+ gl->timer.dt.tv_usec = nsec / 1000;
+ gl->timer.fn = timeout_fn;
+ gl->timer.data = data;
+ } else {
+ gl->timer.fn = 0;
+ gl->timer.data = NULL;
+ };
+/*
+ * Restore the process signal mask.
+ */
+ gl_unmask_signals(gl, &oldset);
+ return 0;
+}
+#endif
/*.......................................................................
- * When select() is available, this function is called by
- * gl_read_character() to respond to file-descriptor events registered by
- * the caller.
+ * When select() is available, this is a private function of
+ * gl_read_input() which responds to file-descriptor events registered by
+ * the caller. Note that it assumes that it is being called from within
+ * gl_read_input()'s sigsetjump() clause.
*
* Input:
* gl GetLine * The resource object of this module.
+ * fd int The file descriptor to be watched for user input.
* Output:
- * return int 0 - A character is waiting to be read from the
- * terminal.
+ * return int 0 - OK.
* 1 - An error occurred.
*/
-static int gl_event_handler(GetLine *gl)
+static int gl_event_handler(GetLine *gl, int fd)
+#if !defined(HAVE_SELECT)
+{return 0;}
+#else
{
/*
+ * Set up a zero-second timeout.
+ */
+ struct timeval zero;
+ zero.tv_sec = zero.tv_usec = 0;
+/*
* If at any time no external callbacks remain, quit the loop return,
* so that we can simply wait in read(). This is designed as an
* optimization for when no callbacks have been registered on entry to
* this function, but since callbacks can delete themselves, it can
* also help later.
*/
- while(gl->fd_nodes) {
+ while(gl->fd_nodes || gl->timer.fn) {
+ int nready; /* The number of file descriptors that are ready for I/O */
/*
* Get the set of descriptors to be watched.
*/
@@ -7400,31 +8964,61 @@ static int gl_event_handler(GetLine *gl)
fd_set wfds = gl->wfds;
fd_set ufds = gl->ufds;
/*
+ * Get the appropriate timeout.
+ */
+ struct timeval dt = gl->timer.fn ? gl->timer.dt : zero;
+/*
+ * Add the specified user-input file descriptor tot he set that is to
+ * be watched.
+ */
+ FD_SET(fd, &rfds);
+/*
+ * Unblock the signals that we are watching, while select is blocked
+ * waiting for I/O.
+ */
+ gl_catch_signals(gl);
+/*
* Wait for activity on any of the file descriptors.
*/
- int nready = select(gl->max_fd+1, &rfds, &wfds, &ufds, NULL);
+ nready = select(gl->max_fd+1, &rfds, &wfds, &ufds,
+ (gl->timer.fn || gl->io_mode==GL_SERVER_MODE) ? &dt : NULL);
+/*
+ * We don't want to do a longjmp in the middle of a callback that
+ * might be modifying global or heap data, so block all the signals
+ * that we are trapping before executing callback functions. Note that
+ * the caller will unblock them again when it needs to, so there is
+ * no need to undo this before returning.
+ */
+ gl_mask_signals(gl, NULL);
/*
* If select() returns but none of the file descriptors are reported
* to have activity, then select() timed out.
*/
if(nready == 0) {
- fprintf(stdout, "\r\nUnexpected select() timeout\r\n");
- return 1;
+/*
+ * Note that in non-blocking server mode, the inactivity timer is used
+ * to allow I/O to block for a specified amount of time, so in this
+ * mode we return the postponed blocked status when an abort is
+ * requested.
+ */
+ if(gl_call_timeout_handler(gl)) {
+ return 1;
+ } else if(gl->io_mode == GL_SERVER_MODE) {
+ gl_record_status(gl, GLR_BLOCKED, BLOCKED_ERRNO);
+ return 1;
+ };
/*
* If nready < 0, this means an error occurred.
*/
} else if(nready < 0) {
if(errno != EINTR) {
-#ifdef EAGAIN
- if(!errno) /* This can happen with SysV O_NDELAY */
- errno = EAGAIN;
-#endif
+ gl_record_status(gl, GLR_ERROR, errno);
return 1;
};
/*
- * If the terminal input file descriptor has data available, return.
+ * If the user-input file descriptor has data available, return.
*/
- } else if(FD_ISSET(gl->input_fd, &rfds)) {
+ } else if(FD_ISSET(fd, &rfds)) {
return 0;
/*
* Check for activity on any of the file descriptors registered by the
@@ -7453,17 +9047,25 @@ static int gl_event_handler(GetLine *gl)
/*
* Is the fd writable?
*/
- } else if(node->wr.fn && FD_ISSET(node->fd, &rfds)) {
+ } else if(node->wr.fn && FD_ISSET(node->fd, &wfds)) {
if(gl_call_fd_handler(gl, &node->wr, node->fd, GLFD_WRITE))
return 1;
break; /* The callback may have changed the list of nodes */
};
};
};
+/*
+ * Just in case the above event handlers asked for the input line to
+ * be redrawn, flush any pending output.
+ */
+ if(gl_flush_output(gl))
+ return 1;
};
return 0;
}
+#endif
+#if defined(HAVE_SELECT)
/*.......................................................................
* This is a private function of gl_event_handler(), used to call a
* file-descriptor callback.
@@ -7481,31 +9083,20 @@ static int gl_call_fd_handler(GetLine *gl, GlFdHandler *gfh, int fd,
GlFdEvent event)
{
Termios attr; /* The terminal attributes */
- int redisplay = 0; /* True to have the input line redisplayed */
int waserr = 0; /* True after any error */
/*
- * We don't want to do a longjmp in the middle of a callback that
- * might be modifying global or heap data, so block all the signals
- * that we are trapping.
- */
- if(sigprocmask(SIG_BLOCK, &gl->new_signal_set, NULL) == -1) {
- fprintf(stderr, "getline(): sigprocmask error: %s\n", strerror(errno));
- return 1;
- };
-/*
* Re-enable conversion of newline characters to carriage-return/linefeed,
* so that the callback can write to the terminal without having to do
* anything special.
*/
if(tcgetattr(gl->input_fd, &attr)) {
- fprintf(stderr, "\r\ngetline(): tcgetattr error: %s\r\n", strerror(errno));
+ _err_record_msg(gl->err, "tcgetattr error", END_ERR_MSG);
return 1;
};
attr.c_oflag |= OPOST;
while(tcsetattr(gl->input_fd, TCSADRAIN, &attr)) {
- if (errno != EINTR) {
- fprintf(stderr, "\r\ngetline(): tcsetattr error: %s\r\n",
- strerror(errno));
+ if(errno != EINTR) {
+ _err_record_msg(gl->err, "tcsetattr error", END_ERR_MSG);
return 1;
};
};
@@ -7515,38 +9106,100 @@ static int gl_call_fd_handler(GetLine *gl, GlFdHandler *gfh, int fd,
switch(gfh->fn(gl, gfh->data, fd, event)) {
default:
case GLFD_ABORT:
+ gl_record_status(gl, GLR_FDABORT, 0);
waserr = 1;
break;
case GLFD_REFRESH:
- redisplay = 1;
+ gl_queue_redisplay(gl);
break;
case GLFD_CONTINUE:
- redisplay = gl->prompt_changed;
break;
};
/*
+ * If the callback function called gl_normal_io(), restore raw mode,
+ * and queue a redisplay of the input line.
+ */
+ if(!gl->raw_mode)
+ waserr = waserr || _gl_raw_io(gl, 1);
+/*
* Disable conversion of newline characters to carriage-return/linefeed.
*/
attr.c_oflag &= ~(OPOST);
while(tcsetattr(gl->input_fd, TCSADRAIN, &attr)) {
if(errno != EINTR) {
- fprintf(stderr, "\ngetline(): tcsetattr error: %s\n", strerror(errno));
+ _err_record_msg(gl->err, "tcsetattr error", END_ERR_MSG);
return 1;
};
};
+ return waserr;
+}
+
+/*.......................................................................
+ * This is a private function of gl_event_handler(), used to call a
+ * inactivity timer callbacks.
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+static int gl_call_timeout_handler(GetLine *gl)
+{
+ Termios attr; /* The terminal attributes */
+ int waserr = 0; /* True after any error */
/*
- * If requested, redisplay the input line.
+ * Make sure that there is an inactivity timeout callback.
*/
- if(redisplay && gl_redisplay(gl, 1))
- return 1;
+ if(!gl->timer.fn)
+ return 0;
/*
- * Unblock the signals that we were trapping before this function
- * was called.
+ * Re-enable conversion of newline characters to carriage-return/linefeed,
+ * so that the callback can write to the terminal without having to do
+ * anything special.
*/
- if(sigprocmask(SIG_UNBLOCK, &gl->new_signal_set, NULL) == -1) {
- fprintf(stderr, "getline(): sigprocmask error: %s\n", strerror(errno));
+ if(tcgetattr(gl->input_fd, &attr)) {
+ _err_record_msg(gl->err, "tcgetattr error", END_ERR_MSG);
return 1;
};
+ attr.c_oflag |= OPOST;
+ while(tcsetattr(gl->input_fd, TCSADRAIN, &attr)) {
+ if(errno != EINTR) {
+ _err_record_msg(gl->err, "tcsetattr error", END_ERR_MSG);
+ return 1;
+ };
+ };
+/*
+ * Invoke the application's callback function.
+ */
+ switch(gl->timer.fn(gl, gl->timer.data)) {
+ default:
+ case GLTO_ABORT:
+ gl_record_status(gl, GLR_TIMEOUT, 0);
+ waserr = 1;
+ break;
+ case GLTO_REFRESH:
+ gl_queue_redisplay(gl);
+ break;
+ case GLTO_CONTINUE:
+ break;
+ };
+/*
+ * If the callback function called gl_normal_io(), restore raw mode,
+ * and queue a redisplay of the input line.
+ */
+ if(!gl->raw_mode)
+ waserr = waserr || _gl_raw_io(gl, 1);
+/*
+ * Disable conversion of newline characters to carriage-return/linefeed.
+ */
+ attr.c_oflag &= ~(OPOST);
+ while(tcsetattr(gl->input_fd, TCSADRAIN, &attr)) {
+ if(errno != EINTR) {
+ _err_record_msg(gl->err, "tcsetattr error", END_ERR_MSG);
+ return 1;
+ };
+ };
return waserr;
}
#endif /* HAVE_SELECT */
@@ -7569,30 +9222,45 @@ static int gl_call_fd_handler(GetLine *gl, GlFdHandler *gfh, int fd,
*/
int gl_group_history(GetLine *gl, unsigned id)
{
+ sigset_t oldset; /* The signals that were blocked on entry to this function */
+ int status; /* The return status of this function */
/*
* Check the arguments.
*/
if(!gl) {
- fprintf(stderr, "gl_group_history: NULL argument(s).\n");
+ errno = EINVAL;
return 1;
};
/*
+ * Block all signals while we install the new configuration.
+ */
+ if(gl_mask_signals(gl, &oldset))
+ return 1;
+/*
* If the group isn't being changed, do nothing.
*/
- if(_glh_get_group(gl->glh) == id)
- return 0;
+ if(_glh_get_group(gl->glh) == id) {
+ status = 0;
/*
* Establish the new group.
*/
- if(_glh_set_group(gl->glh, id))
- return 1;
+ } else if(_glh_set_group(gl->glh, id)) {
+ _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
+ status = 1;
/*
* Prevent history information from the previous group being
* inappropriately used by the next call to gl_get_line().
*/
- gl->preload_history = 0;
- gl->last_search = -1;
- return 0;
+ } else {
+ gl->preload_history = 0;
+ gl->last_search = -1;
+ status = 0;
+ };
+/*
+ * Restore the process signal mask.
+ */
+ gl_unmask_signals(gl, &oldset);
+ return status;
}
/*.......................................................................
@@ -7627,14 +9295,34 @@ int gl_group_history(GetLine *gl, unsigned id)
int gl_show_history(GetLine *gl, FILE *fp, const char *fmt, int all_groups,
int max_lines)
{
+ sigset_t oldset; /* The signals that were blocked on entry to this function */
+ int status; /* The return status of this function */
/*
* Check the arguments.
*/
if(!gl || !fp || !fmt) {
- fprintf(stderr, "gl_show_history: NULL argument(s).\n");
+ if(gl)
+ _err_record_msg(gl->err, "NULL argument(s)", END_ERR_MSG);
+ errno = EINVAL;
return 1;
};
- return _glh_show_history(gl->glh, fp, fmt, all_groups, max_lines);
+/*
+ * Block all signals.
+ */
+ if(gl_mask_signals(gl, &oldset))
+ return 1;
+/*
+ * Display the specified history group(s) while signals are blocked.
+ */
+ status = _glh_show_history(gl->glh, _io_write_stdio, fp, fmt, all_groups,
+ max_lines) || fflush(fp)==EOF;
+ if(!status)
+ _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
+/*
+ * Restore the process signal mask.
+ */
+ gl_unmask_signals(gl, &oldset);
+ return status;
}
/*.......................................................................
@@ -7651,7 +9339,32 @@ int gl_show_history(GetLine *gl, FILE *fp, const char *fmt, int all_groups,
*/
GlTerminalSize gl_terminal_size(GetLine *gl, int def_ncolumn, int def_nline)
{
- GlTerminalSize size; /* The return value */
+ GlTerminalSize size; /* The object to be returned */
+ sigset_t oldset; /* The signals that were blocked on entry */
+ /* to this function */
+/*
+ * Block all signals while accessing gl.
+ */
+ gl_mask_signals(gl, &oldset);
+/*
+ * Lookup/configure the terminal size.
+ */
+ _gl_terminal_size(gl, def_ncolumn, def_nline, &size);
+/*
+ * Restore the process signal mask before returning.
+ */
+ gl_unmask_signals(gl, &oldset);
+ return size;
+}
+
+/*.......................................................................
+ * This is the private body of the gl_terminal_size() function. It
+ * assumes that the caller has checked its arguments and blocked the
+ * delivery of signals.
+ */
+static void _gl_terminal_size(GetLine *gl, int def_ncolumn, int def_nline,
+ GlTerminalSize *size)
+{
const char *env; /* The value of an environment variable */
int n; /* A number read from env[] */
/*
@@ -7667,15 +9380,17 @@ GlTerminalSize gl_terminal_size(GetLine *gl, int def_ncolumn, int def_nline)
/*
* Ask the terminal directly if possible.
*/
-#ifdef USE_SIGWINCH
- (void) gl_resize_terminal(gl, 0);
-#endif
+ gl_query_size(gl, &gl->ncolumn, &gl->nline);
/*
- * If gl_resize_terminal() couldn't be used, or it returned non-sensical
- * values for the number of lines, see if the LINES environment variable
- * exists and specifies a believable number. If this doesn't work,
- * look up the default size in the terminal information database,
- * where available.
+ * If gl_query_size() couldn't ask the terminal, it will have
+ * left gl->nrow and gl->ncolumn unchanged. If these values haven't
+ * been changed from their initial values of zero, we need to find
+ * a different method to get the terminal size.
+ *
+ * If the number of lines isn't known yet, first see if the
+ * LINES environment ariable exists and specifies a believable number.
+ * If this doesn't work, look up the default size in the terminal
+ * information database.
*/
if(gl->nline < 1) {
if((env = getenv("LINES")) && (n=atoi(env)) > 0)
@@ -7689,11 +9404,10 @@ GlTerminalSize gl_terminal_size(GetLine *gl, int def_ncolumn, int def_nline)
#endif
};
/*
- * If gl_resize_terminal() couldn't be used, or it returned non-sensical
- * values for the number of columns, see if the COLUMNS environment variable
- * exists and specifies a believable number. If this doesn't work, fall
- * lookup the default size in the terminal information database,
- * where available.
+ * If the number of lines isn't known yet, first see if the COLUMNS
+ * environment ariable exists and specifies a believable number. If
+ * this doesn't work, look up the default size in the terminal
+ * information database.
*/
if(gl->ncolumn < 1) {
if((env = getenv("COLUMNS")) && (n=atoi(env)) > 0)
@@ -7718,9 +9432,11 @@ GlTerminalSize gl_terminal_size(GetLine *gl, int def_ncolumn, int def_nline)
/*
* Copy the new size into the return value.
*/
- size.nline = gl->nline;
- size.ncolumn = gl->ncolumn;
- return size;
+ if(size) {
+ size->nline = gl->nline;
+ size->ncolumn = gl->ncolumn;
+ };
+ return;
}
/*.......................................................................
@@ -7738,7 +9454,29 @@ GlTerminalSize gl_terminal_size(GetLine *gl, int def_ncolumn, int def_nline)
*/
int gl_resize_history(GetLine *gl, size_t bufsize)
{
- return gl ? _glh_resize_history(gl->glh, bufsize) : 1;
+ sigset_t oldset; /* The signals that were blocked on entry to this function */
+ int status; /* The return status of this function */
+/*
+ * Check the arguments.
+ */
+ if(!gl)
+ return 1;
+/*
+ * Block all signals while modifying the contents of gl.
+ */
+ if(gl_mask_signals(gl, &oldset))
+ return 1;
+/*
+ * Perform the resize while signals are blocked.
+ */
+ status = _glh_resize_history(gl->glh, bufsize);
+ if(status)
+ _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
+/*
+ * Restore the process signal mask before returning.
+ */
+ gl_unmask_signals(gl, &oldset);
+ return status;
}
/*.......................................................................
@@ -7753,8 +9491,21 @@ int gl_resize_history(GetLine *gl, size_t bufsize)
*/
void gl_limit_history(GetLine *gl, int max_lines)
{
- if(gl)
+ if(gl) {
+ sigset_t oldset; /* The signals that were blocked on entry to this block */
+/*
+ * Temporarily block all signals.
+ */
+ gl_mask_signals(gl, &oldset);
+/*
+ * Apply the limit while signals are blocked.
+ */
_glh_limit_history(gl->glh, max_lines);
+/*
+ * Restore the process signal mask before returning.
+ */
+ gl_unmask_signals(gl, &oldset);
+ };
}
/*.......................................................................
@@ -7769,8 +9520,21 @@ void gl_limit_history(GetLine *gl, int max_lines)
*/
void gl_clear_history(GetLine *gl, int all_groups)
{
- if(gl)
+ if(gl) {
+ sigset_t oldset; /* The signals that were blocked on entry to this block */
+/*
+ * Temporarily block all signals.
+ */
+ gl_mask_signals(gl, &oldset);
+/*
+ * Clear the history buffer while signals are blocked.
+ */
_glh_clear_history(gl->glh, all_groups);
+/*
+ * Restore the process signal mask before returning.
+ */
+ gl_unmask_signals(gl, &oldset);
+ };
}
/*.......................................................................
@@ -7783,8 +9547,21 @@ void gl_clear_history(GetLine *gl, int all_groups)
*/
void gl_toggle_history(GetLine *gl, int enable)
{
- if(gl)
+ if(gl) {
+ sigset_t oldset; /* The signals that were blocked on entry to this block */
+/*
+ * Temporarily block all signals.
+ */
+ gl_mask_signals(gl, &oldset);
+/*
+ * Change the history recording mode while signals are blocked.
+ */
_glh_toggle_history(gl->glh, enable);
+/*
+ * Restore the process signal mask before returning.
+ */
+ gl_unmask_signals(gl, &oldset);
+ };
}
/*.......................................................................
@@ -7816,8 +9593,30 @@ void gl_toggle_history(GetLine *gl, int enable)
*/
int gl_lookup_history(GetLine *gl, unsigned long id, GlHistoryLine *line)
{
- return gl ? _glh_lookup_history(gl->glh, (GlhLineID) id, &line->line,
- &line->group, &line->timestamp) : 0;
+ sigset_t oldset; /* The signals that were blocked on entry to this function */
+ int status; /* The return status of this function */
+/*
+ * Check the arguments.
+ */
+ if(!gl)
+ return 0;
+/*
+ * Block all signals while modifying the contents of gl.
+ */
+ if(gl_mask_signals(gl, &oldset))
+ return 1;
+/*
+ * Perform the lookup while signals are blocked.
+ */
+ status = _glh_lookup_history(gl->glh, (GlhLineID) id, &line->line,
+ &line->group, &line->timestamp);
+ if(status)
+ _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
+/*
+ * Restore the process signal mask before returning.
+ */
+ gl_unmask_signals(gl, &oldset);
+ return status;
}
/*.......................................................................
@@ -7832,9 +9631,22 @@ int gl_lookup_history(GetLine *gl, unsigned long id, GlHistoryLine *line)
*/
void gl_state_of_history(GetLine *gl, GlHistoryState *state)
{
- if(gl && state)
+ if(gl && state) {
+ sigset_t oldset; /* The signals that were blocked on entry to this block */
+/*
+ * Temporarily block all signals.
+ */
+ gl_mask_signals(gl, &oldset);
+/*
+ * Lookup the status while signals are blocked.
+ */
_glh_state_of_history(gl->glh, &state->enabled, &state->group,
&state->max_lines);
+/*
+ * Restore the process signal mask before returning.
+ */
+ gl_unmask_signals(gl, &oldset);
+ };
}
/*.......................................................................
@@ -7848,9 +9660,22 @@ void gl_state_of_history(GetLine *gl, GlHistoryState *state)
*/
void gl_range_of_history(GetLine *gl, GlHistoryRange *range)
{
- if(gl && range)
+ if(gl && range) {
+ sigset_t oldset; /* The signals that were blocked on entry to this block */
+/*
+ * Temporarily block all signals.
+ */
+ gl_mask_signals(gl, &oldset);
+/*
+ * Lookup the information while signals are blocked.
+ */
_glh_range_of_history(gl->glh, &range->oldest, &range->newest,
&range->nlines);
+/*
+ * Restore the process signal mask before returning.
+ */
+ gl_unmask_signals(gl, &oldset);
+ };
}
/*.......................................................................
@@ -7865,8 +9690,21 @@ void gl_range_of_history(GetLine *gl, GlHistoryRange *range)
*/
void gl_size_of_history(GetLine *gl, GlHistorySize *size)
{
- if(gl && size)
+ if(gl && size) {
+ sigset_t oldset; /* The signals that were blocked on entry to this block */
+/*
+ * Temporarily block all signals.
+ */
+ gl_mask_signals(gl, &oldset);
+/*
+ * Lookup the information while signals are blocked.
+ */
_glh_size_of_history(gl->glh, &size->size, &size->used);
+/*
+ * Restore the process signal mask before returning.
+ */
+ gl_unmask_signals(gl, &oldset);
+ };
}
/*.......................................................................
@@ -7878,18 +9716,18 @@ static KT_KEY_FN(gl_list_history)
/*
* Start a new line.
*/
- if(fprintf(gl->output_fp, "\r\n") < 0)
+ if(gl_start_newline(gl, 1))
return 1;
/*
* List history lines that belong to the current group.
*/
- _glh_show_history(gl->glh, gl->output_fp, "%N %T %H\r\n", 0,
+ _glh_show_history(gl->glh, gl_write_fn, gl, "%N %T %H\r\n", 0,
count<=1 ? -1 : count);
/*
- * Redisplay the line being edited.
+ * Arrange for the input line to be redisplayed.
*/
- gl->term_curpos = 0;
- return gl_redisplay(gl,1);
+ gl_queue_redisplay(gl);
+ return 0;
}
/*.......................................................................
@@ -7911,9 +9749,25 @@ static KT_KEY_FN(gl_list_history)
int gl_echo_mode(GetLine *gl, int enable)
{
if(gl) {
- int was_echoing = gl->echo;
+ sigset_t oldset; /* The signals that were blocked on entry to this block */
+ int was_echoing; /* The echoing disposition on entry to this function */
+/*
+ * Temporarily block all signals.
+ */
+ gl_mask_signals(gl, &oldset);
+/*
+ * Install the new disposition while signals are blocked.
+ */
+ was_echoing = gl->echo;
if(enable >= 0)
gl->echo = enable;
+/*
+ * Restore the process signal mask before returning.
+ */
+ gl_unmask_signals(gl, &oldset);
+/*
+ * Return the original echoing disposition.
+ */
return was_echoing;
};
return 1;
@@ -7942,14 +9796,18 @@ static int gl_display_prompt(GetLine *gl)
* In case the screen got messed up, send a carriage return to
* put the cursor at the beginning of the current terminal line.
*/
- if(gl_output_control_sequence(gl, 1, gl->bol))
+ if(gl_print_control_sequence(gl, 1, gl->bol))
return 1;
/*
+ * Mark the line as partially displayed.
+ */
+ gl->displayed = 1;
+/*
* Write the prompt, using the currently selected prompt style.
*/
switch(gl->prompt_style) {
case GL_LITERAL_PROMPT:
- if(gl_output_string(gl, gl->prompt, '\0'))
+ if(gl_print_string(gl, gl->prompt, '\0'))
return 1;
break;
case GL_FORMAT_PROMPT:
@@ -8021,7 +9879,7 @@ static int gl_display_prompt(GetLine *gl)
* scratch.
*/
if(old_attr & ~new_attr) {
- if(gl_output_control_sequence(gl, 1, gl->text_attr_off))
+ if(gl_print_control_sequence(gl, 1, gl->text_attr_off))
return 1;
old_attr = 0;
};
@@ -8030,36 +9888,36 @@ static int gl_display_prompt(GetLine *gl)
*/
if(new_attr != old_attr) {
if(new_attr & GL_TXT_BOLD && !(old_attr & GL_TXT_BOLD) &&
- gl_output_control_sequence(gl, 1, gl->bold))
+ gl_print_control_sequence(gl, 1, gl->bold))
return 1;
if(new_attr & GL_TXT_UNDERLINE && !(old_attr & GL_TXT_UNDERLINE) &&
- gl_output_control_sequence(gl, 1, gl->underline))
+ gl_print_control_sequence(gl, 1, gl->underline))
return 1;
if(new_attr & GL_TXT_STANDOUT && !(old_attr & GL_TXT_STANDOUT) &&
- gl_output_control_sequence(gl, 1, gl->standout))
+ gl_print_control_sequence(gl, 1, gl->standout))
return 1;
if(new_attr & GL_TXT_DIM && !(old_attr & GL_TXT_DIM) &&
- gl_output_control_sequence(gl, 1, gl->dim))
+ gl_print_control_sequence(gl, 1, gl->dim))
return 1;
if(new_attr & GL_TXT_REVERSE && !(old_attr & GL_TXT_REVERSE) &&
- gl_output_control_sequence(gl, 1, gl->reverse))
+ gl_print_control_sequence(gl, 1, gl->reverse))
return 1;
if(new_attr & GL_TXT_BLINK && !(old_attr & GL_TXT_BLINK) &&
- gl_output_control_sequence(gl, 1, gl->blink))
+ gl_print_control_sequence(gl, 1, gl->blink))
return 1;
old_attr = new_attr;
};
/*
* Display the latest character.
*/
- if(gl_output_char(gl, *pptr, pptr[1]))
+ if(gl_print_char(gl, *pptr, pptr[1]))
return 1;
};
/*
* Turn off all text attributes now that we have finished drawing
* the prompt.
*/
- if(gl_output_control_sequence(gl, 1, gl->text_attr_off))
+ if(gl_print_control_sequence(gl, 1, gl->text_attr_off))
return 1;
break;
};
@@ -8086,13 +9944,67 @@ static int gl_display_prompt(GetLine *gl)
void gl_replace_prompt(GetLine *gl, const char *prompt)
{
if(gl) {
- gl->prompt = prompt ? prompt : "";
- gl->prompt_len = gl_displayed_prompt_width(gl);
- gl->prompt_changed = 1;
+ sigset_t oldset; /* The signals that were blocked on entry to this block */
+/*
+ * Temporarily block all signals.
+ */
+ gl_mask_signals(gl, &oldset);
+/*
+ * Replace the prompt.
+ */
+ _gl_replace_prompt(gl, prompt);
+/*
+ * Restore the process signal mask before returning.
+ */
+ gl_unmask_signals(gl, &oldset);
};
}
/*.......................................................................
+ * This is the private body of the gl_replace_prompt() function. It
+ * assumes that the caller has checked its arguments and blocked the
+ * delivery of signals.
+ */
+static void _gl_replace_prompt(GetLine *gl, const char *prompt)
+{
+/*
+ * Substitute an empty prompt?
+ */
+ if(!prompt)
+ prompt = "";
+/*
+ * Gaurd against aliasing between prompt and gl->prompt.
+ */
+ if(gl->prompt != prompt) {
+/*
+ * Get the length of the new prompt string.
+ */
+ size_t slen = strlen(prompt);
+/*
+ * If needed, allocate a new buffer for the prompt string.
+ */
+ if(!gl->prompt || slen > strlen(gl->prompt)) {
+ size_t size = sizeof(char) * (slen + 1);
+ char *new_prompt = gl->prompt ? realloc(gl->prompt, size) : malloc(size);
+ if(!new_prompt)
+ return;
+ gl->prompt = new_prompt;
+ };
+/*
+ * Make a copy of the new prompt.
+ */
+ strcpy(gl->prompt, prompt);
+ };
+/*
+ * Record the statistics of the new prompt.
+ */
+ gl->prompt_len = gl_displayed_prompt_width(gl);
+ gl->prompt_changed = 1;
+ gl_queue_redisplay(gl);
+ return;
+}
+
+/*.......................................................................
* Work out the length of the current prompt on the terminal, according
* to the current prompt formatting style.
*
@@ -8156,11 +10068,24 @@ static int gl_displayed_prompt_width(GetLine *gl)
void gl_prompt_style(GetLine *gl, GlPromptStyle style)
{
if(gl) {
+ sigset_t oldset; /* The signals that were blocked on entry to this block */
+/*
+ * Temporarily block all signals.
+ */
+ gl_mask_signals(gl, &oldset);
+/*
+ * Install the new style in gl while signals are blocked.
+ */
if(style != gl->prompt_style) {
gl->prompt_style = style;
gl->prompt_len = gl_displayed_prompt_width(gl);
gl->prompt_changed = 1;
+ gl_queue_redisplay(gl);
};
+/*
+ * Restore the process signal mask before returning.
+ */
+ gl_unmask_signals(gl, &oldset);
};
}
@@ -8184,12 +10109,52 @@ void gl_prompt_style(GetLine *gl, GlPromptStyle style)
int gl_trap_signal(GetLine *gl, int signo, unsigned flags,
GlAfterSignal after, int errno_value)
{
- GlSignalNode *sig;
+ sigset_t oldset; /* The signals that were blocked on entry to this function */
+ int status; /* The return status of this function */
/*
* Check the arguments.
*/
if(!gl) {
- fprintf(stderr, "gl_trap_signal: NULL argument(s).\n");
+ errno = EINVAL;
+ return 1;
+ };
+/*
+ * Block all signals while modifying the contents of gl.
+ */
+ if(gl_mask_signals(gl, &oldset))
+ return 1;
+/*
+ * Perform the modification while signals are blocked.
+ */
+ status = _gl_trap_signal(gl, signo, flags, after, errno_value);
+/*
+ * Restore the process signal mask before returning.
+ */
+ gl_unmask_signals(gl, &oldset);
+ return status;
+}
+
+/*.......................................................................
+ * This is the private body of the gl_trap_signal() function. It
+ * assumes that the caller has checked its arguments and blocked the
+ * delivery of signals.
+ */
+static int _gl_trap_signal(GetLine *gl, int signo, unsigned flags,
+ GlAfterSignal after, int errno_value)
+{
+ GlSignalNode *sig;
+/*
+ * Complain if an attempt is made to trap untrappable signals.
+ * These would otherwise cause errors later in gl_mask_signals().
+ */
+ if(0
+#ifdef SIGKILL
+ || signo==SIGKILL
+#endif
+#ifdef SIGBLOCK
+ || signo==SIGBLOCK
+#endif
+ ) {
return 1;
};
/*
@@ -8219,11 +10184,14 @@ int gl_trap_signal(GetLine *gl, int signo, unsigned flags,
*/
sigemptyset(&sig->proc_mask);
if(sigaddset(&sig->proc_mask, signo) == -1) {
- fprintf(stderr, "gl_trap_signal: sigaddset error: %s\n",
- strerror(errno));
+ _err_record_msg(gl->err, "sigaddset error", END_ERR_MSG);
sig = (GlSignalNode *) _del_FreeListNode(gl->sig_mem, sig);
return 1;
};
+/*
+ * Add the signal to the bit-mask of signals being trapped.
+ */
+ sigaddset(&gl->all_signal_set, signo);
};
/*
* Record the new signal attributes.
@@ -8248,14 +10216,21 @@ int gl_ignore_signal(GetLine *gl, int signo)
{
GlSignalNode *sig; /* The gl->sigs list node of the specified signal */
GlSignalNode *prev; /* The node that precedes sig in the list */
+ sigset_t oldset; /* The signals that were blocked on entry to this */
+ /* function. */
/*
* Check the arguments.
*/
if(!gl) {
- fprintf(stderr, "gl_ignore_signal: NULL argument(s).\n");
+ errno = EINVAL;
return 1;
};
/*
+ * Block all signals while modifying the contents of gl.
+ */
+ if(gl_mask_signals(gl, &oldset))
+ return 1;
+/*
* Find the node of the gl->sigs list which records the disposition
* of the specified signal.
*/
@@ -8274,7 +10249,15 @@ int gl_ignore_signal(GetLine *gl, int signo)
* Return the node to the freelist.
*/
sig = (GlSignalNode *) _del_FreeListNode(gl->sig_mem, sig);
+/*
+ * Remove the signal from the bit-mask union of signals being trapped.
+ */
+ sigdelset(&gl->all_signal_set, signo);
};
+/*
+ * Restore the process signal mask before returning.
+ */
+ gl_unmask_signals(gl, &oldset);
return 0;
}
@@ -8288,42 +10271,53 @@ int gl_ignore_signal(GetLine *gl, int signo)
* gl GetLine * The resource object of gl_get_line().
* newline_char int The newline character to add to the end
* of the line.
- * archive int True to have the line archived in the
- * history buffer.
* Output:
* return int 0 - OK.
* 1 - Error.
*/
-static int gl_line_ended(GetLine *gl, int newline_char, int archive)
+static int gl_line_ended(GetLine *gl, int newline_char)
{
/*
- * If the newline character is printable, display it.
+ * If the newline character is printable, display it at the end of
+ * the line, and add it to the input line buffer.
*/
if(isprint((int)(unsigned char) newline_char)) {
- if(gl_end_of_line(gl, 1) || gl_add_char_to_line(gl, newline_char))
+ if(gl_end_of_line(gl, 1, NULL) || gl_add_char_to_line(gl, newline_char))
return 1;
} else {
/*
- * Otherwise just append it to the input line buffer.
+ * Otherwise just append a newline character to the input line buffer.
*/
- gl->line[gl->ntotal++] = newline_char;
- gl->line[gl->ntotal] = '\0';
+ newline_char = '\n';
+ gl_buffer_char(gl, newline_char, gl->ntotal);
};
/*
* Add the line to the history buffer if it was entered with a
- * newline or carriage return character.
+ * newline character.
*/
- if(archive)
- (void) _glh_add_history(gl->glh, gl->line, 0);
+ if(gl->echo && gl->automatic_history && newline_char=='\n')
+ (void) _gl_append_history(gl, gl->line);
/*
- * Unless depending on the system-provided line editing, start a new
+ * Except when depending on the system-provided line editing, start a new
* line after the end of the line that has just been entered.
*/
- if(gl->editor != GL_NO_EDITOR) {
- if(gl_end_of_line(gl, 1) ||
- gl_output_raw_string(gl, "\r\n"))
- return 1;
- };
+ if(gl->editor != GL_NO_EDITOR && gl_start_newline(gl, 1))
+ return 1;
+/*
+ * Record the successful return status.
+ */
+ gl_record_status(gl, GLR_NEWLINE, 0);
+/*
+ * Attempt to flush any pending output.
+ */
+ (void) gl_flush_output(gl);
+/*
+ * The next call to gl_get_line() will write the prompt for a new line
+ * (or continue the above flush if incomplete), so if we manage to
+ * flush the terminal now, report that we are waiting to write to the
+ * terminal.
+ */
+ gl->pending_io = GLP_WRITE;
return 0;
}
@@ -8340,7 +10334,2511 @@ static int gl_line_ended(GetLine *gl, int newline_char, int archive)
* call to gl_get_line(), or -1 if no signals
* were caught.
*/
-int gl_last_signal(const GetLine *gl)
+int gl_last_signal(GetLine *gl)
+{
+ int signo = -1; /* The requested signal number */
+ if(gl) {
+ sigset_t oldset; /* The signals that were blocked on entry to this block */
+/*
+ * Temporarily block all signals.
+ */
+ gl_mask_signals(gl, &oldset);
+/*
+ * Access gl now that signals are blocked.
+ */
+ signo = gl->last_signal;
+/*
+ * Restore the process signal mask before returning.
+ */
+ gl_unmask_signals(gl, &oldset);
+ };
+ return signo;
+}
+
+/*.......................................................................
+ * Prepare to edit a new line.
+ *
+ * Input:
+ * gl GetLine * The resource object of this library.
+ * prompt char * The prompt to prefix the line with, or NULL to
+ * use the same prompt that was used by the previous
+ * line.
+ * start_line char * The initial contents of the input line, or NULL
+ * if it should start out empty.
+ * start_pos int If start_line isn't NULL, this specifies the
+ * index of the character over which the cursor
+ * should initially be positioned within the line.
+ * If you just want it to follow the last character
+ * of the line, send -1.
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+static int gl_present_line(GetLine *gl, const char *prompt,
+ const char *start_line, int start_pos)
+{
+/*
+ * Prepare the line-editing properties for a new editing session.
+ */
+ gl_reset_editor(gl);
+/*
+ * Record the new prompt and its displayed width.
+ */
+ if(prompt)
+ _gl_replace_prompt(gl, prompt);
+/*
+ * Reset the history search pointers.
+ */
+ if(_glh_cancel_search(gl->glh)) {
+ _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
+ return 1;
+ };
+/*
+ * If the previous line was entered via the repeat-history action,
+ * preload the specified history line.
+ */
+ if(gl->preload_history) {
+ gl->preload_history = 0;
+ if(_glh_recall_line(gl->glh, gl->preload_id, gl->line, gl->linelen+1)) {
+ gl_update_buffer(gl); /* Compute gl->ntotal etc.. */
+ gl->buff_curpos = gl->ntotal;
+ } else {
+ gl_truncate_buffer(gl, 0);
+ };
+ gl->preload_id = 0;
+/*
+ * Present a specified initial line?
+ */
+ } else if(start_line) {
+ char *cptr; /* A pointer into gl->line[] */
+/*
+ * Measure the length of the starting line.
+ */
+ int start_len = strlen(start_line);
+/*
+ * If the length of the line is greater than the available space,
+ * truncate it.
+ */
+ if(start_len > gl->linelen)
+ start_len = gl->linelen;
+/*
+ * Load the line into the buffer.
+ */
+ if(start_line != gl->line)
+ gl_buffer_string(gl, start_line, start_len, 0);
+/*
+ * Strip off any trailing newline and carriage return characters.
+ */
+ for(cptr=gl->line + gl->ntotal - 1; cptr >= gl->line &&
+ (*cptr=='\n' || *cptr=='\r'); cptr--,gl->ntotal--)
+ ;
+ gl_truncate_buffer(gl, gl->ntotal < 0 ? 0 : gl->ntotal);
+/*
+ * Where should the cursor be placed within the line?
+ */
+ if(start_pos < 0 || start_pos > gl->ntotal) {
+ if(gl_place_cursor(gl, gl->ntotal))
+ return 1;
+ } else {
+ if(gl_place_cursor(gl, start_pos))
+ return 1;
+ };
+/*
+ * Clear the input line?
+ */
+ } else {
+ gl_truncate_buffer(gl, 0);
+ };
+/*
+ * Arrange for the line to be displayed by gl_flush_output().
+ */
+ gl_queue_redisplay(gl);
+/*
+ * Update the display.
+ */
+ return gl_flush_output(gl);
+}
+
+/*.......................................................................
+ * Reset all line-editing parameters for a new editing session. Note
+ * that this does not empty the input line, since that would prevent a
+ * gl_get_line() caller from specifying the returned line buffer as
+ * the start_line argument of the next call to gl_get_line().
+ *
+ * Input:
+ * gl GetLine * The line editor resource object.
+ */
+static void gl_reset_editor(GetLine *gl)
+{
+/*
+ * Warning: Don't clear gl->line[] and gl->ntotal here (see above).
+ */
+ gl->buff_curpos = 0;
+ gl->term_curpos = 0;
+ gl->term_len = 0;
+ gl->insert_curpos = 0;
+ gl->number = -1;
+ gl->displayed = 0;
+ gl->endline = 0;
+ gl->redisplay = 0;
+ gl->postpone = 0;
+ gl->nbuf = 0;
+ gl->nread = 0;
+ gl->vi.command = 0;
+ gl->vi.undo.line[0] = '\0';
+ gl->vi.undo.ntotal = 0;
+ gl->vi.undo.buff_curpos = 0;
+ gl->vi.repeat.action.fn = 0;
+ gl->vi.repeat.action.data = 0;
+ gl->last_signal = -1;
+}
+
+/*.......................................................................
+ * Print an informational message to the terminal, after starting a new
+ * line.
+ *
+ * Input:
+ * gl GetLine * The line editor resource object.
+ * ... const char * Zero or more strings to be printed.
+ * ... void * The last argument must always be GL_END_INFO.
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+static int gl_print_info(GetLine *gl, ...)
+{
+ va_list ap; /* The variable argument list */
+ const char *s; /* The string being printed */
+ int waserr = 0; /* True after an error */
+/*
+ * Only display output when echoing is on.
+ */
+ if(gl->echo) {
+/*
+ * Skip to the start of the next empty line before displaying the message.
+ */
+ if(gl_start_newline(gl, 1))
+ return 1;
+/*
+ * Display the list of provided messages.
+ */
+ va_start(ap, gl);
+ while(!waserr && (s = va_arg(ap, const char *)) != GL_END_INFO)
+ waserr = gl_print_raw_string(gl, 1, s, -1);
+ va_end(ap);
+/*
+ * Start a newline.
+ */
+ waserr = waserr || gl_print_raw_string(gl, 1, "\n\r", -1);
+/*
+ * Arrange for the input line to be redrawn.
+ */
+ gl_queue_redisplay(gl);
+ };
+ return waserr;
+}
+
+/*.......................................................................
+ * Go to the start of the next empty line, ready to output miscellaneous
+ * text to the screen.
+ *
+ * Note that when async-signal safety is required, the 'buffered'
+ * argument must be 0.
+ *
+ * Input:
+ * gl GetLine * The line editor resource object.
+ * buffered int If true, used buffered I/O when writing to
+ * the terminal. Otherwise use async-signal-safe
+ * unbuffered I/O.
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+static int gl_start_newline(GetLine *gl, int buffered)
+{
+ int waserr = 0; /* True after any I/O error */
+/*
+ * Move the cursor to the start of the terminal line that follows the
+ * last line of the partially enterred line. In order that this
+ * function remain async-signal safe when write_fn is signal safe, we
+ * can't call our normal output functions, since they call tputs(),
+ * who's signal saftey isn't defined. Fortunately, we can simply use
+ * \r and \n to move the cursor to the right place.
+ */
+ if(gl->displayed) { /* Is an input line currently displayed? */
+/*
+ * On which terminal lines are the cursor and the last character of the
+ * input line?
+ */
+ int curs_line = gl->term_curpos / gl->ncolumn;
+ int last_line = gl->term_len / gl->ncolumn;
+/*
+ * Move the cursor to the start of the line that follows the last
+ * terminal line that is occupied by the input line.
+ */
+ for( ; curs_line < last_line + 1; curs_line++)
+ waserr = waserr || gl_print_raw_string(gl, buffered, "\n", 1);
+ waserr = waserr || gl_print_raw_string(gl, buffered, "\r", 1);
+/*
+ * Mark the line as no longer displayed.
+ */
+ gl_line_erased(gl);
+ };
+ return waserr;
+}
+
+/*.......................................................................
+ * The callback through which all terminal output is routed.
+ * This simply appends characters to a queue buffer, which is
+ * subsequently flushed to the output channel by gl_flush_output().
+ *
+ * Input:
+ * data void * The pointer to a GetLine line editor resource object
+ * cast to (void *).
+ * s const char * The string to be written.
+ * n int The number of characters to write from s[].
+ * Output:
+ * return int The number of characters written. This will always
+ * be equal to 'n' unless an error occurs.
+ */
+static GL_WRITE_FN(gl_write_fn)
+{
+ GetLine *gl = (GetLine *) data;
+ int ndone = _glq_append_chars(gl->cq, s, n, gl->flush_fn, gl);
+ if(ndone != n)
+ _err_record_msg(gl->err, _glq_last_error(gl->cq), END_ERR_MSG);
+ return ndone;
+}
+
+/*.......................................................................
+ * Ask gl_get_line() what caused it to return.
+ *
+ * Input:
+ * gl GetLine * The line editor resource object.
+ * Output:
+ * return GlReturnStatus The return status of the last call to
+ * gl_get_line().
+ */
+GlReturnStatus gl_return_status(GetLine *gl)
+{
+ GlReturnStatus rtn_status = GLR_ERROR; /* The requested status */
+ if(gl) {
+ sigset_t oldset; /* The signals that were blocked on entry to this block */
+/*
+ * Temporarily block all signals.
+ */
+ gl_mask_signals(gl, &oldset);
+/*
+ * Access gl while signals are blocked.
+ */
+ rtn_status = gl->rtn_status;
+/*
+ * Restore the process signal mask before returning.
+ */
+ gl_unmask_signals(gl, &oldset);
+ };
+ return rtn_status;
+}
+
+/*.......................................................................
+ * In non-blocking server-I/O mode, this function should be called
+ * from the application's external event loop to see what type of
+ * terminal I/O is being waited for by gl_get_line(), and thus what
+ * direction of I/O to wait for with select() or poll().
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ * Output:
+ * return GlPendingIO The type of pending I/O being waited for.
+ */
+GlPendingIO gl_pending_io(GetLine *gl)
+{
+ GlPendingIO pending_io = GLP_WRITE; /* The requested information */
+ if(gl) {
+ sigset_t oldset; /* The signals that were blocked on entry to this block */
+/*
+ * Temporarily block all signals.
+ */
+ gl_mask_signals(gl, &oldset);
+/*
+ * Access gl while signals are blocked.
+ */
+ pending_io = gl->pending_io;
+/*
+ * Restore the process signal mask before returning.
+ */
+ gl_unmask_signals(gl, &oldset);
+ };
+ return pending_io;
+}
+
+/*.......................................................................
+ * In server mode, this function configures the terminal for non-blocking
+ * raw terminal I/O. In normal I/O mode it does nothing.
+ *
+ * Callers of this function must be careful to trap all signals that
+ * terminate or suspend the program, and call gl_normal_io()
+ * from the corresponding signal handlers in order to restore the
+ * terminal to its original settings before the program is terminated
+ * or suspended. They should also trap the SIGCONT signal to detect
+ * when the program resumes, and ensure that its signal handler
+ * call gl_raw_io() to redisplay the line and resume editing.
+ *
+ * This function is async signal safe.
+ *
+ * Input:
+ * gl GetLine * The line editor resource object.
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+int gl_raw_io(GetLine *gl)
+{
+ sigset_t oldset; /* The signals that were blocked on entry to this function */
+ int status; /* The return status of _gl_raw_io() */
+/*
+ * Check the arguments.
+ */
+ if(!gl) {
+ errno = EINVAL;
+ return 1;
+ };
+/*
+ * Block all signals.
+ */
+ if(gl_mask_signals(gl, &oldset))
+ return 1;
+/*
+ * Don't allow applications to switch into raw mode unless in server mode.
+ */
+ if(gl->io_mode != GL_SERVER_MODE) {
+ _err_record_msg(gl->err, "Can't switch to raw I/O unless in server mode",
+ END_ERR_MSG);
+ errno = EPERM;
+ status = 1;
+ } else {
+/*
+ * Execute the private body of the function while signals are blocked.
+ */
+ status = _gl_raw_io(gl, 1);
+ };
+/*
+ * Restore the process signal mask.
+ */
+ gl_unmask_signals(gl, &oldset);
+ return status;
+}
+
+/*.......................................................................
+ * This is the private body of the public function, gl_raw_io().
+ * It assumes that the caller has checked its arguments and blocked the
+ * delivery of signals.
+ *
+ * This function is async signal safe.
+ */
+static int _gl_raw_io(GetLine *gl, int redisplay)
+{
+/*
+ * If we are already in the correct mode, do nothing.
+ */
+ if(gl->raw_mode)
+ return 0;
+/*
+ * Switch the terminal to raw mode.
+ */
+ if(gl->is_term && gl_raw_terminal_mode(gl))
+ return 1;
+/*
+ * Switch to non-blocking I/O mode?
+ */
+ if(gl->io_mode==GL_SERVER_MODE &&
+ (gl_nonblocking_io(gl, gl->input_fd) ||
+ gl_nonblocking_io(gl, gl->output_fd) ||
+ (gl->file_fp && gl_nonblocking_io(gl, fileno(gl->file_fp))))) {
+ if(gl->is_term)
+ gl_restore_terminal_attributes(gl);
+ return 1;
+ };
+/*
+ * If an input line is being entered, arrange for it to be
+ * displayed.
+ */
+ if(redisplay) {
+ gl->postpone = 0;
+ gl_queue_redisplay(gl);
+ };
+ return 0;
+}
+
+/*.......................................................................
+ * Restore the terminal to the state that it had when
+ * gl_raw_io() was last called. After calling
+ * gl_raw_io(), this function must be called before
+ * terminating or suspending the program, and before attempting other
+ * uses of the terminal from within the program. See gl_raw_io()
+ * for more details.
+ *
+ * Input:
+ * gl GetLine * The line editor resource object.
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+int gl_normal_io(GetLine *gl)
+{
+ sigset_t oldset; /* The signals that were blocked on entry to this function */
+ int status; /* The return status of _gl_normal_io() */
+/*
+ * Check the arguments.
+ */
+ if(!gl) {
+ errno = EINVAL;
+ return 1;
+ };
+/*
+ * Block all signals.
+ */
+ if(gl_mask_signals(gl, &oldset))
+ return 1;
+/*
+ * Execute the private body of the function while signals are blocked.
+ */
+ status = _gl_normal_io(gl);
+/*
+ * Restore the process signal mask.
+ */
+ gl_unmask_signals(gl, &oldset);
+ return status;
+}
+
+/*.......................................................................
+ * This is the private body of the public function, gl_normal_io().
+ * It assumes that the caller has checked its arguments and blocked the
+ * delivery of signals.
+ */
+static int _gl_normal_io(GetLine *gl)
+{
+/*
+ * If we are already in normal mode, do nothing.
+ */
+ if(!gl->raw_mode)
+ return 0;
+/*
+ * Postpone subsequent redisplays until after _gl_raw_io(gl, 1)
+ * is next called.
+ */
+ gl->postpone = 1;
+/*
+ * Switch back to blocking I/O. Note that this is essential to do
+ * here, because when using non-blocking I/O, the terminal output
+ * buffering code can't always make room for new output without calling
+ * malloc(), and a call to malloc() would mean that this function
+ * couldn't safely be called from signal handlers.
+ */
+ if(gl->io_mode==GL_SERVER_MODE &&
+ (gl_blocking_io(gl, gl->input_fd) ||
+ gl_blocking_io(gl, gl->output_fd) ||
+ (gl->file_fp && gl_blocking_io(gl, fileno(gl->file_fp)))))
+ return 1;
+/*
+ * Move the cursor to the next empty terminal line. Note that
+ * unbuffered I/O is requested, to ensure that gl_start_newline() be
+ * async-signal-safe.
+ */
+ if(gl->is_term && gl_start_newline(gl, 0))
+ return 1;
+/*
+ * Switch the terminal to normal mode.
+ */
+ if(gl->is_term && gl_restore_terminal_attributes(gl)) {
+/*
+ * On error, revert to non-blocking I/O if needed, so that on failure
+ * we remain in raw mode.
+ */
+ if(gl->io_mode==GL_SERVER_MODE) {
+ gl_nonblocking_io(gl, gl->input_fd);
+ gl_nonblocking_io(gl, gl->output_fd);
+ if(gl->file_fp)
+ gl_nonblocking_io(gl, fileno(gl->file_fp));
+ };
+ return 1;
+ };
+ return 0;
+}
+
+/*.......................................................................
+ * This function allows you to install an additional completion
+ * action, or to change the completion function of an existing
+ * one. This should be called before the first call to gl_get_line()
+ * so that the name of the action be defined before the user's
+ * configuration file is read.
+ *
+ * Input:
+ * gl GetLine * The resource object of the command-line input
+ * module.
+ * data void * This is passed to match_fn() whenever it is
+ * called. It could, for example, point to a
+ * symbol table that match_fn() would look up
+ * matches in.
+ * match_fn CplMatchFn * The function that will identify the prefix
+ * to be completed from the input line, and
+ * report matching symbols.
+ * list_only int If non-zero, install an action that only lists
+ * possible completions, rather than attempting
+ * to perform the completion.
+ * name const char * The name with which users can refer to the
+ * binding in tecla configuration files.
+ * keyseq const char * Either NULL, or a key sequence with which
+ * to invoke the binding. This should be
+ * specified in the same manner as key-sequences
+ * in tecla configuration files (eg. "M-^I").
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+int gl_completion_action(GetLine *gl, void *data, CplMatchFn *match_fn,
+ int list_only, const char *name, const char *keyseq)
+{
+ sigset_t oldset; /* The signals that were blocked on entry to this function */
+ int status; /* The return status of _gl_completion_action() */
+/*
+ * Check the arguments.
+ */
+ if(!gl || !name || !match_fn) {
+ errno = EINVAL;
+ return 1;
+ };
+/*
+ * Block all signals.
+ */
+ if(gl_mask_signals(gl, &oldset))
+ return 1;
+/*
+ * Install the new action while signals are blocked.
+ */
+ status = _gl_completion_action(gl, data, match_fn, list_only, name, keyseq);
+/*
+ * Restore the process signal mask.
+ */
+ gl_unmask_signals(gl, &oldset);
+ return status;
+}
+
+/*.......................................................................
+ * This is the private body of the public function, gl_completion_action().
+ * It assumes that the caller has checked its arguments and blocked the
+ * delivery of signals.
+ */
+static int _gl_completion_action(GetLine *gl, void *data, CplMatchFn *match_fn,
+ int list_only, const char *name,
+ const char *keyseq)
+{
+ KtKeyFn *current_fn; /* An existing action function */
+ void *current_data; /* The action-function callback data */
+/*
+ * Which action function is desired?
+ */
+ KtKeyFn *action_fn = list_only ? gl_list_completions : gl_complete_word;
+/*
+ * Is there already an action of the specified name?
+ */
+ if(_kt_lookup_action(gl->bindings, name, &current_fn, &current_data) == 0) {
+/*
+ * If the action has the same type as the one being requested,
+ * simply change the contents of its GlCplCallback callback data.
+ */
+ if(current_fn == action_fn) {
+ GlCplCallback *cb = (GlCplCallback *) current_data;
+ cb->fn = match_fn;
+ cb->data = data;
+ } else {
+ errno = EINVAL;
+ _err_record_msg(gl->err,
+ "Illegal attempt to change the type of an existing completion action",
+ END_ERR_MSG);
+ return 1;
+ };
+/*
+ * No existing action has the specified name.
+ */
+ } else {
+/*
+ * Allocate a new GlCplCallback callback object.
+ */
+ GlCplCallback *cb = (GlCplCallback *) _new_FreeListNode(gl->cpl_mem);
+ if(!cb) {
+ errno = ENOMEM;
+ _err_record_msg(gl->err, "Insufficient memory to add completion action",
+ END_ERR_MSG);
+ return 1;
+ };
+/*
+ * Record the completion callback data.
+ */
+ cb->fn = match_fn;
+ cb->data = data;
+/*
+ * Attempt to register the new action.
+ */
+ if(_kt_set_action(gl->bindings, name, action_fn, cb)) {
+ _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG);
+ _del_FreeListNode(gl->cpl_mem, (void *) cb);
+ return 1;
+ };
+ };
+/*
+ * Bind the action to a given key-sequence?
+ */
+ if(keyseq && _kt_set_keybinding(gl->bindings, KTB_NORM, keyseq, name)) {
+ _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG);
+ return 1;
+ };
+ return 0;
+}
+
+/*.......................................................................
+ * Register an application-provided function as an action function.
+ * This should preferably be called before the first call to gl_get_line()
+ * so that the name of the action becomes defined before the user's
+ * configuration file is read.
+ *
+ * Input:
+ * gl GetLine * The resource object of the command-line input
+ * module.
+ * data void * Arbitrary application-specific callback
+ * data to be passed to the callback
+ * function, fn().
+ * fn GlActionFn * The application-specific function that
+ * implements the action. This will be invoked
+ * whenever the user presses any
+ * key-sequence which is bound to this action.
+ * name const char * The name with which users can refer to the
+ * binding in tecla configuration files.
+ * keyseq const char * The key sequence with which to invoke
+ * the binding. This should be specified in the
+ * same manner as key-sequences in tecla
+ * configuration files (eg. "M-^I").
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+int gl_register_action(GetLine *gl, void *data, GlActionFn *fn,
+ const char *name, const char *keyseq)
+{
+ sigset_t oldset; /* The signals that were blocked on entry to this function */
+ int status; /* The return status of _gl_register_action() */
+/*
+ * Check the arguments.
+ */
+ if(!gl || !name || !fn) {
+ errno = EINVAL;
+ return 1;
+ };
+/*
+ * Block all signals.
+ */
+ if(gl_mask_signals(gl, &oldset))
+ return 1;
+/*
+ * Install the new action while signals are blocked.
+ */
+ status = _gl_register_action(gl, data, fn, name, keyseq);
+/*
+ * Restore the process signal mask.
+ */
+ gl_unmask_signals(gl, &oldset);
+ return status;
+}
+
+/*.......................................................................
+ * This is the private body of the public function, gl_register_action().
+ * It assumes that the caller has checked its arguments and blocked the
+ * delivery of signals.
+ */
+static int _gl_register_action(GetLine *gl, void *data, GlActionFn *fn,
+ const char *name, const char *keyseq)
+{
+ KtKeyFn *current_fn; /* An existing action function */
+ void *current_data; /* The action-function callback data */
+/*
+ * Get the action function which actually runs the application-provided
+ * function.
+ */
+ KtKeyFn *action_fn = gl_run_external_action;
+/*
+ * Is there already an action of the specified name?
+ */
+ if(_kt_lookup_action(gl->bindings, name, &current_fn, &current_data) == 0) {
+/*
+ * If the action has the same type as the one being requested,
+ * simply change the contents of its GlCplCallback callback data.
+ */
+ if(current_fn == action_fn) {
+ GlExternalAction *a = (GlExternalAction *) current_data;
+ a->fn = fn;
+ a->data = data;
+ } else {
+ errno = EINVAL;
+ _err_record_msg(gl->err,
+ "Illegal attempt to change the type of an existing action",
+ END_ERR_MSG);
+ return 1;
+ };
+/*
+ * No existing action has the specified name.
+ */
+ } else {
+/*
+ * Allocate a new GlCplCallback callback object.
+ */
+ GlExternalAction *a =
+ (GlExternalAction *) _new_FreeListNode(gl->ext_act_mem);
+ if(!a) {
+ errno = ENOMEM;
+ _err_record_msg(gl->err, "Insufficient memory to add completion action",
+ END_ERR_MSG);
+ return 1;
+ };
+/*
+ * Record the completion callback data.
+ */
+ a->fn = fn;
+ a->data = data;
+/*
+ * Attempt to register the new action.
+ */
+ if(_kt_set_action(gl->bindings, name, action_fn, a)) {
+ _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG);
+ _del_FreeListNode(gl->cpl_mem, (void *) a);
+ return 1;
+ };
+ };
+/*
+ * Bind the action to a given key-sequence?
+ */
+ if(keyseq && _kt_set_keybinding(gl->bindings, KTB_NORM, keyseq, name)) {
+ _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG);
+ return 1;
+ };
+ return 0;
+}
+
+/*.......................................................................
+ * Invoke an action function previously registered by a call to
+ * gl_register_action().
+ */
+static KT_KEY_FN(gl_run_external_action)
+{
+ GlAfterAction status; /* The return value of the action function */
+/*
+ * Get the container of the action function and associated callback data.
+ */
+ GlExternalAction *a = (GlExternalAction *) data;
+/*
+ * Invoke the action function.
+ */
+ status = a->fn(gl, a->data, count, gl->buff_curpos, gl->line);
+/*
+ * If the callback took us out of raw (possibly non-blocking) input
+ * mode, restore this mode, and queue a redisplay of the input line.
+ */
+ if(_gl_raw_io(gl, 1))
+ return 1;
+/*
+ * Finally, check to see what the action function wants us to do next.
+ */
+ switch(status) {
+ default:
+ case GLA_ABORT:
+ gl_record_status(gl, GLR_ERROR, errno);
+ return 1;
+ break;
+ case GLA_RETURN:
+ return gl_newline(gl, 1, NULL);
+ break;
+ case GLA_CONTINUE:
+ break;
+ };
+ return 0;
+}
+
+/*.......................................................................
+ * In server-I/O mode the terminal is left in raw mode between calls
+ * to gl_get_line(), so it is necessary for the application to install
+ * terminal restoring signal handlers for signals that could terminate
+ * or suspend the process, plus a terminal reconfiguration handler to
+ * be called when a process resumption signal is received, and finally
+ * a handler to be called when a terminal-resize signal is received.
+ *
+ * Since there are many signals that by default terminate or suspend
+ * processes, and different systems support different sub-sets of
+ * these signals, this function provides a convenient wrapper around
+ * sigaction() for assigning the specified handlers to all appropriate
+ * signals. It also arranges that when any one of these signals is
+ * being handled, all other catchable signals are blocked. This is
+ * necessary so that the specified signal handlers can safely call
+ * gl_raw_io(), gl_normal_io() and gl_update_size() without
+ * reentrancy issues.
+ *
+ * Input:
+ * term_handler void (*)(int) The signal handler to invoke when
+ * a process-terminating signal is
+ * received.
+ * susp_handler void (*)(int) The signal handler to invoke when
+ * a process-suspending signal is
+ * received.
+ * cont_handler void (*)(int) The signal handler to invoke when
+ * a process-resumption signal is
+ * received (ie. SIGCONT).
+ * size_handler void (*)(int) The signal handler to invoke when
+ * a terminal-resize signal (ie. SIGWINCH)
+ * is received.
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+int gl_tty_signals(void (*term_handler)(int), void (*susp_handler)(int),
+ void (*cont_handler)(int), void (*size_handler)(int))
+{
+ int i;
+/*
+ * Search for signals of the specified classes, and assign the
+ * associated signal handler to them.
+ */
+ for(i=0; i<sizeof(gl_signal_list)/sizeof(gl_signal_list[0]); i++) {
+ const struct GlDefSignal *sig = gl_signal_list + i;
+ if(sig->attr & GLSA_SUSP) {
+ if(gl_set_tty_signal(sig->signo, susp_handler))
+ return 1;
+ } else if(sig->attr & GLSA_TERM) {
+ if(gl_set_tty_signal(sig->signo, term_handler))
+ return 1;
+ } else if(sig->attr & GLSA_CONT) {
+ if(gl_set_tty_signal(sig->signo, cont_handler))
+ return 1;
+ } else if(sig->attr & GLSA_SIZE) {
+ if(gl_set_tty_signal(sig->signo, size_handler))
+ return 1;
+ };
+ };
+ return 0;
+}
+
+/*.......................................................................
+ * This is a private function of gl_tty_signals(). It installs a given
+ * signal handler, and arranges that when that signal handler is being
+ * invoked other signals are blocked. The latter is important to allow
+ * functions like gl_normal_io(), gl_raw_io() and gl_update_size()
+ * to be called from signal handlers.
+ *
+ * Input:
+ * signo int The signal to be trapped.
+ * handler void (*)(int) The signal handler to assign to the signal.
+ */
+static int gl_set_tty_signal(int signo, void (*handler)(int))
+{
+ SigAction act; /* The signal handler configuation */
+/*
+ * Arrange to block all trappable signals except the one that is being
+ * assigned (the trapped signal will be blocked automatically by the
+ * system).
+ */
+ gl_list_trappable_signals(&act.sa_mask);
+ sigdelset(&act.sa_mask, signo);
+/*
+ * Assign the signal handler.
+ */
+ act.sa_handler = handler;
+/*
+ * There is only one portable signal handling flag, and it isn't
+ * relevant to us, so don't specify any flags.
+ */
+ act.sa_flags = 0;
+/*
+ * Register the signal handler.
+ */
+ if(sigaction(signo, &act, NULL))
+ return 1;
+ return 0;
+}
+
+/*.......................................................................
+ * Display a left-justified string over multiple terminal lines,
+ * taking account of the current width of the terminal. Optional
+ * indentation and an optional prefix string can be specified to be
+ * displayed at the start of each new terminal line used. Similarly,
+ * an optional suffix can be specified to be displayed at the end of
+ * each terminal line. If needed, a single paragraph can be broken
+ * across multiple calls. Note that literal newlines in the input
+ * string can be used to force a newline at any point and that you
+ * should use this feature to explicitly end all paragraphs, including
+ * at the end of the last string that you write. Note that when a new
+ * line is started between two words that are separated by spaces,
+ * those spaces are not output, whereas when a new line is started
+ * because a newline character was found in the string, only the
+ * spaces before the newline character are discarded.
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ * indentation int The number of spaces of indentation to write
+ * at the beginning of each new terminal line.
+ * prefix const char * An optional prefix string to write after the
+ * indentation margin at the start of each new
+ * terminal line. You can specify NULL if no
+ * prefix is required.
+ * suffix const char * An optional suffix string to draw at the end
+ * of the terminal line. Spaces will be added
+ * where necessary to ensure that the suffix ends
+ * in the last column of the terminal line. If
+ * no suffix is desired, specify NULL.
+ * fill_char int The padding character to use when indenting
+ * the line or padding up to the suffix.
+ * def_width int If the terminal width isn't known, such as when
+ * writing to a pipe or redirecting to a file,
+ * this number specifies what width to assume.
+ * start int The number of characters already written to
+ * the start of the current terminal line. This
+ * is primarily used to allow individual
+ * paragraphs to be written over multiple calls
+ * to this function, but can also be used to
+ * allow you to start the first line of a
+ * paragraph with a different prefix or
+ * indentation than those specified above.
+ * string const char * The string to be written.
+ * Output:
+ * return int On error -1 is returned. Otherwise the
+ * return value is the terminal column index at
+ * which the cursor was left after writing the
+ * final word in the string. Successful return
+ * values can thus be passed verbatim to the
+ * 'start' arguments of subsequent calls to
+ * gl_display_text() to allow the printing of a
+ * paragraph to be broken across multiple calls
+ * to gl_display_text().
+ */
+int gl_display_text(GetLine *gl, int indentation, const char *prefix,
+ const char *suffix, int fill_char,
+ int def_width, int start, const char *string)
+{
+ sigset_t oldset; /* The signals that were blocked on entry to this function */
+ int status; /* The return status of _gl_completion_action() */
+/*
+ * Check the arguments?
+ */
+ if(!gl || !string) {
+ errno = EINVAL;
+ return -1;
+ };
+/*
+ * Block all signals.
+ */
+ if(gl_mask_signals(gl, &oldset))
+ return -1;
+/*
+ * Display the text while signals are blocked.
+ */
+ status = _io_display_text(_io_write_stdio, gl->output_fp, indentation,
+ prefix, suffix, fill_char,
+ gl->ncolumn > 0 ? gl->ncolumn : def_width,
+ start, string);
+/*
+ * Restore the process signal mask.
+ */
+ gl_unmask_signals(gl, &oldset);
+ return status;
+}
+
+/*.......................................................................
+ * Block all of the signals that we are currently trapping.
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ * Input/Output:
+ * oldset sigset_t * The superseded process signal mask
+ * will be return in *oldset unless oldset is
+ * NULL.
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+static int gl_mask_signals(GetLine *gl, sigset_t *oldset)
+{
+/*
+ * Block all signals in all_signal_set, along with any others that are
+ * already blocked by the application.
+ */
+ if(sigprocmask(SIG_BLOCK, &gl->all_signal_set, oldset) >= 0) {
+ gl->signals_masked = 1;
+ return 0;
+ };
+/*
+ * On error attempt to query the current process signal mask, so
+ * that oldset be the correct process signal mask to restore later
+ * if the caller of this function ignores the error return value.
+ */
+ if(oldset)
+ (void) sigprocmask(SIG_SETMASK, NULL, oldset);
+ gl->signals_masked = 0;
+ return 1;
+}
+
+/*.......................................................................
+ * Restore a process signal mask that was previously returned via the
+ * oldset argument of gl_mask_signals().
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ * Input/Output:
+ * oldset sigset_t * The process signal mask to be restored.
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+static int gl_unmask_signals(GetLine *gl, sigset_t *oldset)
+{
+ gl->signals_masked = 0;
+ return sigprocmask(SIG_SETMASK, oldset, NULL) < 0;
+}
+
+/*.......................................................................
+ * Arrange to temporarily catch the signals marked in gl->use_signal_set.
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+static int gl_catch_signals(GetLine *gl)
+{
+ return sigprocmask(SIG_UNBLOCK, &gl->use_signal_set, NULL) < 0;
+}
+
+/*.......................................................................
+ * Select the I/O mode to be used by gl_get_line().
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ * mode GlIOMode The I/O mode to establish.
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+int gl_io_mode(GetLine *gl, GlIOMode mode)
+{
+ sigset_t oldset; /* The signals that were blocked on entry to this function */
+ int status; /* The return status of _gl_io_mode() */
+/*
+ * Check the arguments.
+ */
+ if(!gl) {
+ errno = EINVAL;
+ return 1;
+ };
+/*
+ * Check that the requested mode is known.
+ */
+ switch(mode) {
+ case GL_NORMAL_MODE:
+ case GL_SERVER_MODE:
+ break;
+ default:
+ errno = EINVAL;
+ _err_record_msg(gl->err, "Unknown gl_get_line() I/O mode requested.",
+ END_ERR_MSG);
+ return 1;
+ };
+/*
+ * Block all signals.
+ */
+ if(gl_mask_signals(gl, &oldset))
+ return 1;
+/*
+ * Invoke the private body of this function.
+ */
+ status = _gl_io_mode(gl, mode);
+/*
+ * Restore the process signal mask.
+ */
+ gl_unmask_signals(gl, &oldset);
+ return status;
+}
+
+/*.......................................................................
+ * This is the private body of the public function, gl_io_mode().
+ * It assumes that the caller has checked its arguments and blocked the
+ * delivery of signals.
+ */
+static int _gl_io_mode(GetLine *gl, GlIOMode mode)
+{
+/*
+ * Are we already in the specified mode?
+ */
+ if(mode == gl->io_mode)
+ return 0;
+/*
+ * First revert to normal I/O in the current I/O mode.
+ */
+ _gl_normal_io(gl);
+/*
+ * Record the new mode.
+ */
+ gl->io_mode = mode;
+/*
+ * Perform any actions needed by the new mode.
+ */
+ if(mode==GL_SERVER_MODE) {
+ if(_gl_raw_io(gl, 1))
+ return 1;
+ };
+ return 0;
+}
+
+/*.......................................................................
+ * Return extra information (ie. in addition to that provided by errno)
+ * about the last error to occur in either gl_get_line() or its
+ * associated public functions.
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ * Input/Output:
+ * buff char * An optional output buffer. Note that if the
+ * calling application calls any gl_*()
+ * functions from signal handlers, it should
+ * provide a buffer here, so that a copy of
+ * the latest error message can safely be made
+ * while signals are blocked.
+ * n size_t The allocated size of buff[].
+ * Output:
+ * return const char * A pointer to the error message. This will
+ * be the buff argument, unless buff==NULL, in
+ * which case it will be a pointer to an
+ * internal error buffer. In the latter case,
+ * note that the contents of the returned buffer
+ * will change on subsequent calls to any gl_*()
+ * functions.
+ */
+const char *gl_error_message(GetLine *gl, char *buff, size_t n)
+{
+ if(!gl) {
+ static const char *msg = "NULL GetLine argument";
+ if(buff) {
+ strncpy(buff, msg, n);
+ buff[n-1] = '\0';
+ } else {
+ return msg;
+ };
+ } else if(buff) {
+ sigset_t oldset; /* The signals that were blocked on entry to this block */
+/*
+ * Temporarily block all signals.
+ */
+ gl_mask_signals(gl, &oldset);
+/*
+ * Copy the error message into the specified buffer.
+ */
+ if(buff && n > 0) {
+ strncpy(buff, _err_get_msg(gl->err), n);
+ buff[n-1] = '\0';
+ };
+/*
+ * Restore the process signal mask before returning.
+ */
+ gl_unmask_signals(gl, &oldset);
+ } else {
+ return _err_get_msg(gl->err);
+ };
+ return buff;
+}
+
+/*.......................................................................
+ * Return the signal mask used by gl_get_line(). This is the set of
+ * signals that gl_get_line() is currently configured to trap.
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ * Input/Output:
+ * set sigset_t * The set of signals will be returned in *set,
+ * in the form of a signal process mask, as
+ * used by sigaction(), sigprocmask(),
+ * sigpending(), sigsuspend(), sigsetjmp() and
+ * other standard POSIX signal-aware
+ * functions.
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error (examine errno for reason).
+ */
+int gl_list_signals(GetLine *gl, sigset_t *set)
+{
+/*
+ * Check the arguments.
+ */
+ if(!gl || !set) {
+ if(gl)
+ _err_record_msg(gl->err, "NULL argument(s)", END_ERR_MSG);
+ errno = EINVAL;
+ return 1;
+ };
+/*
+ * Copy the signal mask into *set.
+ */
+ memcpy(set, &gl->all_signal_set, sizeof(*set));
+ return 0;
+}
+
+/*.......................................................................
+ * By default, gl_get_line() doesn't trap signals that are blocked
+ * when it is called. This default can be changed either on a
+ * per-signal basis by calling gl_trap_signal(), or on a global basis
+ * by calling this function. What this function does is add the
+ * GLS_UNBLOCK_SIG flag to all signals that are currently configured
+ * to be trapped by gl_get_line(), such that when subsequent calls to
+ * gl_get_line() wait for I/O, these signals are temporarily
+ * unblocked. This behavior is useful in non-blocking server-I/O mode,
+ * where it is used to avoid race conditions related to handling these
+ * signals externally to gl_get_line(). See the demonstration code in
+ * demo3.c, or the gl_handle_signal() man page for further
+ * information.
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ */
+void gl_catch_blocked(GetLine *gl)
+{
+ sigset_t oldset; /* The process signal mask to restore */
+ GlSignalNode *sig; /* A signal node in gl->sigs */
+/*
+ * Check the arguments.
+ */
+ if(!gl) {
+ errno = EINVAL;
+ return;
+ };
+/*
+ * Temporarily block all signals while we modify the contents of gl.
+ */
+ gl_mask_signals(gl, &oldset);
+/*
+ * Add the GLS_UNBLOCK_SIG flag to all configured signals.
+ */
+ for(sig=gl->sigs; sig; sig=sig->next)
+ sig->flags |= GLS_UNBLOCK_SIG;
+/*
+ * Restore the process signal mask that was superseded by the call
+ * to gl_mask_signals().
+ */
+ gl_unmask_signals(gl, &oldset);
+ return;
+}
+
+/*.......................................................................
+ * Respond to signals who's default effects have important
+ * consequences to gl_get_line(). This is intended for use in
+ * non-blocking server mode, where the external event loop is
+ * responsible for catching signals. Signals that are handled include
+ * those that by default terminate or suspend the process, and the
+ * signal that indicates that the terminal size has changed. Note that
+ * this function is not signal safe and should thus not be called from
+ * a signal handler itself. See the gl_io_mode() man page for how it
+ * should be used.
+ *
+ * In the case of signals that by default terminate or suspend
+ * processes, command-line editing will be suspended, the terminal
+ * returned to a usable state, then the default disposition of the
+ * signal restored and the signal resent, in order to suspend or
+ * terminate the process. If the process subsequently resumes,
+ * command-line editing is resumed.
+ *
+ * In the case of signals that indicate that the terminal has been
+ * resized, the new size will be queried, and any input line that is
+ * being edited will be redrawn to fit the new dimensions of the
+ * terminal.
+ *
+ * Input:
+ * signo int The number of the signal to respond to.
+ * gl GetLine * The first element of an array of 'ngl' GetLine
+ * objects.
+ * ngl int The number of elements in the gl[] array. Normally
+ * this will be one.
+ */
+void gl_handle_signal(int signo, GetLine *gl, int ngl)
{
- return gl ? gl->last_signal : -1;
+ int attr; /* The attributes of the specified signal */
+ sigset_t all_signals; /* The set of trappable signals */
+ sigset_t oldset; /* The process signal mask to restore */
+ int i;
+/*
+ * NULL operation?
+ */
+ if(ngl < 1 || !gl)
+ return;
+/*
+ * Look up the default attributes of the specified signal.
+ */
+ attr = gl_classify_signal(signo);
+/*
+ * If the signal isn't known, we are done.
+ */
+ if(!attr)
+ return;
+/*
+ * Temporarily block all signals while we modify the gl objects.
+ */
+ gl_list_trappable_signals(&all_signals);
+ sigprocmask(SIG_BLOCK, &all_signals, &oldset);
+/*
+ * Suspend or terminate the process?
+ */
+ if(attr & (GLSA_SUSP | GLSA_TERM)) {
+ gl_suspend_process(signo, gl, ngl);
+/*
+ * Resize the terminal? Note that ioctl() isn't defined as being
+ * signal safe, so we can't call gl_update_size() here. However,
+ * gl_get_line() checks for resizes on each call, so simply arrange
+ * for the application's event loop to call gl_get_line() as soon as
+ * it becomes possible to write to the terminal. Note that if the
+ * caller is calling select() or poll when this happens, these functions
+ * get interrupted, since a signal has been caught.
+ */
+ } else if(attr & GLSA_SIZE) {
+ for(i=0; i<ngl; i++)
+ gl[i].pending_io = GLP_WRITE;
+ };
+/*
+ * Restore the process signal mask that was superseded by the call
+ * to gl_mask_signals().
+ */
+ sigprocmask(SIG_SETMASK, &oldset, NULL);
+ return;
}
+
+/*.......................................................................
+ * Respond to an externally caught process suspension or
+ * termination signal.
+ *
+ * After restoring the terminal to a usable state, suspend or
+ * terminate the calling process, using the original signal with its
+ * default disposition restored to do so. If the process subsequently
+ * resumes, resume editing any input lines that were being entered.
+ *
+ * Input:
+ * signo int The signal number to suspend the process with. Note
+ * that the default disposition of this signal will be
+ * restored before the signal is sent, so provided
+ * that the default disposition of this signal is to
+ * either suspend or terminate the application,
+ * that is what wil happen, regardless of what signal
+ * handler is currently assigned to this signal.
+ * gl GetLine * The first element of an array of 'ngl' GetLine objects
+ * whose terminals should be restored to a sane state
+ * while the application is suspended.
+ * ngl int The number of elements in the gl[] array.
+ */
+static void gl_suspend_process(int signo, GetLine *gl, int ngl)
+{
+ sigset_t only_signo; /* A signal set containing just signo */
+ sigset_t oldset; /* The signal mask on entry to this function */
+ sigset_t all_signals; /* A signal set containing all signals */
+ struct sigaction old_action; /* The current signal handler */
+ struct sigaction def_action; /* The default signal handler */
+ int i;
+/*
+ * Create a signal mask containing the signal that was trapped.
+ */
+ sigemptyset(&only_signo);
+ sigaddset(&only_signo, signo);
+/*
+ * Temporarily block all signals.
+ */
+ gl_list_trappable_signals(&all_signals);
+ sigprocmask(SIG_BLOCK, &all_signals, &oldset);
+/*
+ * Restore the terminal to a usable state.
+ */
+ for(i=0; i<ngl; i++) {
+ GetLine *obj = gl + i;
+ if(obj->raw_mode) {
+ _gl_normal_io(obj);
+ if(!obj->raw_mode) /* Check that gl_normal_io() succeded */
+ obj->raw_mode = -1; /* Flag raw mode as needing to be restored */
+ };
+ };
+/*
+ * Restore the system default disposition of the signal that we
+ * caught. Note that this signal is currently blocked. Note that we
+ * don't use memcpy() to copy signal sets here, because the signal safety
+ * of memcpy() is undefined.
+ */
+ def_action.sa_handler = SIG_DFL;
+ {
+ char *orig = (char *) &all_signals;
+ char *dest = (char *) &def_action.sa_mask;
+ for(i=0; i<sizeof(sigset_t); i++)
+ *dest++ = *orig++;
+ };
+ sigaction(signo, &def_action, &old_action);
+/*
+ * Resend the signal, and unblock it so that it gets delivered to
+ * the application. This will invoke the default action of this signal.
+ */
+ raise(signo);
+ sigprocmask(SIG_UNBLOCK, &only_signo, NULL);
+/*
+ * If the process resumes again, it will resume here.
+ * Block the signal again, then restore our signal handler.
+ */
+ sigprocmask(SIG_BLOCK, &only_signo, NULL);
+ sigaction(signo, &old_action, NULL);
+/*
+ * Resume command-line editing.
+ */
+ for(i=0; i<ngl; i++) {
+ GetLine *obj = gl + i;
+ if(obj->raw_mode == -1) { /* Did we flag the need to restore raw mode? */
+ obj->raw_mode = 0; /* gl_raw_io() does nothing unless raw_mode==0 */
+ _gl_raw_io(obj, 1);
+ };
+ };
+/*
+ * Restore the process signal mask to the way it was when this function
+ * was called.
+ */
+ sigprocmask(SIG_SETMASK, &oldset, NULL);
+ return;
+}
+
+/*.......................................................................
+ * Return the information about the default attributes of a given signal.
+ * The attributes that are returned are as defined by the standards that
+ * created them, including POSIX, SVR4 and 4.3+BSD, and are taken from a
+ * table in Richard Steven's book, "Advanced programming in the UNIX
+ * environment".
+ *
+ * Input:
+ * signo int The signal to be characterized.
+ * Output:
+ * return int A bitwise union of GlSigAttr enumerators, or 0
+ * if the signal isn't known.
+ */
+static int gl_classify_signal(int signo)
+{
+ int i;
+/*
+ * Search for the specified signal in the gl_signal_list[] table.
+ */
+ for(i=0; i<sizeof(gl_signal_list)/sizeof(gl_signal_list[0]); i++) {
+ const struct GlDefSignal *sig = gl_signal_list + i;
+ if(sig->signo == signo)
+ return sig->attr;
+ };
+/*
+ * Signal not known.
+ */
+ return 0;
+}
+
+/*.......................................................................
+ * When in non-blocking server mode, this function can be used to abandon
+ * the current incompletely entered input line, and prepare to start
+ * editing a new line on the next call to gl_get_line().
+ *
+ * Input:
+ * gl GetLine * The line editor resource object.
+ */
+void gl_abandon_line(GetLine *gl)
+{
+ sigset_t oldset; /* The process signal mask to restore */
+/*
+ * Check the arguments.
+ */
+ if(!gl) {
+ errno = EINVAL;
+ return;
+ };
+/*
+ * Temporarily block all signals while we modify the contents of gl.
+ */
+ gl_mask_signals(gl, &oldset);
+/*
+ * Mark the input line as discarded.
+ */
+ _gl_abandon_line(gl);
+/*
+ * Restore the process signal mask that was superseded by the call
+ * to gl_mask_signals().
+ */
+ gl_unmask_signals(gl, &oldset);
+ return;
+}
+
+/*.......................................................................
+ * This is the private body of the gl_abandon_line() function. It
+ * assumes that the caller has checked its arguments and blocked the
+ * delivery of signals.
+ */
+void _gl_abandon_line(GetLine *gl)
+{
+ gl->endline = 1;
+ gl->pending_io = GLP_WRITE;
+}
+
+/*.......................................................................
+ * How many characters are needed to write a number as an octal string?
+ *
+ * Input:
+ * num unsigned The to be measured.
+ * Output:
+ * return int The number of characters needed.
+ */
+static int gl_octal_width(unsigned num)
+{
+ int n; /* The number of characters needed to render the number */
+ for(n=1; num /= 8; n++)
+ ;
+ return n;
+}
+
+/*.......................................................................
+ * Tell gl_get_line() the current terminal size. Note that this is only
+ * necessary on systems where changes in terminal size aren't reported
+ * via SIGWINCH.
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ * ncolumn int The number of columns in the terminal.
+ * nline int The number of lines in the terminal.
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+int gl_set_term_size(GetLine *gl, int ncolumn, int nline)
+{
+ sigset_t oldset; /* The signals that were blocked on entry */
+ /* to this function */
+ int status; /* The return status */
+/*
+ * Block all signals while accessing gl.
+ */
+ gl_mask_signals(gl, &oldset);
+/*
+ * Install the new terminal size.
+ */
+ status = _gl_set_term_size(gl, ncolumn, nline);
+/*
+ * Restore the process signal mask before returning.
+ */
+ gl_unmask_signals(gl, &oldset);
+ return status;
+}
+
+/*.......................................................................
+ * This is the private body of the gl_set_term_size() function. It
+ * assumes that the caller has checked its arguments and blocked the
+ * delivery of signals.
+ */
+static int _gl_set_term_size(GetLine *gl, int ncolumn, int nline)
+{
+/*
+ * Check the arguments.
+ */
+ if(!gl) {
+ errno = EINVAL;
+ return 1;
+ };
+/*
+ * Reject non-sensical dimensions.
+ */
+ if(ncolumn <= 0 || nline <= 0) {
+ _err_record_msg(gl->err, "Invalid terminal size", END_ERR_MSG);
+ errno = EINVAL;
+ return 1;
+ };
+/*
+ * Install the new dimensions in the terminal driver if possible, so
+ * that future calls to gl_query_size() get the new value.
+ */
+#ifdef TIOCSWINSZ
+ if(gl->is_term) {
+ struct winsize size;
+ size.ws_row = nline;
+ size.ws_col = ncolumn;
+ size.ws_xpixel = 0;
+ size.ws_ypixel = 0;
+ if(ioctl(gl->output_fd, TIOCSWINSZ, &size) == -1) {
+ _err_record_msg(gl->err, "Can't change terminal size", END_ERR_MSG);
+ return 1;
+ };
+ };
+#endif
+/*
+ * If an input line is in the process of being edited, redisplay it to
+ * accomodate the new dimensions, and record the new dimensions in
+ * gl->nline and gl->ncolumn.
+ */
+ return gl_handle_tty_resize(gl, ncolumn, nline);
+}
+
+/*.......................................................................
+ * Record a character in the input line buffer at a given position.
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ * c char The character to be recorded.
+ * bufpos int The index in the buffer at which to record the
+ * character.
+ * Output:
+ * return int 0 - OK.
+ * 1 - Insufficient room.
+ */
+static int gl_buffer_char(GetLine *gl, char c, int bufpos)
+{
+/*
+ * Guard against buffer overruns.
+ */
+ if(bufpos >= gl->linelen)
+ return 1;
+/*
+ * Record the new character.
+ */
+ gl->line[bufpos] = c;
+/*
+ * If the new character was placed beyond the end of the current input
+ * line, update gl->ntotal to reflect the increased number of characters
+ * that are in gl->line, and terminate the string.
+ */
+ if(bufpos >= gl->ntotal) {
+ gl->ntotal = bufpos+1;
+ gl->line[gl->ntotal] = '\0';
+ };
+ return 0;
+}
+
+/*.......................................................................
+ * Copy a given string into the input buffer, overwriting the current
+ * contents.
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ * s const char * The string to be recorded.
+ * n int The number of characters to be copied from the
+ * string.
+ * bufpos int The index in the buffer at which to place the
+ * the first character of the string.
+ * Output:
+ * return int 0 - OK.
+ * 1 - String truncated to fit.
+ */
+static int gl_buffer_string(GetLine *gl, const char *s, int n, int bufpos)
+{
+ int nnew; /* The number of characters actually recorded */
+ int i;
+/*
+ * How many of the characters will fit within the buffer?
+ */
+ nnew = bufpos + n <= gl->linelen ? n : (gl->linelen - bufpos);
+/*
+ * Record the first nnew characters of s[] in the buffer.
+ */
+ for(i=0; i<nnew; i++)
+ gl_buffer_char(gl, s[i], bufpos + i);
+/*
+ * Was the string truncated?
+ */
+ return nnew < n;
+}
+
+/*.......................................................................
+ * Make room in the input buffer for a string to be inserted. This
+ * involves moving the characters that follow a specified point, towards
+ * the end of the buffer.
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ * start int The index of the first character to be moved.
+ * n int The width of the gap.
+ * Output:
+ * return int 0 - OK.
+ * 1 - Insufficient room.
+ */
+static int gl_make_gap_in_buffer(GetLine *gl, int start, int n)
+{
+/*
+ * Ensure that the buffer has sufficient space.
+ */
+ if(gl->ntotal + n > gl->linelen)
+ return 1;
+/*
+ * Move everything including and beyond the character at 'start'
+ * towards the end of the string.
+ */
+ memmove(gl->line + start + n, gl->line + start, gl->ntotal - start + 1);
+/*
+ * Update the recorded size of the line.
+ */
+ gl->ntotal += n;
+ return 1;
+}
+
+/*.......................................................................
+ * Remove a given number of characters from the input buffer. This
+ * involves moving the characters that follow the removed characters to
+ * where the removed sub-string started in the input buffer.
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ * start int The first character to be removed.
+ * n int The number of characters to remove.
+ */
+static void gl_remove_from_buffer(GetLine *gl, int start, int n)
+{
+ memmove(gl->line + start, gl->line + start + n, gl->ntotal - start - n + 1);
+/*
+ * Update the recorded size of the line.
+ */
+ gl->ntotal -= n;
+}
+
+/*.......................................................................
+ * Truncate the string in the input line buffer after a given number of
+ * characters.
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ * n int The new length of the line.
+ * Output:
+ * return int 0 - OK.
+ * 1 - n > gl->linelen.
+ */
+static int gl_truncate_buffer(GetLine *gl, int n)
+{
+ if(n > gl->linelen)
+ return 1;
+ gl->line[n] = '\0';
+ gl->ntotal = n;
+ return 0;
+}
+
+/*.......................................................................
+ * When the contents of gl->line[] are changed without calling any of the
+ * gl_ buffer manipulation functions, this function must be called to
+ * compute the length of this string, and ancillary information.
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ */
+static void gl_update_buffer(GetLine *gl)
+{
+ int len; /* The length of the line */
+/*
+ * Measure the length of the input line.
+ */
+ for(len=0; len <= gl->linelen && gl->line[len]; len++)
+ ;
+/*
+ * Just in case the string wasn't correctly terminated, do so here.
+ */
+ gl->line[len] = '\0';
+/*
+ * Record the number of characters that are now in gl->line[].
+ */
+ gl->ntotal = len;
+/*
+ * Ensure that the cursor stays within the bounds of the modified
+ * input line.
+ */
+ if(gl->buff_curpos > gl->ntotal)
+ gl->buff_curpos = gl->ntotal;
+/*
+ * Arrange for the input line to be redrawn.
+ */
+ gl_queue_redisplay(gl);
+ return;
+}
+
+/*.......................................................................
+ * Erase the displayed input line, including its prompt, and leave the
+ * cursor where the erased line started. Note that to allow this
+ * function to be used when responding to a terminal resize, this
+ * function is designed to work even if the horizontal cursor position
+ * doesn't match the internally recorded position.
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+static int gl_erase_line(GetLine *gl)
+{
+/*
+ * Is a line currently displayed?
+ */
+ if(gl->displayed) {
+/*
+ * Relative the the start of the input line, which terminal line of
+ * the current input line is the cursor currently on?
+ */
+ int cursor_line = gl->term_curpos / gl->ncolumn;
+/*
+ * Move the cursor to the start of the line.
+ */
+ for( ; cursor_line > 0; cursor_line--) {
+ if(gl_print_control_sequence(gl, 1, gl->up))
+ return 1;
+ };
+ if(gl_print_control_sequence(gl, 1, gl->bol))
+ return 1;
+/*
+ * Clear from the start of the line to the end of the terminal.
+ */
+ if(gl_print_control_sequence(gl, gl->nline, gl->clear_eod))
+ return 1;
+/*
+ * Mark the line as no longer displayed.
+ */
+ gl_line_erased(gl);
+ };
+ return 0;
+}
+
+/*.......................................................................
+ * Arrange for the input line to be redisplayed by gl_flush_output(),
+ * as soon as the output queue becomes empty.
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ */
+static void gl_queue_redisplay(GetLine *gl)
+{
+ gl->redisplay = 1;
+ gl->pending_io = GLP_WRITE;
+}
+
+/*.......................................................................
+ * Truncate the displayed input line starting from the current
+ * terminal cursor position, and leave the cursor at the end of the
+ * truncated line. The input-line buffer is not affected.
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+static int gl_truncate_display(GetLine *gl)
+{
+/*
+ * Keep a record of the current terminal cursor position.
+ */
+ int term_curpos = gl->term_curpos;
+/*
+ * First clear from the cursor to the end of the current input line.
+ */
+ if(gl_print_control_sequence(gl, 1, gl->clear_eol))
+ return 1;
+/*
+ * If there is more than one line displayed, go to the start of the
+ * next line and clear from there to the end of the display. Note that
+ * we can't use clear_eod to do the whole job of clearing from the
+ * current cursor position to the end of the terminal because
+ * clear_eod is only defined when used at the start of a terminal line
+ * (eg. with gnome terminals, clear_eod clears from the start of the
+ * current terminal line, rather than from the current cursor
+ * position).
+ */
+ if(gl->term_len / gl->ncolumn > gl->term_curpos / gl->ncolumn) {
+ if(gl_print_control_sequence(gl, 1, gl->down) ||
+ gl_print_control_sequence(gl, 1, gl->bol) ||
+ gl_print_control_sequence(gl, gl->nline, gl->clear_eod))
+ return 1;
+/*
+ * Where is the cursor now?
+ */
+ gl->term_curpos = gl->ncolumn * (term_curpos / gl->ncolumn + 1);
+/*
+ * Restore the cursor position.
+ */
+ gl_set_term_curpos(gl, term_curpos);
+ };
+/*
+ * Update the recorded position of the final character.
+ */
+ gl->term_len = gl->term_curpos;
+ return 0;
+}
+
+/*.......................................................................
+ * Return the set of all trappable signals.
+ *
+ * Input:
+ * signals sigset_t * The set of signals will be recorded in
+ * *signals.
+ */
+static void gl_list_trappable_signals(sigset_t *signals)
+{
+/*
+ * Start with the set of all signals.
+ */
+ sigfillset(signals);
+/*
+ * Remove un-trappable signals from this set.
+ */
+#ifdef SIGKILL
+ sigdelset(signals, SIGKILL);
+#endif
+#ifdef SIGSTOP
+ sigdelset(signals, SIGSTOP);
+#endif
+}
+
+/*.......................................................................
+ * Read an input line from a non-interactive input stream.
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ * Output:
+ * return int 0 - OK
+ * 1 - Error.
+ */
+static int gl_read_stream_line(GetLine *gl)
+{
+ char c = '\0'; /* The latest character read from fp */
+/*
+ * Record the fact that we are about to read input.
+ */
+ gl->pending_io = GLP_READ;
+/*
+ * If we are starting a new line, reset the line-editing parameters,
+ * and discard the previous input line.
+ */
+ if(gl->endline) {
+ gl_reset_editor(gl);
+ gl_truncate_buffer(gl, 0);
+ };
+/*
+ * Read one character at a time.
+ */
+ while(gl->ntotal < gl->linelen && c != '\n') {
+/*
+ * Attempt to read one more character.
+ */
+ switch(gl_read_input(gl, &c)) {
+ case GL_READ_OK:
+ break;
+ case GL_READ_EOF: /* Reached end-of-file? */
+/*
+ * If any characters were read before the end-of-file condition,
+ * interpolate a newline character, so that the caller sees a
+ * properly terminated line. Otherwise return an end-of-file
+ * condition.
+ */
+ if(gl->ntotal > 0) {
+ c = '\n';
+ } else {
+ gl_record_status(gl, GLR_EOF, 0);
+ return 1;
+ };
+ break;
+ case GL_READ_BLOCKED: /* Input blocked? */
+ gl_record_status(gl, GLR_BLOCKED, BLOCKED_ERRNO);
+ return 1;
+ break;
+ case GL_READ_ERROR: /* I/O error? */
+ return 1;
+ break;
+ };
+/*
+ * Append the character to the line buffer.
+ */
+ if(gl_buffer_char(gl, c, gl->ntotal))
+ return 1;
+ };
+/*
+ * Was the end of the input line reached before running out of buffer space?
+ */
+ gl->endline = (c == '\n');
+ return 0;
+}
+
+/*.......................................................................
+ * Read a single character from a non-interactive input stream.
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ * Output:
+ * return int The character, or EOF on error.
+ */
+static int gl_read_stream_char(GetLine *gl)
+{
+ char c = '\0'; /* The latest character read from fp */
+ int retval = EOF; /* The return value of this function */
+/*
+ * Arrange to discard any incomplete input line.
+ */
+ _gl_abandon_line(gl);
+/*
+ * Record the fact that we are about to read input.
+ */
+ gl->pending_io = GLP_READ;
+/*
+ * Attempt to read one more character.
+ */
+ switch(gl_read_input(gl, &c)) {
+ case GL_READ_OK: /* Success */
+ retval = c;
+ break;
+ case GL_READ_BLOCKED: /* The read blocked */
+ gl_record_status(gl, GLR_BLOCKED, BLOCKED_ERRNO);
+ retval = EOF; /* Failure */
+ break;
+ case GL_READ_EOF: /* End of file reached */
+ gl_record_status(gl, GLR_EOF, 0);
+ retval = EOF; /* Failure */
+ break;
+ case GL_READ_ERROR:
+ retval = EOF; /* Failure */
+ break;
+ };
+ return retval;
+}
+
+/*.......................................................................
+ * Bind a key sequence to a given action.
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ * origin GlKeyOrigin The originator of the key binding.
+ * key const char * The key-sequence to be bound (or unbound).
+ * action const char * The name of the action to bind the key to,
+ * or either NULL or "" to unbind the
+ * key-sequence.
+ * Output:
+ * return int 0 - OK
+ * 1 - Error.
+ */
+int gl_bind_keyseq(GetLine *gl, GlKeyOrigin origin, const char *keyseq,
+ const char *action)
+{
+ KtBinder binder; /* The private internal equivalent of 'origin' */
+/*
+ * Check the arguments.
+ */
+ if(!gl || !keyseq) {
+ errno = EINVAL;
+ if(gl)
+ _err_record_msg(gl->err, "NULL argument(s)", END_ERR_MSG);
+ return 1;
+ };
+/*
+ * An empty action string requests that the key-sequence be unbound.
+ * This is indicated to _kt_set_keybinding() by passing a NULL action
+ * string, so convert an empty string to a NULL action pointer.
+ */
+ if(action && *action=='\0')
+ action = NULL;
+/*
+ * Translate the public originator enumeration to the private equivalent.
+ */
+ binder = origin==GL_USER_KEY ? KTB_USER : KTB_NORM;
+/*
+ * Bind the action to a given key-sequence?
+ */
+ if(keyseq && _kt_set_keybinding(gl->bindings, binder, keyseq, action)) {
+ _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG);
+ return 1;
+ };
+ return 0;
+}
+
+/*.......................................................................
+ * This is the public wrapper around the gl_clear_termina() function.
+ * It clears the terminal and leaves the cursor at the home position.
+ * In server I/O mode, the next call to gl_get_line() will also
+ * redisplay the current input line.
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+int gl_erase_terminal(GetLine *gl)
+{
+ sigset_t oldset; /* The signals that were blocked on entry */
+ /* to this function */
+ int status; /* The return status */
+/*
+ * Block all signals while accessing gl.
+ */
+ gl_mask_signals(gl, &oldset);
+/*
+ * Clear the terminal.
+ */
+ status = gl_clear_screen(gl, 1, NULL);
+/*
+ * Attempt to flush the clear-screen control codes to the terminal.
+ * If this doesn't complete the job, the next call to gl_get_line()
+ * will.
+ */
+ (void) gl_flush_output(gl);
+/*
+ * Restore the process signal mask before returning.
+ */
+ gl_unmask_signals(gl, &oldset);
+ return status;
+}
+
+/*.......................................................................
+ * This function must be called by any function that erases the input
+ * line.
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ */
+static void gl_line_erased(GetLine *gl)
+{
+ gl->displayed = 0;
+ gl->term_curpos = 0;
+ gl->term_len = 0;
+}
+
+/*.......................................................................
+ * Append a specified line to the history list.
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ * line const char * The line to be added.
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+int gl_append_history(GetLine *gl, const char *line)
+{
+ sigset_t oldset; /* The signals that were blocked on entry */
+ /* to this function */
+ int status; /* The return status */
+/*
+ * Check the arguments.
+ */
+ if(!gl || !line) {
+ errno = EINVAL;
+ return 1;
+ };
+/*
+ * Block all signals.
+ */
+ if(gl_mask_signals(gl, &oldset))
+ return 1;
+/*
+ * Execute the private body of the function while signals are blocked.
+ */
+ status = _gl_append_history(gl, line);
+/*
+ * Restore the process signal mask.
+ */
+ gl_unmask_signals(gl, &oldset);
+ return status;
+}
+
+/*.......................................................................
+ * This is the private body of the public function, gl_append_history().
+ * It assumes that the caller has checked its arguments and blocked the
+ * delivery of signals.
+ */
+static int _gl_append_history(GetLine *gl, const char *line)
+{
+ int status =_glh_add_history(gl->glh, line, 0);
+ if(status)
+ _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
+ return status;
+}
+
+/*.......................................................................
+ * Enable or disable the automatic addition of newly entered lines to the
+ * history list.
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ * enable int If true, subsequently entered lines will
+ * automatically be added to the history list
+ * before they are returned to the caller of
+ * gl_get_line(). If 0, the choice of how and
+ * when to archive lines in the history list,
+ * is left up to the calling application, which
+ * can do so via calls to gl_append_history().
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+int gl_automatic_history(GetLine *gl, int enable)
+{
+ sigset_t oldset; /* The signals that were blocked on entry */
+ /* to this function */
+/*
+ * Check the arguments.
+ */
+ if(!gl) {
+ errno = EINVAL;
+ return 1;
+ };
+/*
+ * Block all signals.
+ */
+ if(gl_mask_signals(gl, &oldset))
+ return 1;
+/*
+ * Execute the private body of the function while signals are blocked.
+ */
+ gl->automatic_history = enable;
+/*
+ * Restore the process signal mask.
+ */
+ gl_unmask_signals(gl, &oldset);
+ return 0;
+}
+
+/*.......................................................................
+ * This is a public function that reads a single uninterpretted
+ * character from the user, without displaying anything.
+ *
+ * Input:
+ * gl GetLine * A resource object previously returned by
+ * new_GetLine().
+ * Output:
+ * return int The character that was read, or EOF if the read
+ * had to be aborted (in which case you can call
+ * gl_return_status() to find out why).
+ */
+int gl_read_char(GetLine *gl)
+{
+ int retval; /* The return value of _gl_read_char() */
+/*
+ * This function can be called from application callback functions,
+ * so check whether signals have already been masked, so that we don't
+ * do it again, and overwrite gl->old_signal_set.
+ */
+ int was_masked = gl->signals_masked;
+/*
+ * Check the arguments.
+ */
+ if(!gl) {
+ errno = EINVAL;
+ return EOF;
+ };
+/*
+ * Temporarily block all of the signals that we have been asked to trap.
+ */
+ if(!was_masked && gl_mask_signals(gl, &gl->old_signal_set))
+ return EOF;
+/*
+ * Perform the character reading task.
+ */
+ retval = _gl_read_char(gl);
+/*
+ * Restore the process signal mask to how it was when this function was
+ * first called.
+ */
+ if(!was_masked)
+ gl_unmask_signals(gl, &gl->old_signal_set);
+ return retval;
+}
+
+/*.......................................................................
+ * This is the main body of the public function gl_read_char().
+ */
+static int _gl_read_char(GetLine *gl)
+{
+ int retval = EOF; /* The return value */
+ int waserr = 0; /* True if an error occurs */
+ char c; /* The character read */
+/*
+ * This function can be called from application callback functions,
+ * so check whether signals have already been overriden, so that we don't
+ * overwrite the preserved signal handlers with gl_get_line()s. Also
+ * record whether we are currently in raw I/O mode or not, so that this
+ * can be left in the same state on leaving this function.
+ */
+ int was_overriden = gl->signals_overriden;
+ int was_raw = gl->raw_mode;
+/*
+ * Also keep a record of the direction of any I/O that gl_get_line()
+ * is awaiting, so that we can restore this status on return.
+ */
+ GlPendingIO old_pending_io = gl->pending_io;
+/*
+ * Assume that this call will successfully complete the input operation
+ * until proven otherwise.
+ */
+ gl_clear_status(gl);
+/*
+ * If this is the first call to this function or gl_get_line(),
+ * since new_GetLine(), complete any postponed configuration.
+ */
+ if(!gl->configured) {
+ (void) _gl_configure_getline(gl, NULL, NULL, TECLA_CONFIG_FILE);
+ gl->configured = 1;
+ };
+/*
+ * Before installing our signal handler functions, record the fact
+ * that there are no pending signals.
+ */
+ gl_pending_signal = -1;
+/*
+ * Temporarily override the signal handlers of the calling program,
+ * so that we can intercept signals that would leave the terminal
+ * in a bad state.
+ */
+ if(!was_overriden)
+ waserr = gl_override_signal_handlers(gl);
+/*
+ * After recording the current terminal settings, switch the terminal
+ * into raw input mode, without redisplaying any partially entered input
+ * line.
+ */
+ if(!was_raw)
+ waserr = waserr || _gl_raw_io(gl, 0);
+/*
+ * Attempt to read the line. This will require more than one attempt if
+ * either a current temporary input file is opened by gl_get_input_line()
+ * or the end of a temporary input file is reached by gl_read_stream_line().
+ */
+ while(!waserr) {
+/*
+ * Read a line from a non-interactive stream?
+ */
+ if(gl->file_fp || !gl->is_term) {
+ retval = gl_read_stream_char(gl);
+ if(retval != EOF) { /* Success? */
+ break;
+ } else if(gl->file_fp) { /* End of temporary input file? */
+ gl_revert_input(gl);
+ gl_record_status(gl, GLR_NEWLINE, 0);
+ } else { /* An error? */
+ waserr = 1;
+ break;
+ };
+ };
+/*
+ * Read from the terminal? Note that the above if() block may have
+ * changed gl->file_fp, so it is necessary to retest it here, rather
+ * than using an else statement.
+ */
+ if(!gl->file_fp && gl->is_term) {
+/*
+ * Flush any pending output to the terminal before waiting
+ * for the user to type a character.
+ */
+ if(_glq_char_count(gl->cq) > 0 && gl_flush_output(gl)) {
+ retval = EOF;
+/*
+ * Read one character. Don't append it to the key buffer, since
+ * this would subseuqnely appear as bogus input to the line editor.
+ */
+ } else if(gl_read_terminal(gl, 0, &c) == 0) {
+/*
+ * Record the character for return.
+ */
+ retval = c;
+/*
+ * In this mode, count each character as being a new key-sequence.
+ */
+ gl->keyseq_count++;
+/*
+ * Delete the character that was read, from the key-press buffer.
+ */
+ gl_discard_chars(gl, 1);
+ };
+ if(retval==EOF)
+ waserr = 1;
+ else
+ break;
+ };
+ };
+/*
+ * If an error occurred, but gl->rtn_status is still set to
+ * GLR_NEWLINE, change the status to GLR_ERROR. Otherwise
+ * leave it at whatever specific value was assigned by the function
+ * that aborted input. This means that only functions that trap
+ * non-generic errors have to remember to update gl->rtn_status
+ * themselves.
+ */
+ if(waserr && gl->rtn_status == GLR_NEWLINE)
+ gl_record_status(gl, GLR_ERROR, errno);
+/*
+ * Restore terminal settings, if they were changed by this function.
+ */
+ if(!was_raw && gl->io_mode != GL_SERVER_MODE)
+ _gl_normal_io(gl);
+/*
+ * Restore the signal handlers, if they were overriden by this function.
+ */
+ if(!was_overriden)
+ gl_restore_signal_handlers(gl);
+/*
+ * If this function gets aborted early, the errno value associated
+ * with the event that caused this to happen is recorded in
+ * gl->rtn_errno. Since errno may have been overwritten by cleanup
+ * functions after this, restore its value to the value that it had
+ * when the error condition occured, so that the caller can examine it
+ * to find out what happened.
+ */
+ errno = gl->rtn_errno;
+/*
+ * Error conditions are signalled to the caller, by setting the returned
+ * character to EOF.
+ */
+ if(gl->rtn_status != GLR_NEWLINE)
+ retval = EOF;
+/*
+ * Restore the indication of what direction of I/O gl_get_line()
+ * was awaiting before this call.
+ */
+ gl->pending_io = old_pending_io;
+/*
+ * Return the acquired character.
+ */
+ return retval;
+}
+
+/*.......................................................................
+ * Reset the GetLine completion status. This function should be called
+ * at the start of gl_get_line(), gl_read_char() and gl_query_char()
+ * to discard the completion status and non-zero errno value of any
+ * preceding calls to these functions.
+ *
+ * Input:
+ * gl GetLine * The resource object of this module.
+ */
+static void gl_clear_status(GetLine *gl)
+{
+ gl_record_status(gl, GLR_NEWLINE, 0);
+}
+
+/*.......................................................................
+ * When an error or other event causes gl_get_line() to return, this
+ * function should be called to record information about what
+ * happened, including the value of errno and the value that
+ * gl_return_status() should return.
+ *
+ * Input:
+ * gl GetLine * The resource object of this module.
+ * rtn_status GlReturnStatus The completion status. To clear a
+ * previous abnormal completion status,
+ * specify GLR_NEWLINE (this is what
+ * gl_clear_status() does).
+ * rtn_errno int The associated value of errno.
+ */
+static void gl_record_status(GetLine *gl, GlReturnStatus rtn_status,
+ int rtn_errno)
+{
+/*
+ * If rtn_status==GLR_NEWLINE, then this resets the completion status, so we
+ * should always heed this. Otherwise, only record the first abnormal
+ * condition that occurs after such a reset.
+ */
+ if(rtn_status == GLR_NEWLINE || gl->rtn_status == GLR_NEWLINE) {
+ gl->rtn_status = rtn_status;
+ gl->rtn_errno = rtn_errno;
+ };
+}
+
diff --git a/libtecla-1.4.1/getline.h b/libtecla-1.6.1/getline.h
index 24b0875..60a9c33 100644
--- a/libtecla-1.4.1/getline.h
+++ b/libtecla-1.6.1/getline.h
@@ -2,7 +2,7 @@
#define getline_h
/*
- * Copyright (c) 2000, 2001 by Martin C. Shepherd.
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
*
* All rights reserved.
*
diff --git a/libtecla-1.4.1/hash.c b/libtecla-1.6.1/hash.c
index 89f8245..acaaff6 100644
--- a/libtecla-1.4.1/hash.c
+++ b/libtecla-1.6.1/hash.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2001 by Martin C. Shepherd.
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
*
* All rights reserved.
*
@@ -33,6 +33,7 @@
#include <stdio.h>
#include <string.h>
#include <ctype.h>
+#include <errno.h>
#include "hash.h"
#include "strngmem.h"
@@ -68,27 +69,18 @@ typedef struct {
} HashBucket;
/*
- * Set the max length of the error-reporting string. There is no point
- * in this being longer than the width of a typical terminal window.
- * In composing error messages, I have assumed that this number is
- * at least 80, so you don't decrease it below this number.
- */
-#define ERRLEN 200
-
-/*
* A hash-table consists of 'size' hash buckets.
* Note that the HashTable typedef for this struct is contained in hash.h.
*/
struct HashTable {
- char errmsg[ERRLEN+1];/* Error-report buffer */
- HashMemory *mem; /* HashTable free-list */
- int internal_mem; /* True if 'mem' was allocated by _new_HashTable() */
- int case_sensitive; /* True if case is significant in lookup keys */
- int size; /* The number of hash buckets */
- HashBucket *bucket; /* An array of 'size' hash buckets */
+ HashMemory *mem; /* HashTable free-list */
+ int internal_mem; /* True if 'mem' was allocated by _new_HashTable() */
+ int case_sensitive; /* True if case is significant in lookup keys */
+ int size; /* The number of hash buckets */
+ HashBucket *bucket; /* An array of 'size' hash buckets */
int (*keycmp)(const char *, const char *); /* Key comparison function */
- void *app_data; /* Application-provided data */
- HASH_DEL_FN(*del_fn); /* Application-provided 'app_data' destructor */
+ void *app_data; /* Application-provided data */
+ HASH_DEL_FN(*del_fn); /* Application-provided 'app_data' destructor */
};
static HashNode *_del_HashNode(HashTable *hash, HashNode *node);
@@ -119,7 +111,7 @@ HashMemory *_new_HashMemory(int hash_count, int node_count)
*/
mem = (HashMemory *) malloc(sizeof(HashMemory));
if(!mem) {
- fprintf(stderr, "_new_HashMemory: Insufficient memory.\n");
+ errno = ENOMEM;
return NULL;
};
/*
@@ -132,15 +124,13 @@ HashMemory *_new_HashMemory(int hash_count, int node_count)
/*
* Allocate the two free-lists.
*/
- mem->hash_memory = _new_FreeList("_new_HashMemory", sizeof(HashTable),
- hash_count);
+ mem->hash_memory = _new_FreeList(sizeof(HashTable), hash_count);
if(!mem->hash_memory)
return _del_HashMemory(mem, 1);
- mem->node_memory = _new_FreeList("_new_HashMemory", sizeof(HashNode),
- node_count);
+ mem->node_memory = _new_FreeList(sizeof(HashNode), node_count);
if(!mem->node_memory)
return _del_HashMemory(mem, 1);
- mem->string_memory = _new_StringMem("_new_HashMemory", 64);
+ mem->string_memory = _new_StringMem(64);
if(!mem->string_memory)
return _del_HashMemory(mem, 1);
/*
@@ -167,16 +157,15 @@ HashMemory *_new_HashMemory(int hash_count, int node_count)
*/
HashMemory *_del_HashMemory(HashMemory *mem, int force)
{
- const char *caller = "_del_HashMemory";
if(mem) {
if(!force && (_busy_FreeListNodes(mem->hash_memory) > 0 ||
_busy_FreeListNodes(mem->node_memory) > 0)) {
- fprintf(stderr, "%s: Free-list in use.\n", caller);
+ errno = EBUSY;
return NULL;
};
- mem->hash_memory = _del_FreeList(caller, mem->hash_memory, force);
- mem->node_memory = _del_FreeList(caller, mem->node_memory, force);
- mem->string_memory = _del_StringMem(caller, mem->string_memory, force);
+ mem->hash_memory = _del_FreeList(mem->hash_memory, force);
+ mem->node_memory = _del_FreeList(mem->node_memory, force);
+ mem->string_memory = _del_StringMem(mem->string_memory, force);
free(mem);
};
return NULL;
@@ -224,7 +213,7 @@ HashTable *_new_HashTable(HashMemory *mem, int size, HashCase hcase,
* Check arguments.
*/
if(size <= 0) {
- fprintf(stderr, "_new_HashTable: Illegal table size (%d).\n", size);
+ errno = EINVAL;
return NULL;
};
/*
@@ -240,7 +229,7 @@ HashTable *_new_HashTable(HashMemory *mem, int size, HashCase hcase,
*/
hash = (HashTable *) _new_FreeListNode(mem->hash_memory);
if(!hash) {
- fprintf(stderr, "_new_HashTable: Insufficient memory.\n");
+ errno = ENOMEM;
if(allocate_mem)
mem = _del_HashMemory(mem, 1);
return NULL;
@@ -250,7 +239,6 @@ HashTable *_new_HashTable(HashMemory *mem, int size, HashCase hcase,
* the container at least up to the point at which it can safely
* be passed to _del_HashTable().
*/
- hash->errmsg[0] = '\0';
hash->mem = mem;
hash->internal_mem = allocate_mem;
hash->case_sensitive = hcase==HONOUR_CASE;
@@ -264,8 +252,7 @@ HashTable *_new_HashTable(HashMemory *mem, int size, HashCase hcase,
*/
hash->bucket = (HashBucket *) malloc(sizeof(HashBucket) * size);
if(!hash->bucket) {
- fprintf(stderr, "_new_HashTable: Insufficient memory for %d buckets.\n",
- size);
+ errno = ENOMEM;
return _del_HashTable(hash);
};
/*
@@ -351,8 +338,10 @@ Symbol *_new_HashSymbol(HashTable *hash, const char *name, int code,
/*
* Check arguments.
*/
- if(!hash || !name)
+ if(!hash || !name) {
+ errno = EINVAL;
return NULL;
+ };
/*
* Get the hash bucket of the specified name.
*/
diff --git a/libtecla-1.4.1/hash.h b/libtecla-1.6.1/hash.h
index 13c0a2b..6cee6a2 100644
--- a/libtecla-1.4.1/hash.h
+++ b/libtecla-1.6.1/hash.h
@@ -2,7 +2,7 @@
#define hash_h
/*
- * Copyright (c) 2000, 2001 by Martin C. Shepherd.
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
*
* All rights reserved.
*
@@ -124,7 +124,7 @@ typedef enum {
/* Create a new hash-table */
HashTable *_new_HashTable(HashMemory *mem, int size, HashCase hcase,
- void *app_data, HASH_DEL_FN(*del_fn));
+ void *app_data, HASH_DEL_FN(*del_fn));
/* Delete a reference to a hash-table */
diff --git a/libtecla-1.6.1/history.c b/libtecla-1.6.1/history.c
new file mode 100644
index 0000000..cffa33e
--- /dev/null
+++ b/libtecla-1.6.1/history.c
@@ -0,0 +1,2842 @@
+/*
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
+ *
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, and/or sell copies of the Software, and to permit persons
+ * to whom the Software is furnished to do so, provided that the above
+ * copyright notice(s) and this permission notice appear in all copies of
+ * the Software and that both the above copyright notice(s) and this
+ * permission notice appear in supporting documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+ * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
+ * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder
+ * shall not be used in advertising or otherwise to promote the sale, use
+ * or other dealings in this Software without prior written authorization
+ * of the copyright holder.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+#include <errno.h>
+
+#include "ioutil.h"
+#include "history.h"
+#include "freelist.h"
+#include "errmsg.h"
+
+/*
+ * History lines are split into sub-strings of GLH_SEG_SIZE
+ * characters. To avoid wasting space in the GlhLineSeg structure,
+ * this should be a multiple of the size of a pointer.
+ */
+#define GLH_SEG_SIZE 16
+
+/*
+ * GlhLineSeg structures contain fixed sized segments of a larger
+ * string. These are linked into lists to record strings, with all but
+ * the last segment having GLH_SEG_SIZE characters. The last segment
+ * of a string is terminated within the GLH_SEG_SIZE characters with a
+ * '\0'.
+ */
+typedef struct GlhLineSeg GlhLineSeg;
+struct GlhLineSeg {
+ GlhLineSeg *next; /* The next sub-string of the history line */
+ char s[GLH_SEG_SIZE]; /* The sub-string. Beware that only the final */
+ /* substring of a line, as indicated by 'next' */
+ /* being NULL, is '\0' terminated. */
+};
+
+/*
+ * History lines are recorded in a hash table, such that repeated
+ * lines are stored just once.
+ *
+ * Start by defining the size of the hash table. This should be a
+ * prime number.
+ */
+#define GLH_HASH_SIZE 113
+
+typedef struct GlhHashBucket GlhHashBucket;
+
+/*
+ * Each history line will be represented in the hash table by a
+ * structure of the following type.
+ */
+typedef struct GlhHashNode GlhHashNode;
+struct GlhHashNode {
+ GlhHashBucket *bucket; /* The parent hash-table bucket of this node */
+ GlhHashNode *next; /* The next in the list of nodes within the */
+ /* parent hash-table bucket. */
+ GlhLineSeg *head; /* The list of sub-strings which make up a line */
+ int len; /* The length of the line, excluding any '\0' */
+ int used; /* The number of times this string is pointed to by */
+ /* the time-ordered list of history lines. */
+ int reported; /* A flag that is used when searching to ensure that */
+ /* a line isn't reported redundantly. */
+};
+
+/*
+ * How many new GlhHashNode elements should be allocated at a time?
+ */
+#define GLH_HASH_INCR 50
+
+static int _glh_is_line(GlhHashNode *hash, const char *line, size_t n);
+static int _glh_line_matches_prefix(GlhHashNode *line, GlhHashNode *prefix);
+static void _glh_return_line(GlhHashNode *hash, char *line, size_t dim);
+
+/*
+ * All history lines which hash to a given bucket in the hash table, are
+ * recorded in a structure of the following type.
+ */
+struct GlhHashBucket {
+ GlhHashNode *lines; /* The list of history lines which fall in this bucket */
+};
+
+static GlhHashBucket *glh_find_bucket(GlHistory *glh, const char *line,
+ size_t n);
+static GlhHashNode *glh_find_hash_node(GlhHashBucket *bucket, const char *line,
+ size_t n);
+
+typedef struct {
+ FreeList *node_mem; /* A free-list of GlhHashNode structures */
+ GlhHashBucket bucket[GLH_HASH_SIZE]; /* The buckets of the hash table */
+} GlhLineHash;
+
+/*
+ * GlhLineNode's are used to record history lines in time order.
+ */
+typedef struct GlhLineNode GlhLineNode;
+struct GlhLineNode {
+ long id; /* The unique identifier of this history line */
+ time_t timestamp; /* The time at which the line was archived */
+ unsigned group; /* The identifier of the history group to which the */
+ /* the line belongs. */
+ GlhLineNode *next; /* The next youngest line in the list */
+ GlhLineNode *prev; /* The next oldest line in the list */
+ GlhHashNode *line; /* The hash-table entry of the history line */
+};
+
+/*
+ * The number of GlhLineNode elements per freelist block.
+ */
+#define GLH_LINE_INCR 100
+
+/*
+ * Encapsulate the time-ordered list of historical lines.
+ */
+typedef struct {
+ FreeList *node_mem; /* A freelist of GlhLineNode objects */
+ GlhLineNode *head; /* The oldest line in the list */
+ GlhLineNode *tail; /* The newest line in the list */
+} GlhLineList;
+
+/*
+ * The _glh_lookup_history() returns copies of history lines in a
+ * dynamically allocated array. This array is initially allocated
+ * GLH_LOOKUP_SIZE bytes. If subsequently this size turns out to be
+ * too small, realloc() is used to increase its size to the required
+ * size plus GLH_LOOKUP_MARGIN. The idea of the later parameter is to
+ * reduce the number of realloc() operations needed.
+ */
+#define GLH_LBUF_SIZE 300
+#define GLH_LBUF_MARGIN 100
+
+/*
+ * Encapsulate all of the resources needed to store historical input lines.
+ */
+struct GlHistory {
+ ErrMsg *err; /* The error-reporting buffer */
+ GlhLineSeg *buffer; /* An array of sub-line nodes to be partitioned */
+ /* into lists of sub-strings recording input lines. */
+ int nbuff; /* The allocated dimension of buffer[] */
+ GlhLineSeg *unused; /* The list of free nodes in buffer[] */
+ GlhLineList list; /* A time ordered list of history lines */
+ GlhLineNode *recall; /* The last line recalled, or NULL if no recall */
+ /* session is currently active. */
+ GlhLineNode *id_node;/* The node at which the last ID search terminated */
+ GlhLineHash hash; /* A hash-table of reference-counted history lines */
+ GlhHashNode *prefix; /* A pointer to a line containing the prefix that */
+ /* is being searched for. Note that if prefix==NULL */
+ /* and prefix_len>0, this means that no line in */
+ /* the buffer starts with the requested prefix. */
+ int prefix_len; /* The length of the prefix being searched for. */
+ char *lbuf; /* The array in which _glh_lookup_history() returns */
+ /* history lines */
+ int lbuf_dim; /* The allocated size of lbuf[] */
+ int nbusy; /* The number of line segments in buffer[] that are */
+ /* currently being used to record sub-lines */
+ int nfree; /* The number of line segments in buffer that are */
+ /* not currently being used to record sub-lines */
+ unsigned long seq; /* The next ID to assign to a line node */
+ unsigned group; /* The identifier of the current history group */
+ int nline; /* The number of lines currently in the history list */
+ int max_lines; /* Either -1 or a ceiling on the number of lines */
+ int enable; /* If false, ignore history additions and lookups */
+};
+
+#ifndef WITHOUT_FILE_SYSTEM
+static int _glh_cant_load_history(GlHistory *glh, const char *filename,
+ int lineno, const char *message, FILE *fp);
+static int _glh_cant_save_history(GlHistory *glh, const char *message,
+ const char *filename, FILE *fp);
+static int _glh_write_timestamp(FILE *fp, time_t timestamp);
+static int _glh_decode_timestamp(char *string, char **endp, time_t *timestamp);
+#endif
+static void _glh_discard_line(GlHistory *glh, GlhLineNode *node);
+static GlhLineNode *_glh_find_id(GlHistory *glh, GlhLineID id);
+static GlhHashNode *_glh_acquire_copy(GlHistory *glh, const char *line,
+ size_t n);
+static GlhHashNode *_glh_discard_copy(GlHistory *glh, GlhHashNode *hnode);
+static int _glh_prepare_for_recall(GlHistory *glh, char *line);
+
+/*
+ * The following structure and functions are used to iterate through
+ * the characters of a segmented history line.
+ */
+typedef struct {
+ GlhLineSeg *seg; /* The line segment that the next character will */
+ /* be returned from. */
+ int posn; /* The index in the above line segment, containing */
+ /* the next unread character. */
+ char c; /* The current character in the input line */
+} GlhLineStream;
+static void glh_init_stream(GlhLineStream *str, GlhHashNode *line);
+static void glh_step_stream(GlhLineStream *str);
+
+/*
+ * See if search prefix contains any globbing characters.
+ */
+static int glh_contains_glob(GlhHashNode *prefix);
+/*
+ * Match a line against a search pattern.
+ */
+static int glh_line_matches_glob(GlhLineStream *lstr, GlhLineStream *pstr);
+static int glh_matches_range(char c, GlhLineStream *pstr);
+
+/*.......................................................................
+ * Create a line history maintenance object.
+ *
+ * Input:
+ * buflen size_t The number of bytes to allocate to the
+ * buffer that is used to record all of the
+ * most recent lines of user input that will fit.
+ * If buflen==0, no buffer will be allocated.
+ * Output:
+ * return GlHistory * The new object, or NULL on error.
+ */
+GlHistory *_new_GlHistory(size_t buflen)
+{
+ GlHistory *glh; /* The object to be returned */
+ int i;
+/*
+ * Allocate the container.
+ */
+ glh = (GlHistory *) malloc(sizeof(GlHistory));
+ if(!glh) {
+ errno = ENOMEM;
+ return NULL;
+ };
+/*
+ * Before attempting any operation that might fail, initialize the
+ * container at least up to the point at which it can safely be passed
+ * to _del_GlHistory().
+ */
+ glh->err = NULL;
+ glh->buffer = NULL;
+ glh->nbuff = (buflen+GLH_SEG_SIZE-1) / GLH_SEG_SIZE;
+ glh->unused = NULL;
+ glh->list.node_mem = NULL;
+ glh->list.head = glh->list.tail = NULL;
+ glh->recall = NULL;
+ glh->id_node = NULL;
+ glh->hash.node_mem = NULL;
+ for(i=0; i<GLH_HASH_SIZE; i++)
+ glh->hash.bucket[i].lines = NULL;
+ glh->prefix = NULL;
+ glh->lbuf = NULL;
+ glh->lbuf_dim = 0;
+ glh->nbusy = 0;
+ glh->nfree = glh->nbuff;
+ glh->seq = 0;
+ glh->group = 0;
+ glh->nline = 0;
+ glh->max_lines = -1;
+ glh->enable = 1;
+/*
+ * Allocate a place to record error messages.
+ */
+ glh->err = _new_ErrMsg();
+ if(!glh->err)
+ return _del_GlHistory(glh);
+/*
+ * Allocate the buffer, if required.
+ */
+ if(glh->nbuff > 0) {
+ glh->nbuff = glh->nfree;
+ glh->buffer = (GlhLineSeg *) malloc(sizeof(GlhLineSeg) * glh->nbuff);
+ if(!glh->buffer) {
+ errno = ENOMEM;
+ return _del_GlHistory(glh);
+ };
+/*
+ * All nodes of the buffer are currently unused, so link them all into
+ * a list and make glh->unused point to the head of this list.
+ */
+ glh->unused = glh->buffer;
+ for(i=0; i<glh->nbuff-1; i++) {
+ GlhLineSeg *seg = glh->unused + i;
+ seg->next = seg + 1;
+ };
+ glh->unused[i].next = NULL;
+ };
+/*
+ * Allocate the GlhLineNode freelist.
+ */
+ glh->list.node_mem = _new_FreeList(sizeof(GlhLineNode), GLH_LINE_INCR);
+ if(!glh->list.node_mem)
+ return _del_GlHistory(glh);
+/*
+ * Allocate the GlhHashNode freelist.
+ */
+ glh->hash.node_mem = _new_FreeList(sizeof(GlhLineNode), GLH_HASH_INCR);
+ if(!glh->hash.node_mem)
+ return _del_GlHistory(glh);
+/*
+ * Allocate the array that _glh_lookup_history() uses to return a
+ * copy of a given history line. This will be resized when necessary.
+ */
+ glh->lbuf_dim = GLH_LBUF_SIZE;
+ glh->lbuf = (char *) malloc(glh->lbuf_dim);
+ if(!glh->lbuf) {
+ errno = ENOMEM;
+ return _del_GlHistory(glh);
+ };
+ return glh;
+}
+
+/*.......................................................................
+ * Delete a GlHistory object.
+ *
+ * Input:
+ * glh GlHistory * The object to be deleted.
+ * Output:
+ * return GlHistory * The deleted object (always NULL).
+ */
+GlHistory *_del_GlHistory(GlHistory *glh)
+{
+ if(glh) {
+/*
+ * Delete the error-message buffer.
+ */
+ glh->err = _del_ErrMsg(glh->err);
+/*
+ * Delete the buffer.
+ */
+ if(glh->buffer) {
+ free(glh->buffer);
+ glh->buffer = NULL;
+ glh->unused = NULL;
+ };
+/*
+ * Delete the freelist of GlhLineNode's.
+ */
+ glh->list.node_mem = _del_FreeList(glh->list.node_mem, 1);
+/*
+ * The contents of the list were deleted by deleting the freelist.
+ */
+ glh->list.head = NULL;
+ glh->list.tail = NULL;
+/*
+ * Delete the freelist of GlhHashNode's.
+ */
+ glh->hash.node_mem = _del_FreeList(glh->hash.node_mem, 1);
+/*
+ * Delete the lookup buffer.
+ */
+ if(glh->lbuf)
+ free(glh->lbuf);
+/*
+ * Delete the container.
+ */
+ free(glh);
+ };
+ return NULL;
+}
+
+/*.......................................................................
+ * Append a new line to the history list, deleting old lines to make
+ * room, if needed.
+ *
+ * Input:
+ * glh GlHistory * The input-line history maintenance object.
+ * line char * The line to be archived.
+ * force int Unless this flag is non-zero, empty lines aren't
+ * archived. This flag requests that the line be
+ * archived regardless.
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+int _glh_add_history(GlHistory *glh, const char *line, int force)
+{
+ int slen; /* The length of the line to be recorded (minus the '\0') */
+ int empty; /* True if the string is empty */
+ const char *nlptr; /* A pointer to a newline character in line[] */
+ GlhHashNode *hnode; /* The hash-table node of the line */
+ GlhLineNode *lnode; /* A node in the time-ordered list of lines */
+ int i;
+/*
+ * Check the arguments.
+ */
+ if(!glh || !line) {
+ errno = EINVAL;
+ return 1;
+ };
+/*
+ * Is history enabled?
+ */
+ if(!glh->enable || !glh->buffer || glh->max_lines == 0)
+ return 0;
+/*
+ * Cancel any ongoing search.
+ */
+ if(_glh_cancel_search(glh))
+ return 1;
+/*
+ * How long is the string to be recorded, being careful not to include
+ * any terminating '\n' character.
+ */
+ nlptr = strchr(line, '\n');
+ if(nlptr)
+ slen = (nlptr - line);
+ else
+ slen = strlen(line);
+/*
+ * Is the line empty?
+ */
+ empty = 1;
+ for(i=0; i<slen && empty; i++)
+ empty = isspace((int)(unsigned char) line[i]);
+/*
+ * If the line is empty, don't add it to the buffer unless explicitly
+ * told to.
+ */
+ if(empty && !force)
+ return 0;
+/*
+ * Has an upper limit to the number of lines in the history list been
+ * specified?
+ */
+ if(glh->max_lines >= 0) {
+/*
+ * If necessary, remove old lines until there is room to add one new
+ * line without exceeding the specified line limit.
+ */
+ while(glh->nline > 0 && glh->nline >= glh->max_lines)
+ _glh_discard_line(glh, glh->list.head);
+/*
+ * We can't archive the line if the maximum number of lines allowed is
+ * zero.
+ */
+ if(glh->max_lines == 0)
+ return 0;
+ };
+/*
+ * Unless already stored, store a copy of the line in the history buffer,
+ * then return a reference-counted hash-node pointer to this copy.
+ */
+ hnode = _glh_acquire_copy(glh, line, slen);
+ if(!hnode) {
+ _err_record_msg(glh->err, "No room to store history line", END_ERR_MSG);
+ errno = ENOMEM;
+ return 1;
+ };
+/*
+ * Allocate a new node in the time-ordered list of lines.
+ */
+ lnode = (GlhLineNode *) _new_FreeListNode(glh->list.node_mem);
+/*
+ * If a new line-node couldn't be allocated, discard our copy of the
+ * stored line before reporting the error.
+ */
+ if(!lnode) {
+ hnode = _glh_discard_copy(glh, hnode);
+ _err_record_msg(glh->err, "No room to store history line", END_ERR_MSG);
+ errno = ENOMEM;
+ return 1;
+ };
+/*
+ * Record a pointer to the hash-table record of the line in the new
+ * list node.
+ */
+ lnode->id = glh->seq++;
+ lnode->timestamp = time(NULL);
+ lnode->group = glh->group;
+ lnode->line = hnode;
+/*
+ * Append the new node to the end of the time-ordered list.
+ */
+ if(glh->list.head)
+ glh->list.tail->next = lnode;
+ else
+ glh->list.head = lnode;
+ lnode->next = NULL;
+ lnode->prev = glh->list.tail;
+ glh->list.tail = lnode;
+/*
+ * Record the addition of a line to the list.
+ */
+ glh->nline++;
+ return 0;
+}
+
+/*.......................................................................
+ * Recall the next oldest line that has the search prefix last recorded
+ * by _glh_search_prefix().
+ *
+ * Input:
+ * glh GlHistory * The input-line history maintenance object.
+ * line char * The input line buffer. On input this should contain
+ * the current input line, and on output, if anything
+ * was found, its contents will have been replaced
+ * with the matching line.
+ * dim size_t The allocated dimension of the line buffer.
+ * Output:
+ * return char * A pointer to line[0], or NULL if not found.
+ */
+char *_glh_find_backwards(GlHistory *glh, char *line, size_t dim)
+{
+ GlhLineNode *node; /* The line location node being checked */
+ GlhHashNode *old_line; /* The previous recalled line */
+/*
+ * Check the arguments.
+ */
+ if(!glh || !line) {
+ if(glh)
+ _err_record_msg(glh->err, "NULL argument(s)", END_ERR_MSG);
+ errno = EINVAL;
+ return NULL;
+ };
+/*
+ * Is history enabled?
+ */
+ if(!glh->enable || !glh->buffer || glh->max_lines == 0)
+ return NULL;
+/*
+ * Check the line dimensions.
+ */
+ if(dim < strlen(line) + 1) {
+ _err_record_msg(glh->err, "'dim' argument inconsistent with strlen(line)",
+ END_ERR_MSG);
+ errno = EINVAL;
+ return NULL;
+ };
+/*
+ * Preserve the input line if needed.
+ */
+ if(_glh_prepare_for_recall(glh, line))
+ return NULL;
+/*
+ * From where should we start the search?
+ */
+ if(glh->recall) {
+ node = glh->recall->prev;
+ old_line = glh->recall->line;
+ } else {
+ node = glh->list.tail;
+ old_line = NULL;
+ };
+/*
+ * Search backwards through the list for the first match with the
+ * prefix string that differs from the last line that was recalled.
+ */
+ while(node && (node->group != glh->group || node->line == old_line ||
+ !_glh_line_matches_prefix(node->line, glh->prefix)))
+ node = node->prev;
+/*
+ * Was a matching line found?
+ */
+ if(node) {
+/*
+ * Recall the found node as the starting point for subsequent
+ * searches.
+ */
+ glh->recall = node;
+/*
+ * Copy the matching line into the provided line buffer.
+ */
+ _glh_return_line(node->line, line, dim);
+/*
+ * Return it.
+ */
+ return line;
+ };
+/*
+ * No match was found.
+ */
+ return NULL;
+}
+
+/*.......................................................................
+ * Recall the next newest line that has the search prefix last recorded
+ * by _glh_search_prefix().
+ *
+ * Input:
+ * glh GlHistory * The input-line history maintenance object.
+ * line char * The input line buffer. On input this should contain
+ * the current input line, and on output, if anything
+ * was found, its contents will have been replaced
+ * with the matching line.
+ * dim size_t The allocated dimensions of the line buffer.
+ * Output:
+ * return char * The line requested, or NULL if no matching line
+ * was found.
+ */
+char *_glh_find_forwards(GlHistory *glh, char *line, size_t dim)
+{
+ GlhLineNode *node; /* The line location node being checked */
+ GlhHashNode *old_line; /* The previous recalled line */
+/*
+ * Check the arguments.
+ */
+ if(!glh || !line) {
+ if(glh)
+ _err_record_msg(glh->err, "NULL argument(s)", END_ERR_MSG);
+ errno = EINVAL;
+ return NULL;
+ };
+/*
+ * Is history enabled?
+ */
+ if(!glh->enable || !glh->buffer || glh->max_lines == 0)
+ return NULL;
+/*
+ * Check the line dimensions.
+ */
+ if(dim < strlen(line) + 1) {
+ _err_record_msg(glh->err, "'dim' argument inconsistent with strlen(line)",
+ END_ERR_MSG);
+ errno = EINVAL;
+ return NULL;
+ };
+/*
+ * From where should we start the search?
+ */
+ if(glh->recall) {
+ node = glh->recall->next;
+ old_line = glh->recall->line;
+ } else {
+ return NULL;
+ };
+/*
+ * Search forwards through the list for the first match with the
+ * prefix string.
+ */
+ while(node && (node->group != glh->group || node->line == old_line ||
+ !_glh_line_matches_prefix(node->line, glh->prefix)))
+ node = node->next;
+/*
+ * Was a matching line found?
+ */
+ if(node) {
+/*
+ * Copy the matching line into the provided line buffer.
+ */
+ _glh_return_line(node->line, line, dim);
+/*
+ * Record the starting point of the next search.
+ */
+ glh->recall = node;
+/*
+ * If we just returned the line that was being entered when the search
+ * session first started, cancel the search.
+ */
+ if(node == glh->list.tail)
+ _glh_cancel_search(glh);
+/*
+ * Return the matching line to the user.
+ */
+ return line;
+ };
+/*
+ * No match was found.
+ */
+ return NULL;
+}
+
+/*.......................................................................
+ * If a search is in progress, cancel it.
+ *
+ * This involves discarding the line that was temporarily saved by
+ * _glh_find_backwards() when the search was originally started,
+ * and reseting the search iteration pointer to NULL.
+ *
+ * Input:
+ * glh GlHistory * The input-line history maintenance object.
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+int _glh_cancel_search(GlHistory *glh)
+{
+/*
+ * Check the arguments.
+ */
+ if(!glh) {
+ errno = EINVAL;
+ return 1;
+ };
+/*
+ * If there wasn't a search in progress, do nothing.
+ */
+ if(!glh->recall)
+ return 0;
+/*
+ * Reset the search pointers. Note that it is essential to set
+ * glh->recall to NULL before calling _glh_discard_line(), to avoid an
+ * infinite recursion.
+ */
+ glh->recall = NULL;
+/*
+ * Delete the node of the preserved line.
+ */
+ _glh_discard_line(glh, glh->list.tail);
+ return 0;
+}
+
+/*.......................................................................
+ * Set the prefix of subsequent history searches.
+ *
+ * Input:
+ * glh GlHistory * The input-line history maintenance object.
+ * line const char * The command line who's prefix is to be used.
+ * prefix_len int The length of the prefix.
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+int _glh_search_prefix(GlHistory *glh, const char *line, int prefix_len)
+{
+/*
+ * Check the arguments.
+ */
+ if(!glh) {
+ errno = EINVAL;
+ return 1;
+ };
+/*
+ * Is history enabled?
+ */
+ if(!glh->enable || !glh->buffer || glh->max_lines == 0)
+ return 0;
+/*
+ * Discard any existing prefix.
+ */
+ glh->prefix = _glh_discard_copy(glh, glh->prefix);
+/*
+ * Only store a copy of the prefix string if it isn't a zero-length string.
+ */
+ if(prefix_len > 0) {
+/*
+ * Get a reference-counted copy of the prefix from the history cache buffer.
+ */
+ glh->prefix = _glh_acquire_copy(glh, line, prefix_len);
+/*
+ * Was there insufficient buffer space?
+ */
+ if(!glh->prefix) {
+ _err_record_msg(glh->err, "The search prefix is too long to store",
+ END_ERR_MSG);
+ errno = ENOMEM;
+ return 1;
+ };
+ };
+ return 0;
+}
+
+/*.......................................................................
+ * Recall the oldest recorded line.
+ *
+ * Input:
+ * glh GlHistory * The input-line history maintenance object.
+ * line char * The input line buffer. On input this should contain
+ * the current input line, and on output, its contents
+ * will have been replaced with the oldest line.
+ * dim size_t The allocated dimensions of the line buffer.
+ * Output:
+ * return char * A pointer to line[0], or NULL if not found.
+ */
+char *_glh_oldest_line(GlHistory *glh, char *line, size_t dim)
+{
+ GlhLineNode *node; /* The line location node being checked */
+/*
+ * Check the arguments.
+ */
+ if(!glh || !line) {
+ if(glh)
+ _err_record_msg(glh->err, "NULL argument(s)", END_ERR_MSG);
+ errno = EINVAL;
+ return NULL;
+ };
+/*
+ * Is history enabled?
+ */
+ if(!glh->enable || !glh->buffer || glh->max_lines == 0)
+ return NULL;
+/*
+ * Check the line dimensions.
+ */
+ if(dim < strlen(line) + 1) {
+ _err_record_msg(glh->err, "'dim' argument inconsistent with strlen(line)",
+ END_ERR_MSG);
+ errno = EINVAL;
+ return NULL;
+ };
+/*
+ * Preserve the input line if needed.
+ */
+ if(_glh_prepare_for_recall(glh, line))
+ return NULL;
+/*
+ * Locate the oldest line that belongs to the current group.
+ */
+ for(node=glh->list.head; node && node->group != glh->group;
+ node = node->next)
+ ;
+/*
+ * No line found?
+ */
+ if(!node)
+ return NULL;
+/*
+ * Record the above node as the starting point for subsequent
+ * searches.
+ */
+ glh->recall = node;
+/*
+ * Copy the recalled line into the provided line buffer.
+ */
+ _glh_return_line(node->line, line, dim);
+/*
+ * If we just returned the line that was being entered when the search
+ * session first started, cancel the search.
+ */
+ if(node == glh->list.tail)
+ _glh_cancel_search(glh);
+ return line;
+}
+
+/*.......................................................................
+ * Recall the line that was being entered when the search started.
+ *
+ * Input:
+ * glh GlHistory * The input-line history maintenance object.
+ * line char * The input line buffer. On input this should contain
+ * the current input line, and on output, its contents
+ * will have been replaced with the line that was
+ * being entered when the search was started.
+ * dim size_t The allocated dimensions of the line buffer.
+ * Output:
+ * return char * A pointer to line[0], or NULL if not found.
+ */
+char *_glh_current_line(GlHistory *glh, char *line, size_t dim)
+{
+/*
+ * Check the arguments.
+ */
+ if(!glh || !line) {
+ if(glh)
+ _err_record_msg(glh->err, "NULL argument(s)", END_ERR_MSG);
+ errno = EINVAL;
+ return NULL;
+ };
+/*
+ * If history isn't enabled, or no history search has yet been started,
+ * ignore the call.
+ */
+ if(!glh->enable || !glh->buffer || glh->max_lines == 0 || !glh->recall)
+ return NULL;
+/*
+ * Check the line dimensions.
+ */
+ if(dim < strlen(line) + 1) {
+ _err_record_msg(glh->err, "'dim' argument inconsistent with strlen(line)",
+ END_ERR_MSG);
+ errno = EINVAL;
+ return NULL;
+ };
+/*
+ * Copy the recalled line into the provided line buffer.
+ */
+ _glh_return_line(glh->list.tail->line, line, dim);
+/*
+ * Since we have returned to the starting point of the search, cancel it.
+ */
+ _glh_cancel_search(glh);
+ return line;
+}
+
+/*.......................................................................
+ * Query the id of a history line offset by a given number of lines from
+ * the one that is currently being recalled. If a recall session isn't
+ * in progress, or the offset points outside the history list, 0 is
+ * returned.
+ *
+ * Input:
+ * glh GlHistory * The input-line history maintenance object.
+ * offset int The line offset (0 for the current line, < 0
+ * for an older line, > 0 for a newer line.
+ * Output:
+ * return GlhLineID The identifier of the line that is currently
+ * being recalled, or 0 if no recall session is
+ * currently in progress.
+ */
+GlhLineID _glh_line_id(GlHistory *glh, int offset)
+{
+ GlhLineNode *node; /* The line location node being checked */
+/*
+ * Is history enabled?
+ */
+ if(!glh->enable || !glh->buffer || glh->max_lines == 0)
+ return 0;
+/*
+ * Search forward 'offset' lines to find the required line.
+ */
+ if(offset >= 0) {
+ for(node=glh->recall; node && offset != 0; node=node->next) {
+ if(node->group == glh->group)
+ offset--;
+ };
+ } else {
+ for(node=glh->recall; node && offset != 0; node=node->prev) {
+ if(node->group == glh->group)
+ offset++;
+ };
+ };
+ return node ? node->id : 0;
+}
+
+/*.......................................................................
+ * Recall a line by its history buffer ID. If the line is no longer
+ * in the buffer, or the id is zero, NULL is returned.
+ *
+ * Input:
+ * glh GlHistory * The input-line history maintenance object.
+ * id GlhLineID The ID of the line to be returned.
+ * line char * The input line buffer. On input this should contain
+ * the current input line, and on output, its contents
+ * will have been replaced with the saved line.
+ * dim size_t The allocated dimensions of the line buffer.
+ * Output:
+ * return char * A pointer to line[0], or NULL if not found.
+ */
+char *_glh_recall_line(GlHistory *glh, GlhLineID id, char *line, size_t dim)
+{
+ GlhLineNode *node; /* The line location node being checked */
+/*
+ * Is history enabled?
+ */
+ if(!glh->enable || !glh->buffer || glh->max_lines == 0)
+ return NULL;
+/*
+ * Preserve the input line if needed.
+ */
+ if(_glh_prepare_for_recall(glh, line))
+ return NULL;
+/*
+ * Search for the specified line.
+ */
+ node = _glh_find_id(glh, id);
+/*
+ * Not found?
+ */
+ if(!node || node->group != glh->group)
+ return NULL;
+/*
+ * Record the node of the matching line as the starting point
+ * for subsequent searches.
+ */
+ glh->recall = node;
+/*
+ * Copy the recalled line into the provided line buffer.
+ */
+ _glh_return_line(node->line, line, dim);
+ return line;
+}
+
+/*.......................................................................
+ * Save the current history in a specified file.
+ *
+ * Input:
+ * glh GlHistory * The input-line history maintenance object.
+ * filename const char * The name of the new file to record the
+ * history in.
+ * comment const char * Extra information such as timestamps will
+ * be recorded on a line started with this
+ * string, the idea being that the file can
+ * double as a command file. Specify "" if
+ * you don't care.
+ * max_lines int The maximum number of lines to save, or -1
+ * to save all of the lines in the history
+ * list.
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+int _glh_save_history(GlHistory *glh, const char *filename, const char *comment,
+ int max_lines)
+{
+#ifdef WITHOUT_FILE_SYSTEM
+ _err_record_msg(glh->err, "Can't save history without filesystem access",
+ END_ERR_MSG);
+ errno = EINVAL;
+ return 1;
+#else
+ FILE *fp; /* The output file */
+ GlhLineNode *node; /* The line being saved */
+ GlhLineNode *head; /* The head of the list of lines to be saved */
+ GlhLineSeg *seg; /* One segment of a line being saved */
+/*
+ * Check the arguments.
+ */
+ if(!glh || !filename || !comment) {
+ if(glh)
+ _err_record_msg(glh->err, "NULL argument(s)", END_ERR_MSG);
+ errno = EINVAL;
+ return 1;
+ };
+/*
+ * Attempt to open the specified file.
+ */
+ fp = fopen(filename, "w");
+ if(!fp)
+ return _glh_cant_save_history(glh, "Can't open", filename, NULL);
+/*
+ * If a ceiling on the number of lines to save was specified, count
+ * that number of lines backwards, to find the first line to be saved.
+ */
+ head = NULL;
+ if(max_lines >= 0) {
+ for(head=glh->list.tail; head && --max_lines > 0; head=head->prev)
+ ;
+ };
+ if(!head)
+ head = glh->list.head;
+/*
+ * Write the contents of the history buffer to the history file, writing
+ * associated data such as timestamps, to a line starting with the
+ * specified comment string.
+ */
+ for(node=head; node; node=node->next) {
+/*
+ * Write peripheral information associated with the line, as a comment.
+ */
+ if(fprintf(fp, "%s ", comment) < 0 ||
+ _glh_write_timestamp(fp, node->timestamp) ||
+ fprintf(fp, " %u\n", node->group) < 0) {
+ return _glh_cant_save_history(glh, "Error writing", filename, fp);
+ };
+/*
+ * Write the history line.
+ */
+ for(seg=node->line->head; seg; seg=seg->next) {
+ size_t slen = seg->next ? GLH_SEG_SIZE : strlen(seg->s);
+ if(fwrite(seg->s, sizeof(char), slen, fp) != slen)
+ return _glh_cant_save_history(glh, "Error writing", filename, fp);
+ };
+ fputc('\n', fp);
+ };
+/*
+ * Close the history file.
+ */
+ if(fclose(fp) == EOF)
+ return _glh_cant_save_history(glh, "Error writing", filename, NULL);
+ return 0;
+#endif
+}
+
+#ifndef WITHOUT_FILE_SYSTEM
+/*.......................................................................
+ * This is a private error return function of _glh_save_history(). It
+ * composes an error report in the error buffer, composed using
+ * sprintf("%s %s (%s)", message, filename, strerror(errno)). It then
+ * closes fp and returns the error return code of _glh_save_history().
+ *
+ * Input:
+ * glh GlHistory * The input-line history maintenance object.
+ * message const char * A message to be followed by the filename.
+ * filename const char * The name of the offending output file.
+ * fp FILE * The stream to be closed (send NULL if not
+ * open).
+ * Output:
+ * return int Always 1.
+ */
+static int _glh_cant_save_history(GlHistory *glh, const char *message,
+ const char *filename, FILE *fp)
+{
+ _err_record_msg(glh->err, message, filename, " (",
+ strerror(errno), ")", END_ERR_MSG);
+ if(fp)
+ (void) fclose(fp);
+ return 1;
+}
+
+/*.......................................................................
+ * Write a timestamp to a given stdio stream, in the format
+ * yyyymmddhhmmss
+ *
+ * Input:
+ * fp FILE * The stream to write to.
+ * timestamp time_t The timestamp to be written.
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+static int _glh_write_timestamp(FILE *fp, time_t timestamp)
+{
+ struct tm *t; /* THe broken-down calendar time */
+/*
+ * Get the calendar components corresponding to the given timestamp.
+ */
+ if(timestamp < 0 || (t = localtime(&timestamp)) == NULL) {
+ if(fprintf(fp, "?") < 0)
+ return 1;
+ return 0;
+ };
+/*
+ * Write the calendar time as yyyymmddhhmmss.
+ */
+ if(fprintf(fp, "%04d%02d%02d%02d%02d%02d", t->tm_year + 1900, t->tm_mon + 1,
+ t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec) < 0)
+ return 1;
+ return 0;
+}
+
+#endif
+
+/*.......................................................................
+ * Restore previous history lines from a given file.
+ *
+ * Input:
+ * glh GlHistory * The input-line history maintenance object.
+ * filename const char * The name of the file to read from.
+ * comment const char * The same comment string that was passed to
+ * _glh_save_history() when this file was
+ * written.
+ * line char * A buffer into which lines can be read.
+ * dim size_t The allocated dimension of line[].
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+int _glh_load_history(GlHistory *glh, const char *filename, const char *comment,
+ char *line, size_t dim)
+{
+#ifdef WITHOUT_FILE_SYSTEM
+ _err_record_msg(glh->err, "Can't load history without filesystem access",
+ END_ERR_MSG);
+ errno = EINVAL;
+ return 1;
+#else
+ FILE *fp; /* The output file */
+ size_t comment_len; /* The length of the comment string */
+ time_t timestamp; /* The timestamp of the history line */
+ unsigned group; /* The identifier of the history group to which */
+ /* the line belongs. */
+ int lineno; /* The line number being read */
+/*
+ * Check the arguments.
+ */
+ if(!glh || !filename || !comment || !line) {
+ if(glh)
+ _err_record_msg(glh->err, "NULL argument(s)", END_ERR_MSG);
+ errno = EINVAL;
+ return 1;
+ };
+/*
+ * Measure the length of the comment string.
+ */
+ comment_len = strlen(comment);
+/*
+ * Clear the history list.
+ */
+ _glh_clear_history(glh, 1);
+/*
+ * Attempt to open the specified file. Don't treat it as an error
+ * if the file doesn't exist.
+ */
+ fp = fopen(filename, "r");
+ if(!fp)
+ return 0;
+/*
+ * Attempt to read each line and preceding peripheral info, and add these
+ * to the history list.
+ */
+ for(lineno=1; fgets(line, dim, fp) != NULL; lineno++) {
+ char *lptr; /* A pointer into the input line */
+/*
+ * Check that the line starts with the comment string.
+ */
+ if(strncmp(line, comment, comment_len) != 0) {
+ return _glh_cant_load_history(glh, filename, lineno,
+ "Corrupt history parameter line", fp);
+ };
+/*
+ * Skip spaces and tabs after the comment.
+ */
+ for(lptr=line+comment_len; *lptr && (*lptr==' ' || *lptr=='\t'); lptr++)
+ ;
+/*
+ * The next word must be a timestamp.
+ */
+ if(_glh_decode_timestamp(lptr, &lptr, &timestamp)) {
+ return _glh_cant_load_history(glh, filename, lineno,
+ "Corrupt timestamp", fp);
+ };
+/*
+ * Skip spaces and tabs.
+ */
+ while(*lptr==' ' || *lptr=='\t')
+ lptr++;
+/*
+ * The next word must be an unsigned integer group number.
+ */
+ group = (int) strtoul(lptr, &lptr, 10);
+ if(*lptr != ' ' && *lptr != '\n') {
+ return _glh_cant_load_history(glh, filename, lineno,
+ "Corrupt group id", fp);
+ };
+/*
+ * Skip spaces and tabs.
+ */
+ while(*lptr==' ' || *lptr=='\t')
+ lptr++;
+/*
+ * There shouldn't be anything left on the line.
+ */
+ if(*lptr != '\n') {
+ return _glh_cant_load_history(glh, filename, lineno,
+ "Corrupt parameter line", fp);
+ };
+/*
+ * Now read the history line itself.
+ */
+ lineno++;
+ if(fgets(line, dim, fp) == NULL)
+ return _glh_cant_load_history(glh, filename, lineno, "Read error", fp);
+/*
+ * Append the line to the history buffer.
+ */
+ if(_glh_add_history(glh, line, 1)) {
+ return _glh_cant_load_history(glh, filename, lineno,
+ "Insufficient memory to record line", fp);
+ };
+/*
+ * Record the group and timestamp information along with the line.
+ */
+ if(glh->list.tail) {
+ glh->list.tail->timestamp = timestamp;
+ glh->list.tail->group = group;
+ };
+ };
+/*
+ * Close the file.
+ */
+ (void) fclose(fp);
+ return 0;
+#endif
+}
+
+#ifndef WITHOUT_FILE_SYSTEM
+/*.......................................................................
+ * This is a private error return function of _glh_load_history().
+ */
+static int _glh_cant_load_history(GlHistory *glh, const char *filename,
+ int lineno, const char *message, FILE *fp)
+{
+ char lnum[20];
+/*
+ * Convert the line number to a string.
+ */
+ sprintf(lnum, "%d", lineno);
+/*
+ * Render an error message.
+ */
+ _err_record_msg(glh->err, filename, ":", lnum, ":", message, END_ERR_MSG);
+/*
+ * Close the file.
+ */
+ if(fp)
+ (void) fclose(fp);
+ return 1;
+}
+
+/*.......................................................................
+ * Read a timestamp from a string.
+ *
+ * Input:
+ * string char * The string to read from.
+ * Input/Output:
+ * endp char ** On output *endp will point to the next unprocessed
+ * character in string[].
+ * timestamp time_t * The timestamp will be assigned to *t.
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+static int _glh_decode_timestamp(char *string, char **endp, time_t *timestamp)
+{
+ unsigned year,month,day,hour,min,sec; /* Calendar time components */
+ struct tm t;
+/*
+ * There are 14 characters in the date format yyyymmddhhmmss.
+ */
+ enum {TSLEN=14};
+ char timestr[TSLEN+1]; /* The timestamp part of the string */
+/*
+ * If the time wasn't available at the time that the line was recorded
+ * it will have been written as "?". Check for this before trying
+ * to read the timestamp.
+ */
+ if(string[0] == '\?') {
+ *endp = string+1;
+ *timestamp = -1;
+ return 0;
+ };
+/*
+ * The timestamp is expected to be written in the form yyyymmddhhmmss.
+ */
+ if(strlen(string) < TSLEN) {
+ *endp = string;
+ return 1;
+ };
+/*
+ * Copy the timestamp out of the string.
+ */
+ strncpy(timestr, string, TSLEN);
+ timestr[TSLEN] = '\0';
+/*
+ * Decode the timestamp.
+ */
+ if(sscanf(timestr, "%4u%2u%2u%2u%2u%2u", &year, &month, &day, &hour, &min,
+ &sec) != 6) {
+ *endp = string;
+ return 1;
+ };
+/*
+ * Advance the string pointer over the successfully read timestamp.
+ */
+ *endp = string + TSLEN;
+/*
+ * Copy the read values into a struct tm.
+ */
+ t.tm_sec = sec;
+ t.tm_min = min;
+ t.tm_hour = hour;
+ t.tm_mday = day;
+ t.tm_wday = 0;
+ t.tm_yday = 0;
+ t.tm_mon = month - 1;
+ t.tm_year = year - 1900;
+ t.tm_isdst = -1;
+/*
+ * Convert the contents of the struct tm to a time_t.
+ */
+ *timestamp = mktime(&t);
+ return 0;
+}
+#endif
+
+/*.......................................................................
+ * Switch history groups.
+ *
+ * Input:
+ * glh GlHistory * The input-line history maintenance object.
+ * group unsigned The new group identifier. This will be recorded
+ * with subsequent history lines, and subsequent
+ * history searches will only return lines with
+ * this group identifier. This allows multiple
+ * separate history lists to exist within
+ * a single GlHistory object. Note that the
+ * default group identifier is 0.
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+int _glh_set_group(GlHistory *glh, unsigned group)
+{
+/*
+ * Check the arguments.
+ */
+ if(!glh) {
+ if(glh)
+ _err_record_msg(glh->err, "NULL argument(s)", END_ERR_MSG);
+ errno = EINVAL;
+ return 1;
+ };
+/*
+ * Is the group being changed?
+ */
+ if(group != glh->group) {
+/*
+ * Cancel any ongoing search.
+ */
+ if(_glh_cancel_search(glh))
+ return 1;
+/*
+ * Record the new group.
+ */
+ glh->group = group;
+ };
+ return 0;
+}
+
+/*.......................................................................
+ * Query the current history group.
+ *
+ * Input:
+ * glh GlHistory * The input-line history maintenance object.
+ * Output:
+ * return unsigned The group identifier.
+ */
+int _glh_get_group(GlHistory *glh)
+{
+ return glh ? glh->group : 0;
+}
+
+/*.......................................................................
+ * Display the contents of the history list.
+ *
+ * Input:
+ * glh GlHistory * The input-line history maintenance object.
+ * write_fn GlWriteFn * The function to call to write the line, or
+ * 0 to discard the output.
+ * data void * Anonymous data to pass to write_fn().
+ * fmt const char * A format string. This can contain arbitrary
+ * characters, which are written verbatim, plus
+ * any of the following format directives:
+ * %D - The date, like 2001-11-20
+ * %T - The time of day, like 23:59:59
+ * %N - The sequential entry number of the
+ * line in the history buffer.
+ * %G - The history group number of the line.
+ * %% - A literal % character.
+ * %H - The history line.
+ * all_groups int If true, display history lines from all
+ * history groups. Otherwise only display
+ * those of the current history group.
+ * max_lines int If max_lines is < 0, all available lines
+ * are displayed. Otherwise only the most
+ * recent max_lines lines will be displayed.
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+int _glh_show_history(GlHistory *glh, GlWriteFn *write_fn, void *data,
+ const char *fmt, int all_groups, int max_lines)
+{
+ GlhLineNode *node; /* The line being displayed */
+ GlhLineNode *oldest; /* The oldest line to display */
+ GlhLineSeg *seg; /* One segment of a line being displayed */
+ enum {TSMAX=32}; /* The maximum length of the date and time string */
+ char buffer[TSMAX+1]; /* The buffer in which to write the date and time */
+ int idlen; /* The length of displayed ID strings */
+ unsigned grpmax; /* The maximum group number in the buffer */
+ int grplen; /* The number of characters needed to print grpmax */
+ int len; /* The length of a string to be written */
+/*
+ * Check the arguments.
+ */
+ if(!glh || !write_fn || !fmt) {
+ if(glh)
+ _err_record_msg(glh->err, "NULL argument(s)", END_ERR_MSG);
+ errno = EINVAL;
+ return 1;
+ };
+/*
+ * Is history enabled?
+ */
+ if(!glh->enable || !glh->list.head)
+ return 0;
+/*
+ * Work out the length to display ID numbers, choosing the length of
+ * the biggest number in the buffer. Smaller numbers will be padded
+ * with leading zeroes if needed.
+ */
+ sprintf(buffer, "%lu", (unsigned long) glh->list.tail->id);
+ idlen = strlen(buffer);
+/*
+ * Find the largest group number.
+ */
+ grpmax = 0;
+ for(node=glh->list.head; node; node=node->next) {
+ if(node->group > grpmax)
+ grpmax = node->group;
+ };
+/*
+ * Find out how many characters are needed to display the group number.
+ */
+ sprintf(buffer, "%u", (unsigned) grpmax);
+ grplen = strlen(buffer);
+/*
+ * Find the node that follows the oldest line to be displayed.
+ */
+ if(max_lines < 0) {
+ oldest = glh->list.head;
+ } else if(max_lines==0) {
+ return 0;
+ } else {
+ for(oldest=glh->list.tail; oldest; oldest=oldest->prev) {
+ if((all_groups || oldest->group == glh->group) && --max_lines <= 0)
+ break;
+ };
+/*
+ * If the number of lines in the buffer doesn't exceed the specified
+ * maximum, start from the oldest line in the buffer.
+ */
+ if(!oldest)
+ oldest = glh->list.head;
+ };
+/*
+ * List the history lines in increasing time order.
+ */
+ for(node=oldest; node; node=node->next) {
+/*
+ * Only display lines from the current history group, unless
+ * told otherwise.
+ */
+ if(all_groups || node->group == glh->group) {
+ const char *fptr; /* A pointer into the format string */
+ struct tm *t = NULL; /* The broken time version of the timestamp */
+/*
+ * Work out the calendar representation of the node timestamp.
+ */
+ if(node->timestamp != (time_t) -1)
+ t = localtime(&node->timestamp);
+/*
+ * Parse the format string.
+ */
+ fptr = fmt;
+ while(*fptr) {
+/*
+ * Search for the start of the next format directive or the end of the string.
+ */
+ const char *start = fptr;
+ while(*fptr && *fptr != '%')
+ fptr++;
+/*
+ * Display any literal characters that precede the located directive.
+ */
+ if(fptr > start) {
+ len = (int) (fptr - start);
+ if(write_fn(data, start, len) != len)
+ return 1;
+ };
+/*
+ * Did we hit a new directive before the end of the line?
+ */
+ if(*fptr) {
+/*
+ * Obey the directive. Ignore unknown directives.
+ */
+ switch(*++fptr) {
+ case 'D': /* Display the date */
+ if(t && strftime(buffer, TSMAX, "%Y-%m-%d", t) != 0) {
+ len = strlen(buffer);
+ if(write_fn(data, buffer, len) != len)
+ return 1;
+ };
+ break;
+ case 'T': /* Display the time of day */
+ if(t && strftime(buffer, TSMAX, "%H:%M:%S", t) != 0) {
+ len = strlen(buffer);
+ if(write_fn(data, buffer, len) != len)
+ return 1;
+ };
+ break;
+ case 'N': /* Display the sequential entry number */
+ sprintf(buffer, "%*lu", idlen, (unsigned long) node->id);
+ len = strlen(buffer);
+ if(write_fn(data, buffer, len) != len)
+ return 1;
+ break;
+ case 'G':
+ sprintf(buffer, "%*u", grplen, (unsigned) node->group);
+ len = strlen(buffer);
+ if(write_fn(data, buffer, len) != len)
+ return 1;
+ break;
+ case 'H': /* Display the history line */
+ for(seg=node->line->head; seg; seg=seg->next) {
+ len = seg->next ? GLH_SEG_SIZE : strlen(seg->s);
+ if(write_fn(data, seg->s, len) != len)
+ return 1;
+ };
+ break;
+ case '%': /* A literal % symbol */
+ if(write_fn(data, "%", 1) != 1)
+ return 1;
+ break;
+ };
+/*
+ * Skip the directive.
+ */
+ if(*fptr)
+ fptr++;
+ };
+ };
+ };
+ };
+ return 0;
+}
+
+/*.......................................................................
+ * Change the size of the history buffer.
+ *
+ * Input:
+ * glh GlHistory * The input-line history maintenance object.
+ * bufsize size_t The number of bytes in the history buffer, or 0
+ * to delete the buffer completely.
+ * Output:
+ * return int 0 - OK.
+ * 1 - Insufficient memory (the previous buffer
+ * will have been retained). No error message
+ * will be displayed.
+ */
+int _glh_resize_history(GlHistory *glh, size_t bufsize)
+{
+ int nbuff; /* The number of segments in the new buffer */
+ int i;
+/*
+ * Check the arguments.
+ */
+ if(!glh) {
+ errno = EINVAL;
+ return 1;
+ };
+/*
+ * How many buffer segments does the requested buffer size correspond
+ * to?
+ */
+ nbuff = (bufsize+GLH_SEG_SIZE-1) / GLH_SEG_SIZE;
+/*
+ * Has a different size than the current size been requested?
+ */
+ if(glh->nbuff != nbuff) {
+/*
+ * Cancel any ongoing search.
+ */
+ (void) _glh_cancel_search(glh);
+/*
+ * Create a wholly new buffer?
+ */
+ if(glh->nbuff == 0 && nbuff>0) {
+ glh->buffer = (GlhLineSeg *) malloc(sizeof(GlhLineSeg) * nbuff);
+ if(!glh->buffer)
+ return 1;
+ glh->nbuff = nbuff;
+ glh->nfree = glh->nbuff;
+ glh->nbusy = 0;
+ glh->nline = 0;
+/*
+ * Link the currently unused nodes of the buffer into a list.
+ */
+ glh->unused = glh->buffer;
+ for(i=0; i<glh->nbuff-1; i++) {
+ GlhLineSeg *seg = glh->unused + i;
+ seg->next = seg + 1;
+ };
+ glh->unused[i].next = NULL;
+/*
+ * Delete an existing buffer?
+ */
+ } else if(nbuff == 0) {
+ _glh_clear_history(glh, 1);
+ free(glh->buffer);
+ glh->buffer = NULL;
+ glh->unused = NULL;
+ glh->nbuff = 0;
+ glh->nfree = 0;
+ glh->nbusy = 0;
+ glh->nline = 0;
+/*
+ * Change from one finite buffer size to another?
+ */
+ } else {
+ GlhLineSeg *buffer; /* The resized buffer */
+ int nbusy; /* The number of used line segments in the new buffer */
+/*
+ * Starting from the oldest line in the buffer, discard lines until
+ * the buffer contains at most 'nbuff' used line segments.
+ */
+ while(glh->list.head && glh->nbusy > nbuff)
+ _glh_discard_line(glh, glh->list.head);
+/*
+ * Attempt to allocate a new buffer.
+ */
+ buffer = (GlhLineSeg *) malloc(nbuff * sizeof(GlhLineSeg));
+ if(!buffer) {
+ errno = ENOMEM;
+ return 1;
+ };
+/*
+ * Copy the used segments of the old buffer to the start of the new buffer.
+ */
+ nbusy = 0;
+ for(i=0; i<GLH_HASH_SIZE; i++) {
+ GlhHashBucket *b = glh->hash.bucket + i;
+ GlhHashNode *hnode;
+ for(hnode=b->lines; hnode; hnode=hnode->next) {
+ GlhLineSeg *seg = hnode->head;
+ hnode->head = buffer + nbusy;
+ for( ; seg; seg=seg->next) {
+ buffer[nbusy] = *seg;
+ buffer[nbusy].next = seg->next ? &buffer[nbusy+1] : NULL;
+ nbusy++;
+ };
+ };
+ };
+/*
+ * Make a list of the new buffer's unused segments.
+ */
+ for(i=nbusy; i<nbuff-1; i++)
+ buffer[i].next = &buffer[i+1];
+ if(i < nbuff)
+ buffer[i].next = NULL;
+/*
+ * Discard the old buffer.
+ */
+ free(glh->buffer);
+/*
+ * Install the new buffer.
+ */
+ glh->buffer = buffer;
+ glh->nbuff = nbuff;
+ glh->nbusy = nbusy;
+ glh->nfree = nbuff - nbusy;
+ glh->unused = glh->nfree > 0 ? (buffer + nbusy) : NULL;
+ };
+ };
+ return 0;
+}
+
+/*.......................................................................
+ * Set an upper limit to the number of lines that can be recorded in the
+ * history list, or remove a previously specified limit.
+ *
+ * Input:
+ * glh GlHistory * The input-line history maintenance object.
+ * max_lines int The maximum number of lines to allow, or -1 to
+ * cancel a previous limit and allow as many lines
+ * as will fit in the current history buffer size.
+ */
+void _glh_limit_history(GlHistory *glh, int max_lines)
+{
+ if(!glh)
+ return;
+/*
+ * Apply a new limit?
+ */
+ if(max_lines >= 0 && max_lines != glh->max_lines) {
+/*
+ * Count successively older lines until we reach the start of the
+ * list, or until we have seen max_lines lines (at which point 'node'
+ * will be line number max_lines+1).
+ */
+ int nline = 0;
+ GlhLineNode *node;
+ for(node=glh->list.tail; node && ++nline <= max_lines; node=node->prev)
+ ;
+/*
+ * Discard any lines that exceed the limit.
+ */
+ if(node) {
+ GlhLineNode *oldest = node->next; /* The oldest line to be kept */
+/*
+ * Delete nodes from the head of the list until we reach the node that
+ * is to be kept.
+ */
+ while(glh->list.head && glh->list.head != oldest)
+ _glh_discard_line(glh, glh->list.head);
+ };
+ };
+/*
+ * Record the new limit.
+ */
+ glh->max_lines = max_lines;
+ return;
+}
+
+/*.......................................................................
+ * Discard either all history, or the history associated with the current
+ * history group.
+ *
+ * Input:
+ * glh GlHistory * The input-line history maintenance object.
+ * all_groups int If true, clear all of the history. If false,
+ * clear only the stored lines associated with the
+ * currently selected history group.
+ */
+void _glh_clear_history(GlHistory *glh, int all_groups)
+{
+ int i;
+/*
+ * Check the arguments.
+ */
+ if(!glh)
+ return;
+/*
+ * Cancel any ongoing search.
+ */
+ (void) _glh_cancel_search(glh);
+/*
+ * Delete all history lines regardless of group?
+ */
+ if(all_groups) {
+/*
+ * Claer the time-ordered list of lines.
+ */
+ _rst_FreeList(glh->list.node_mem);
+ glh->list.head = glh->list.tail = NULL;
+ glh->nline = 0;
+ glh->id_node = NULL;
+/*
+ * Clear the hash table.
+ */
+ for(i=0; i<GLH_HASH_SIZE; i++)
+ glh->hash.bucket[i].lines = NULL;
+ _rst_FreeList(glh->hash.node_mem);
+/*
+ * Move all line segment nodes back onto the list of unused segments.
+ */
+ if(glh->buffer) {
+ glh->unused = glh->buffer;
+ for(i=0; i<glh->nbuff-1; i++) {
+ GlhLineSeg *seg = glh->unused + i;
+ seg->next = seg + 1;
+ };
+ glh->unused[i].next = NULL;
+ glh->nfree = glh->nbuff;
+ glh->nbusy = 0;
+ } else {
+ glh->unused = NULL;
+ glh->nbusy = glh->nfree = 0;
+ };
+/*
+ * Just delete lines of the current group?
+ */
+ } else {
+ GlhLineNode *node; /* The line node being checked */
+ GlhLineNode *next; /* The line node that follows 'node' */
+/*
+ * Search out and delete the line nodes of the current group.
+ */
+ for(node=glh->list.head; node; node=next) {
+/*
+ * Keep a record of the following node before we delete the current
+ * node.
+ */
+ next = node->next;
+/*
+ * Discard this node?
+ */
+ if(node->group == glh->group)
+ _glh_discard_line(glh, node);
+ };
+ };
+ return;
+}
+
+/*.......................................................................
+ * Temporarily enable or disable the history list.
+ *
+ * Input:
+ * glh GlHistory * The input-line history maintenance object.
+ * enable int If true, turn on the history mechanism. If
+ * false, disable it.
+ */
+void _glh_toggle_history(GlHistory *glh, int enable)
+{
+ if(glh)
+ glh->enable = enable;
+}
+
+/*.......................................................................
+ * Discard a given archived input line.
+ *
+ * Input:
+ * glh GlHistory * The history container object.
+ * node GlhLineNode * The line to be discarded, specified via its
+ * entry in the time-ordered list of historical
+ * input lines.
+ */
+static void _glh_discard_line(GlHistory *glh, GlhLineNode *node)
+{
+/*
+ * Remove the node from the linked list.
+ */
+ if(node->prev)
+ node->prev->next = node->next;
+ else
+ glh->list.head = node->next;
+ if(node->next)
+ node->next->prev = node->prev;
+ else
+ glh->list.tail = node->prev;
+/*
+ * If we are deleting the node that is marked as the start point of the
+ * last ID search, remove the cached starting point.
+ */
+ if(node == glh->id_node)
+ glh->id_node = NULL;
+/*
+ * If we are deleting the node that is marked as the start point of the
+ * next prefix search, cancel the search.
+ */
+ if(node == glh->recall)
+ _glh_cancel_search(glh);
+/*
+ * Delete our copy of the line.
+ */
+ node->line = _glh_discard_copy(glh, node->line);
+/*
+ * Return the node to the freelist.
+ */
+ (void) _del_FreeListNode(glh->list.node_mem, node);
+/*
+ * Record the removal of a line from the list.
+ */
+ glh->nline--;
+ return;
+}
+
+/*.......................................................................
+ * Lookup the details of a given history line, given its id.
+ *
+ * Input:
+ * glh GlHistory * The input-line history maintenance object.
+ * id GlLineID The sequential number of the line.
+ * Input/Output:
+ * line const char ** A pointer to a copy of the history line will be
+ * assigned to *line. Beware that this pointer may
+ * be invalidated by the next call to any public
+ * history function.
+ * group unsigned * The group membership of the line will be assigned
+ * to *group.
+ * timestamp time_t * The timestamp of the line will be assigned to
+ * *timestamp.
+ * Output:
+ * return int 0 - The requested line wasn't found.
+ * 1 - The line was found.
+ */
+int _glh_lookup_history(GlHistory *glh, GlhLineID id, const char **line,
+ unsigned *group, time_t *timestamp)
+{
+ GlhLineNode *node; /* The located line location node */
+/*
+ * Check the arguments.
+ */
+ if(!glh)
+ return 0;
+/*
+ * Search for the line that has the specified ID.
+ */
+ node = _glh_find_id(glh, id);
+/*
+ * Not found?
+ */
+ if(!node)
+ return 0;
+/*
+ * Has the history line been requested?
+ */
+ if(line) {
+/*
+ * If necessary, reallocate the lookup buffer to accomodate the size of
+ * a copy of the located line.
+ */
+ if(node->line->len + 1 > glh->lbuf_dim) {
+ int lbuf_dim = node->line->len + 1;
+ char *lbuf = realloc(glh->lbuf, lbuf_dim);
+ if(!lbuf) {
+ errno = ENOMEM;
+ return 0;
+ };
+ glh->lbuf_dim = lbuf_dim;
+ glh->lbuf = lbuf;
+ };
+/*
+ * Copy the history line into the lookup buffer.
+ */
+ _glh_return_line(node->line, glh->lbuf, glh->lbuf_dim);
+/*
+ * Assign the lookup buffer as the returned line pointer.
+ */
+ *line = glh->lbuf;
+ };
+/*
+ * Does the caller want to know the group of the line?
+ */
+ if(group)
+ *group = node->group;
+/*
+ * Does the caller want to know the timestamp of the line?
+ */
+ if(timestamp)
+ *timestamp = node->timestamp;
+ return 1;
+}
+
+/*.......................................................................
+ * Lookup a node in the history list by its ID.
+ *
+ * Input:
+ * glh GlHistory * The input-line history maintenance object.
+ * id GlhLineID The ID of the line to be returned.
+ * Output:
+ * return GlhLIneNode * The located node, or NULL if not found.
+ */
+static GlhLineNode *_glh_find_id(GlHistory *glh, GlhLineID id)
+{
+ GlhLineNode *node; /* The node being checked */
+/*
+ * Is history enabled?
+ */
+ if(!glh->enable || !glh->list.head)
+ return NULL;
+/*
+ * If possible, start at the end point of the last ID search.
+ * Otherwise start from the head of the list.
+ */
+ node = glh->id_node;
+ if(!node)
+ node = glh->list.head;
+/*
+ * Search forwards from 'node'?
+ */
+ if(node->id < id) {
+ while(node && node->id != id)
+ node = node->next;
+ glh->id_node = node ? node : glh->list.tail;
+/*
+ * Search backwards from 'node'?
+ */
+ } else {
+ while(node && node->id != id)
+ node = node->prev;
+ glh->id_node = node ? node : glh->list.head;
+ };
+/*
+ * Return the located node (this will be NULL if the ID wasn't found).
+ */
+ return node;
+}
+
+/*.......................................................................
+ * Query the state of the history list. Note that any of the input/output
+ * pointers can be specified as NULL.
+ *
+ * Input:
+ * glh GlHistory * The input-line history maintenance object.
+ * Input/Output:
+ * enabled int * If history is enabled, *enabled will be
+ * set to 1. Otherwise it will be assigned 0.
+ * group unsigned * The current history group ID will be assigned
+ * to *group.
+ * max_lines int * The currently requested limit on the number
+ * of history lines in the list, or -1 if
+ * unlimited.
+ */
+void _glh_state_of_history(GlHistory *glh, int *enabled, unsigned *group,
+ int *max_lines)
+{
+ if(glh) {
+ if(enabled)
+ *enabled = glh->enable;
+ if(group)
+ *group = glh->group;
+ if(max_lines)
+ *max_lines = glh->max_lines;
+ };
+}
+
+/*.......................................................................
+ * Get the range of lines in the history buffer.
+ *
+ * Input:
+ * glh GlHistory * The input-line history maintenance object.
+ * Input/Output:
+ * oldest unsigned long * The sequential entry number of the oldest
+ * line in the history list will be assigned
+ * to *oldest, unless there are no lines, in
+ * which case 0 will be assigned.
+ * newest unsigned long * The sequential entry number of the newest
+ * line in the history list will be assigned
+ * to *newest, unless there are no lines, in
+ * which case 0 will be assigned.
+ * nlines int * The number of lines currently in the history
+ * list.
+ */
+void _glh_range_of_history(GlHistory *glh, unsigned long *oldest,
+ unsigned long *newest, int *nlines)
+{
+ if(glh) {
+ if(oldest)
+ *oldest = glh->list.head ? glh->list.head->id : 0;
+ if(newest)
+ *newest = glh->list.tail ? glh->list.tail->id : 0;
+ if(nlines)
+ *nlines = glh->nline;
+ };
+}
+
+/*.......................................................................
+ * Return the size of the history buffer and the amount of the
+ * buffer that is currently in use.
+ *
+ * Input:
+ * glh GlHistory * The input-line history maintenance object.
+ * Input/Output:
+ * buff_size size_t * The size of the history buffer (bytes).
+ * buff_used size_t * The amount of the history buffer that
+ * is currently occupied (bytes).
+ */
+void _glh_size_of_history(GlHistory *glh, size_t *buff_size, size_t *buff_used)
+{
+ if(glh) {
+ if(buff_size)
+ *buff_size = (glh->nbusy + glh->nfree) * GLH_SEG_SIZE;
+/*
+ * Determine the amount of buffer space that is currently occupied.
+ */
+ if(buff_used)
+ *buff_used = glh->nbusy * GLH_SEG_SIZE;
+ };
+}
+
+/*.......................................................................
+ * Return extra information (ie. in addition to that provided by errno)
+ * about the last error to occur in any of the public functions of this
+ * module.
+ *
+ * Input:
+ * glh GlHistory * The container of the history list.
+ * Output:
+ * return const char * A pointer to the internal buffer in which
+ * the error message is temporarily stored.
+ */
+const char *_glh_last_error(GlHistory *glh)
+{
+ return glh ? _err_get_msg(glh->err) : "NULL GlHistory argument";
+}
+
+/*.......................................................................
+ * Unless already stored, store a copy of the line in the history buffer,
+ * then return a reference-counted hash-node pointer to this copy.
+ *
+ * Input:
+ * glh GlHistory * The history maintenance buffer.
+ * line const char * The history line to be recorded.
+ * n size_t The length of the string, excluding any '\0'
+ * terminator.
+ * Output:
+ * return GlhHashNode * The hash-node containing the stored line, or
+ * NULL on error.
+ */
+static GlhHashNode *_glh_acquire_copy(GlHistory *glh, const char *line,
+ size_t n)
+{
+ GlhHashBucket *bucket; /* The hash-table bucket of the line */
+ GlhHashNode *hnode; /* The hash-table node of the line */
+ int i;
+/*
+ * In which bucket should the line be recorded?
+ */
+ bucket = glh_find_bucket(glh, line, n);
+/*
+ * Is the line already recorded there?
+ */
+ hnode = glh_find_hash_node(bucket, line, n);
+/*
+ * If the line isn't recorded in the buffer yet, make room for it.
+ */
+ if(!hnode) {
+ GlhLineSeg *seg; /* A line segment */
+ int offset; /* An offset into line[] */
+/*
+ * How many string segments will be needed to record the new line,
+ * including space for a '\0' terminator?
+ */
+ int nseg = ((n+1) + GLH_SEG_SIZE-1) / GLH_SEG_SIZE;
+/*
+ * Discard the oldest history lines in the buffer until at least
+ * 'nseg' segments have been freed up, or until we run out of buffer
+ * space.
+ */
+ while(glh->nfree < nseg && glh->nbusy > 0)
+ _glh_discard_line(glh, glh->list.head);
+/*
+ * If the buffer is smaller than the new line, don't attempt to truncate
+ * it to fit. Simply don't archive it.
+ */
+ if(glh->nfree < nseg)
+ return NULL;
+/*
+ * Record the line in the first 'nseg' segments of the list of unused segments.
+ */
+ offset = 0;
+ for(i=0,seg=glh->unused; i<nseg-1; i++,seg=seg->next, offset+=GLH_SEG_SIZE)
+ memcpy(seg->s, line + offset, GLH_SEG_SIZE);
+ memcpy(seg->s, line + offset, n-offset);
+ seg->s[n-offset] = '\0';
+/*
+ * Create a new hash-node for the line.
+ */
+ hnode = (GlhHashNode *) _new_FreeListNode(glh->hash.node_mem);
+ if(!hnode)
+ return NULL;
+/*
+ * Move the copy of the line from the list of unused segments to
+ * the hash node.
+ */
+ hnode->head = glh->unused;
+ glh->unused = seg->next;
+ seg->next = NULL;
+ glh->nbusy += nseg;
+ glh->nfree -= nseg;
+/*
+ * Prepend the new hash node to the list within the associated bucket.
+ */
+ hnode->next = bucket->lines;
+ bucket->lines = hnode;
+/*
+ * Initialize the rest of the members of the hash node.
+ */
+ hnode->len = n;
+ hnode->reported = 0;
+ hnode->used = 0;
+ hnode->bucket = bucket;
+ };
+/*
+ * Increment the reference count of the line.
+ */
+ hnode->used++;
+ return hnode;
+}
+
+/*.......................................................................
+ * Decrement the reference count of the history line of a given hash-node,
+ * and if the count reaches zero, delete both the hash-node and the
+ * buffered copy of the line.
+ *
+ * Input:
+ * glh GlHistory * The history container object.
+ * hnode GlhHashNode * The node to be removed.
+ * Output:
+ * return GlhHashNode * The deleted hash-node (ie. NULL).
+ */
+static GlhHashNode *_glh_discard_copy(GlHistory *glh, GlhHashNode *hnode)
+{
+ if(hnode) {
+ GlhHashBucket *bucket = hnode->bucket;
+/*
+ * If decrementing the reference count of the hash-node doesn't reduce
+ * the reference count to zero, then the line is still in use in another
+ * object, so don't delete it yet. Return NULL to indicate that the caller's
+ * access to the hash-node copy has been deleted.
+ */
+ if(--hnode->used >= 1)
+ return NULL;
+/*
+ * Remove the hash-node from the list in its parent bucket.
+ */
+ if(bucket->lines == hnode) {
+ bucket->lines = hnode->next;
+ } else {
+ GlhHashNode *prev; /* The node which precedes hnode in the bucket */
+ for(prev=bucket->lines; prev && prev->next != hnode; prev=prev->next)
+ ;
+ if(prev)
+ prev->next = hnode->next;
+ };
+ hnode->next = NULL;
+/*
+ * Return the line segments of the hash-node to the list of unused segments.
+ */
+ if(hnode->head) {
+ GlhLineSeg *tail; /* The last node in the list of line segments */
+ int nseg; /* The number of segments being discarded */
+/*
+ * Get the last node of the list of line segments referenced in the hash-node,
+ * while counting the number of line segments used.
+ */
+ for(nseg=1,tail=hnode->head; tail->next; nseg++,tail=tail->next)
+ ;
+/*
+ * Prepend the list of line segments used by the hash node to the
+ * list of unused line segments.
+ */
+ tail->next = glh->unused;
+ glh->unused = hnode->head;
+ glh->nbusy -= nseg;
+ glh->nfree += nseg;
+ };
+/*
+ * Return the container of the hash-node to the freelist.
+ */
+ hnode = (GlhHashNode *) _del_FreeListNode(glh->hash.node_mem, hnode);
+ };
+ return NULL;
+}
+
+/*.......................................................................
+ * Private function to locate the hash bucket associated with a given
+ * history line.
+ *
+ * This uses a hash-function described in the dragon-book
+ * ("Compilers - Principles, Techniques and Tools", by Aho, Sethi and
+ * Ullman; pub. Adison Wesley) page 435.
+ *
+ * Input:
+ * glh GlHistory * The history container object.
+ * line const char * The historical line to look up.
+ * n size_t The length of the line in line[], excluding
+ * any '\0' terminator.
+ * Output:
+ * return GlhHashBucket * The located hash-bucket.
+ */
+static GlhHashBucket *glh_find_bucket(GlHistory *glh, const char *line,
+ size_t n)
+{
+ unsigned long h = 0L;
+ int i;
+ for(i=0; i<n; i++) {
+ unsigned char c = line[i];
+ h = 65599UL * h + c; /* 65599 is a prime close to 2^16 */
+ };
+ return glh->hash.bucket + (h % GLH_HASH_SIZE);
+}
+
+/*.......................................................................
+ * Find a given history line within a given hash-table bucket.
+ *
+ * Input:
+ * bucket GlhHashBucket * The hash-table bucket in which to search.
+ * line const char * The historical line to lookup.
+ * n size_t The length of the line in line[], excluding
+ * any '\0' terminator.
+ * Output:
+ * return GlhHashNode * The hash-table entry of the line, or NULL
+ * if not found.
+ */
+static GlhHashNode *glh_find_hash_node(GlhHashBucket *bucket, const char *line,
+ size_t n)
+{
+ GlhHashNode *node; /* A node in the list of lines in the bucket */
+/*
+ * Compare each of the lines in the list of lines, against 'line'.
+ */
+ for(node=bucket->lines; node; node=node->next) {
+ if(_glh_is_line(node, line, n))
+ return node;
+ };
+ return NULL;
+}
+
+/*.......................................................................
+ * Return non-zero if a given string is equal to a given segmented line
+ * node.
+ *
+ * Input:
+ * hash GlhHashNode * The hash-table entry of the line.
+ * line const char * The string to be compared to the segmented
+ * line.
+ * n size_t The length of the line in line[], excluding
+ * any '\0' terminator.
+ * Output:
+ * return int 0 - The lines differ.
+ * 1 - The lines are the same.
+ */
+static int _glh_is_line(GlhHashNode *hash, const char *line, size_t n)
+{
+ GlhLineSeg *seg; /* A node in the list of line segments */
+ int i;
+/*
+ * Do the two lines have the same length?
+ */
+ if(n != hash->len)
+ return 0;
+/*
+ * Compare the characters of the segmented and unsegmented versions
+ * of the line.
+ */
+ for(seg=hash->head; n>0 && seg; seg=seg->next) {
+ const char *s = seg->s;
+ for(i=0; n>0 && i<GLH_SEG_SIZE; i++,n--) {
+ if(*line++ != *s++)
+ return 0;
+ };
+ };
+ return 1;
+}
+
+/*.......................................................................
+ * Return non-zero if a given line has the specified segmented search
+ * prefix.
+ *
+ * Input:
+ * line GlhHashNode * The line to be compared against the prefix.
+ * prefix GlhHashNode * The search prefix, or NULL to match any string.
+ * Output:
+ * return int 0 - The line doesn't have the specified prefix.
+ * 1 - The line has the specified prefix.
+ */
+static int _glh_line_matches_prefix(GlhHashNode *line, GlhHashNode *prefix)
+{
+ GlhLineStream lstr; /* The stream that is used to traverse 'line' */
+ GlhLineStream pstr; /* The stream that is used to traverse 'prefix' */
+/*
+ * When prefix==NULL, this means that the nul string
+ * is to be matched, and this matches all lines.
+ */
+ if(!prefix)
+ return 1;
+/*
+ * Wrap the two history lines that are to be compared in iterator
+ * stream objects.
+ */
+ glh_init_stream(&lstr, line);
+ glh_init_stream(&pstr, prefix);
+/*
+ * If the prefix contains a glob pattern, match the prefix as a glob
+ * pattern.
+ */
+ if(glh_contains_glob(prefix))
+ return glh_line_matches_glob(&lstr, &pstr);
+/*
+ * Is the prefix longer than the line being compared against it?
+ */
+ if(prefix->len > line->len)
+ return 0;
+/*
+ * Compare the line to the prefix.
+ */
+ while(pstr.c != '\0' && pstr.c == lstr.c) {
+ glh_step_stream(&lstr);
+ glh_step_stream(&pstr);
+ };
+/*
+ * Did we reach the end of the prefix string before finding
+ * any differences?
+ */
+ return pstr.c == '\0';
+}
+
+/*.......................................................................
+ * Copy a given history line into a specified output string.
+ *
+ * Input:
+ * hash GlhHashNode The hash-table entry of the history line to
+ * be copied.
+ * line char * A copy of the history line.
+ * dim size_t The allocated dimension of the line buffer.
+ */
+static void _glh_return_line(GlhHashNode *hash, char *line, size_t dim)
+{
+ GlhLineSeg *seg; /* A node in the list of line segments */
+ int i;
+ for(seg=hash->head; dim>0 && seg; seg=seg->next) {
+ const char *s = seg->s;
+ for(i=0; dim>0 && i<GLH_SEG_SIZE; i++,dim--)
+ *line++ = *s++;
+ };
+/*
+ * If the line wouldn't fit in the output buffer, replace the last character
+ * with a '\0' terminator.
+ */
+ if(dim==0)
+ line[-1] = '\0';
+}
+
+/*.......................................................................
+ * This function should be called whenever a new line recall is
+ * attempted. It preserves a copy of the current input line in the
+ * history list while other lines in the history list are being
+ * returned.
+ *
+ * Input:
+ * glh GlHistory * The input-line history maintenance object.
+ * line char * The current contents of the input line buffer.
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+static int _glh_prepare_for_recall(GlHistory *glh, char *line)
+{
+/*
+ * If a recall session has already been started, but we have returned
+ * to the preserved copy of the input line, if the user has changed
+ * this line, we should replace the preserved copy of the original
+ * input line with the new one. To do this simply cancel the session,
+ * so that a new session is started below.
+ */
+ if(glh->recall && glh->recall == glh->list.tail &&
+ !_glh_is_line(glh->recall->line, line, strlen(line))) {
+ _glh_cancel_search(glh);
+ };
+/*
+ * If this is the first line recall of a new recall session, save the
+ * current line for potential recall later, and mark it as the last
+ * line recalled.
+ */
+ if(!glh->recall) {
+ if(_glh_add_history(glh, line, 1))
+ return 1;
+ glh->recall = glh->list.tail;
+/*
+ * The above call to _glh_add_history() will have incremented the line
+ * sequence number, after adding the line. Since we only want this to
+ * to be incremented for permanently entered lines, decrement it again.
+ */
+ glh->seq--;
+ };
+ return 0;
+}
+
+/*.......................................................................
+ * Return non-zero if a history search session is currently in progress.
+ *
+ * Input:
+ * glh GlHistory * The input-line history maintenance object.
+ * Output:
+ * return int 0 - No search is currently in progress.
+ * 1 - A search is in progress.
+ */
+int _glh_search_active(GlHistory *glh)
+{
+ return glh && glh->recall;
+}
+
+/*.......................................................................
+ * Initialize a character iterator object to point to the start of a
+ * given history line. The first character of the line will be placed
+ * in str->c, and subsequent characters can be placed there by calling
+ * glh_strep_stream().
+ *
+ * Input:
+ * str GlhLineStream * The iterator object to be initialized.
+ * line GlhHashNode * The history line to be iterated over (a
+ * NULL value here, is interpretted as an
+ * empty string by glh_step_stream()).
+ */
+static void glh_init_stream(GlhLineStream *str, GlhHashNode *line)
+{
+ str->seg = line ? line->head : NULL;
+ str->posn = 0;
+ str->c = str->seg ? str->seg->s[0] : '\0';
+}
+
+/*.......................................................................
+ * Copy the next unread character in the line being iterated, in str->c.
+ * Once the end of the history line has been reached, all futher calls
+ * set str->c to '\0'.
+ *
+ * Input:
+ * str GlhLineStream * The history-line iterator to read from.
+ */
+static void glh_step_stream(GlhLineStream *str)
+{
+/*
+ * Get the character from the current iterator position within the line.
+ */
+ str->c = str->seg ? str->seg->s[str->posn] : '\0';
+/*
+ * Unless we have reached the end of the string, move the iterator
+ * to the position of the next character in the line.
+ */
+ if(str->c != '\0' && ++str->posn >= GLH_SEG_SIZE) {
+ str->posn = 0;
+ str->seg = str->seg->next;
+ };
+}
+
+/*.......................................................................
+ * Return non-zero if the specified search prefix contains any glob
+ * wildcard characters.
+ *
+ * Input:
+ * prefix GlhHashNode * The search prefix.
+ * Output:
+ * return int 0 - The prefix doesn't contain any globbing
+ * characters.
+ * 1 - The prefix contains at least one
+ * globbing character.
+ */
+static int glh_contains_glob(GlhHashNode *prefix)
+{
+ GlhLineStream pstr; /* The stream that is used to traverse 'prefix' */
+/*
+ * Wrap a stream iterator around the prefix, so that we can traverse it
+ * without worrying about line-segmentation.
+ */
+ glh_init_stream(&pstr, prefix);
+/*
+ * Search for unescaped wildcard characters.
+ */
+ while(pstr.c != '\0') {
+ switch(pstr.c) {
+ case '\\': /* Skip escaped characters */
+ glh_step_stream(&pstr);
+ break;
+ case '*': case '?': case '[': /* A wildcard character? */
+ return 1;
+ break;
+ };
+ glh_step_stream(&pstr);
+ };
+/*
+ * No wildcard characters were found.
+ */
+ return 0;
+}
+
+/*.......................................................................
+ * Return non-zero if the history line matches a search prefix containing
+ * a glob pattern.
+ *
+ * Input:
+ * lstr GlhLineStream * The iterator stream being used to traverse
+ * the history line that is being matched.
+ * pstr GlhLineStream * The iterator stream being used to traverse
+ * the pattern.
+ * Output:
+ * return int 0 - Doesn't match.
+ * 1 - The line matches the pattern.
+ */
+static int glh_line_matches_glob(GlhLineStream *lstr, GlhLineStream *pstr)
+{
+/*
+ * Match each character of the pattern until we reach the end of the
+ * pattern.
+ */
+ while(pstr->c != '\0') {
+/*
+ * Handle the next character of the pattern.
+ */
+ switch(pstr->c) {
+/*
+ * A match zero-or-more characters wildcard operator.
+ */
+ case '*':
+/*
+ * Skip the '*' character in the pattern.
+ */
+ glh_step_stream(pstr);
+/*
+ * If the pattern ends with the '*' wildcard, then the
+ * rest of the line matches this.
+ */
+ if(pstr->c == '\0')
+ return 1;
+/*
+ * Using the wildcard to match successively longer sections of
+ * the remaining characters of the line, attempt to match
+ * the tail of the line against the tail of the pattern.
+ */
+ while(lstr->c) {
+ GlhLineStream old_lstr = *lstr;
+ GlhLineStream old_pstr = *pstr;
+ if(glh_line_matches_glob(lstr, pstr))
+ return 1;
+/*
+ * Restore the line and pattern iterators for a new try.
+ */
+ *lstr = old_lstr;
+ *pstr = old_pstr;
+/*
+ * Prepare to try again, one character further into the line.
+ */
+ glh_step_stream(lstr);
+ };
+ return 0; /* The pattern following the '*' didn't match */
+ break;
+/*
+ * A match-one-character wildcard operator.
+ */
+ case '?':
+/*
+ * If there is a character to be matched, skip it and advance the
+ * pattern pointer.
+ */
+ if(lstr->c) {
+ glh_step_stream(lstr);
+ glh_step_stream(pstr);
+/*
+ * If we hit the end of the line, there is no character
+ * matching the operator, so the pattern doesn't match.
+ */
+ } else {
+ return 0;
+ };
+ break;
+/*
+ * A character range operator, with the character ranges enclosed
+ * in matching square brackets.
+ */
+ case '[':
+ glh_step_stream(pstr); /* Skip the '[' character */
+ if(!lstr->c || !glh_matches_range(lstr->c, pstr))
+ return 0;
+ glh_step_stream(lstr); /* Skip the character that matched */
+ break;
+/*
+ * A backslash in the pattern prevents the following character as
+ * being seen as a special character.
+ */
+ case '\\':
+ glh_step_stream(pstr); /* Skip the backslash */
+ /* Note fallthrough to default */
+/*
+ * A normal character to be matched explicitly.
+ */
+ default:
+ if(lstr->c == pstr->c) {
+ glh_step_stream(lstr);
+ glh_step_stream(pstr);
+ } else {
+ return 0;
+ };
+ break;
+ };
+ };
+/*
+ * To get here, pattern must have been exhausted. The line only
+ * matches the pattern if the line as also been exhausted.
+ */
+ return pstr->c == '\0' && lstr->c == '\0';
+}
+
+/*.......................................................................
+ * Match a character range expression terminated by an unescaped close
+ * square bracket.
+ *
+ * Input:
+ * c char The character to be matched with the range
+ * pattern.
+ * pstr GlhLineStream * The iterator stream being used to traverse
+ * the pattern.
+ * Output:
+ * return int 0 - Doesn't match.
+ * 1 - The character matched.
+ */
+static int glh_matches_range(char c, GlhLineStream *pstr)
+{
+ int invert = 0; /* True to invert the sense of the match */
+ int matched = 0; /* True if the character matched the pattern */
+ char lastc = '\0'; /* The previous character in the pattern */
+/*
+ * If the first character is a caret, the sense of the match is
+ * inverted and only if the character isn't one of those in the
+ * range, do we say that it matches.
+ */
+ if(pstr->c == '^') {
+ glh_step_stream(pstr);
+ invert = 1;
+ };
+/*
+ * The hyphen is only a special character when it follows the first
+ * character of the range (not including the caret).
+ */
+ if(pstr->c == '-') {
+ glh_step_stream(pstr);
+ if(c == '-')
+ matched = 1;
+/*
+ * Skip other leading '-' characters since they make no sense.
+ */
+ while(pstr->c == '-')
+ glh_step_stream(pstr);
+ };
+/*
+ * The hyphen is only a special character when it follows the first
+ * character of the range (not including the caret or a hyphen).
+ */
+ if(pstr->c == ']') {
+ glh_step_stream(pstr);
+ if(c == ']')
+ matched = 1;
+ };
+/*
+ * Having dealt with the characters that have special meanings at
+ * the beginning of a character range expression, see if the
+ * character matches any of the remaining characters of the range,
+ * up until a terminating ']' character is seen.
+ */
+ while(!matched && pstr->c && pstr->c != ']') {
+/*
+ * Is this a range of characters signaled by the two end characters
+ * separated by a hyphen?
+ */
+ if(pstr->c == '-') {
+ glh_step_stream(pstr); /* Skip the hyphen */
+ if(pstr->c != ']') {
+ if(c >= lastc && c <= pstr->c)
+ matched = 1;
+ };
+/*
+ * A normal character to be compared directly.
+ */
+ } else if(pstr->c == c) {
+ matched = 1;
+ };
+/*
+ * Record and skip the character that we just processed.
+ */
+ lastc = pstr->c;
+ if(pstr->c != ']')
+ glh_step_stream(pstr);
+ };
+/*
+ * Find the terminating ']'.
+ */
+ while(pstr->c && pstr->c != ']')
+ glh_step_stream(pstr);
+/*
+ * Did we find a terminating ']'?
+ */
+ if(pstr->c == ']') {
+/*
+ * Skip the terminating ']'.
+ */
+ glh_step_stream(pstr);
+/*
+ * If the pattern started with a caret, invert the sense of the match.
+ */
+ if(invert)
+ matched = !matched;
+/*
+ * If the pattern didn't end with a ']', then it doesn't match,
+ * regardless of the value of the required sense of the match.
+ */
+ } else {
+ matched = 0;
+ };
+ return matched;
+}
+
diff --git a/libtecla-1.4.1/history.h b/libtecla-1.6.1/history.h
index 49671a4..d32ee8f 100644
--- a/libtecla-1.4.1/history.h
+++ b/libtecla-1.6.1/history.h
@@ -2,7 +2,7 @@
#define history_h
/*
- * Copyright (c) 2000, 2001 by Martin C. Shepherd.
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
*
* All rights reserved.
*
@@ -32,7 +32,7 @@
* of the copyright holder.
*/
-#include <stdio.h> /* FILE * */
+#include <stdio.h> /* FILE * */
/*-----------------------------------------------------------------------
* This module is used to record and traverse historical lines of user input.
@@ -106,8 +106,8 @@ int _glh_get_group(GlHistory *glh);
* Display the contents of the history list to the specified stdio
* output group.
*/
-int _glh_show_history(GlHistory *glh, FILE *fp, const char *fmt,
- int all_groups, int max_lines);
+int _glh_show_history(GlHistory *glh, GlWriteFn *write_fn, void *data,
+ const char *fmt, int all_groups, int max_lines);
/*
* Change the size of the history buffer.
@@ -156,4 +156,14 @@ void _glh_range_of_history(GlHistory *glh, unsigned long *oldest,
*/
void _glh_size_of_history(GlHistory *glh, size_t *buff_size, size_t *buff_used);
+/*
+ * Get information about the last error in this module.
+ */
+const char *_glh_last_error(GlHistory *glh);
+
+/*
+ * Return non-zero if a history search session is currently in progress.
+ */
+int _glh_search_active(GlHistory *glh);
+
#endif
diff --git a/libtecla-1.4.1/homedir.c b/libtecla-1.6.1/homedir.c
index f2029b7..eb666c3 100644
--- a/libtecla-1.4.1/homedir.c
+++ b/libtecla-1.6.1/homedir.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2001 by Martin C. Shepherd.
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
*
* All rights reserved.
*
@@ -29,6 +29,12 @@
* of the copyright holder.
*/
+/*
+ * If file-system access is to be excluded, this module has no function,
+ * so all of its code should be excluded.
+ */
+#ifndef WITHOUT_FILE_SYSTEM
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -41,20 +47,21 @@
#include "pathutil.h"
#include "homedir.h"
-
-/*
- * Set the max length of the error-reporting string. There is no point
- * in this being longer than the width of a typical terminal window.
- * In composing error messages, I have assumed that this number is
- * at least 80, so you don't decrease it below this number.
- */
-#define ERRLEN 200
+#include "errmsg.h"
/*
* Use the reentrant POSIX threads versions of the password lookup functions?
*/
-#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199506L
+#if defined(PREFER_REENTRANT) && defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199506L
#define THREAD_COMPATIBLE 1
+/*
+ * Under Solaris we can use thr_main() to determine whether
+ * threads are actually running, and thus when it is necessary
+ * to avoid non-reentrant features.
+ */
+#if defined __sun && defined __SVR4
+#include <thread.h> /* Solaris thr_main() */
+#endif
#endif
/*
@@ -68,12 +75,12 @@
* maintained in objects of the following type.
*/
struct HomeDir {
- char errmsg[ERRLEN+1]; /* Error-report buffer */
- char *buffer; /* A buffer for reading password entries and */
- /* directory paths. */
- int buflen; /* The allocated size of buffer[] */
+ ErrMsg *err; /* The error message report buffer */
+ char *buffer; /* A buffer for reading password entries and */
+ /* directory paths. */
+ int buflen; /* The allocated size of buffer[] */
#ifdef THREAD_COMPATIBLE
- struct passwd pwd; /* The password entry of a user */
+ struct passwd pwd; /* The password entry of a user */
#endif
};
@@ -94,7 +101,7 @@ HomeDir *_new_HomeDir(void)
*/
home = (HomeDir *) malloc(sizeof(HomeDir));
if(!home) {
- fprintf(stderr, "_new_HomeDir: Insufficient memory.\n");
+ errno = ENOMEM;
return NULL;
};
/*
@@ -102,10 +109,16 @@ HomeDir *_new_HomeDir(void)
* container at least up to the point at which it can safely be passed
* to _del_HomeDir().
*/
- home->errmsg[0] = '\0';
+ home->err = NULL;
home->buffer = NULL;
home->buflen = 0;
/*
+ * Allocate a place to record error messages.
+ */
+ home->err = _new_ErrMsg();
+ if(!home->err)
+ return _del_HomeDir(home);
+/*
* Allocate the buffer that is used by the reentrant POSIX password-entry
* lookup functions.
*/
@@ -138,7 +151,7 @@ HomeDir *_new_HomeDir(void)
*/
home->buffer = (char *) malloc(home->buflen);
if(!home->buffer) {
- fprintf(stderr, "_new_HomeDir: Insufficient memory.");
+ errno = ENOMEM;
return _del_HomeDir(home);
};
return home;
@@ -155,6 +168,7 @@ HomeDir *_new_HomeDir(void)
HomeDir *_del_HomeDir(HomeDir *home)
{
if(home) {
+ home->err = _del_ErrMsg(home->err);
if(home->buffer)
free(home->buffer);
free(home);
@@ -200,23 +214,32 @@ const char *_hd_lookup_home_dir(HomeDir *home, const char *user)
* Check the arguments.
*/
if(!home) {
- fprintf(stderr, "_hd_lookup_home_dir: NULL argument(s).\n");
+ errno = EINVAL;
return NULL;
};
/*
* Handle the ksh "~+". This expands to the absolute path of the
* current working directory.
*/
- if (!login_user && strcmp(user, "+") == 0) {
+ if(!login_user && strcmp(user, "+") == 0) {
home_dir = hd_getpwd(home);
if(!home_dir) {
- strncpy(home->errmsg, "Cannot determine current directory.", ERRLEN);
- home->errmsg[ERRLEN] = '\0';
+ _err_record_msg(home->err, "Can't determine current directory",
+ END_ERR_MSG);
return NULL;
}
return home_dir;
};
/*
+ * When looking up the home directory of the current user, see if the
+ * HOME environment variable is set, and if so, return its value.
+ */
+ if(login_user) {
+ home_dir = getenv("HOME");
+ if(home_dir)
+ return home_dir;
+ };
+/*
* Look up the password entry of the user.
* First the POSIX threads version - this is painful!
*/
@@ -233,8 +256,8 @@ const char *_hd_lookup_home_dir(HomeDir *home, const char *user)
else
status = getpwnam_r(user, &home->pwd, home->buffer, home->buflen, &ret);
if(status || !ret) {
- const char *fmt = "User '%.*s' doesn't exist.";
- sprintf(home->errmsg, fmt, ERRLEN - strlen(fmt), user);
+ _err_record_msg(home->err, "User '", user, "' doesn't exist.",
+ END_ERR_MSG);
return NULL;
};
/*
@@ -249,8 +272,8 @@ const char *_hd_lookup_home_dir(HomeDir *home, const char *user)
{
struct passwd *pwd = login_user ? getpwuid(geteuid()) : getpwnam(user);
if(!pwd) {
- const char *fmt = "User '%.*s' doesn't exist.";
- sprintf(home->errmsg, fmt, ERRLEN - strlen(fmt), user);
+ _err_record_msg(home->err, "User '", user, "' doesn't exist.",
+ END_ERR_MSG);
return NULL;
};
/*
@@ -273,7 +296,7 @@ const char *_hd_lookup_home_dir(HomeDir *home, const char *user)
*/
const char *_hd_last_home_dir_error(HomeDir *home)
{
- return home ? home->errmsg : "NULL HomeDir argument";
+ return home ? _err_get_msg(home->err) : "NULL HomeDir argument";
}
/*.......................................................................
@@ -284,6 +307,10 @@ const char *_hd_last_home_dir_error(HomeDir *home)
* Input:
* home HomeDir * The resource object for reading home
* directories.
+ * prefix const char * Only information for usernames that
+ * start with this prefix will be
+ * returned. Note that the empty
+ & string "", matches all usernames.
* data void * Anonymous data to be passed to the
* callback function.
* callback_fn HOME_DIR_FN(*) The function to call for each user.
@@ -293,24 +320,64 @@ const char *_hd_last_home_dir_error(HomeDir *home)
* of the error can be obtained by
* calling _hd_last_home_dir_error().
*/
-int _hd_scan_user_home_dirs(HomeDir *home, void *data, HOME_DIR_FN(*callback_fn))
+int _hd_scan_user_home_dirs(HomeDir *home, const char *prefix,
+ void *data, HOME_DIR_FN(*callback_fn))
{
int waserr = 0; /* True after errors */
+ int prefix_len; /* The length of prefix[] */
/*
* Check the arguments.
*/
- if(!home || !callback_fn) {
- if(home)
- strcpy(home->errmsg,
- "_hd_scan_user_home_dirs: Missing callback function");
+ if(!home || !prefix || !callback_fn) {
+ if(home) {
+ _err_record_msg(home->err,
+ "_hd_scan_user_home_dirs: Missing callback function",
+ END_ERR_MSG);
+ };
return 1;
};
/*
+ * Get the length of the username prefix.
+ */
+ prefix_len = strlen(prefix);
+/*
* There are no reentrant versions of getpwent() etc for scanning
* the password file, so disable username completion when the
* library is compiled to be reentrant.
*/
-#if !defined(_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 199506L
+#if defined(PREFER_REENTRANT) && defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199506L
+#if defined __sun && defined __SVR4
+ if(thr_main() >= 0) /* thread library is linked in */
+#else
+ if(1)
+#endif
+ {
+ struct passwd pwd_buffer; /* A returned password entry */
+ struct passwd *pwd; /* A pointer to pwd_buffer */
+ char buffer[512]; /* The buffer in which the string members of */
+ /* pwd_buffer are stored. */
+/*
+ * See if the prefix that is being completed is a complete username.
+ */
+ if(!waserr && getpwnam_r(prefix, &pwd_buffer, buffer, sizeof(buffer),
+ &pwd) == 0 && pwd != NULL) {
+ waserr = callback_fn(data, pwd->pw_name, pwd->pw_dir,
+ _err_get_msg(home->err), ERR_MSG_LEN);
+ };
+/*
+ * See if the username of the current user minimally matches the prefix.
+ */
+ if(!waserr && getpwuid_r(getuid(), &pwd_buffer, buffer, sizeof(buffer),
+ &pwd) == 0 && pwd != NULL &&
+ strncmp(prefix, pwd->pw_name, prefix_len)==0) {
+ waserr = callback_fn(data, pwd->pw_name, pwd->pw_dir,
+ _err_get_msg(home->err), ERR_MSG_LEN);
+ };
+/*
+ * Reentrancy not required?
+ */
+ } else
+#endif
{
struct passwd *pwd; /* The pointer to the latest password entry */
/*
@@ -322,27 +389,29 @@ int _hd_scan_user_home_dirs(HomeDir *home, void *data, HOME_DIR_FN(*callback_fn)
* that start with the specified prefix, and adding them to the
* list of matches.
*/
- while((pwd = getpwent()) != NULL && !waserr)
- waserr = callback_fn(data, pwd->pw_name, pwd->pw_dir, home->errmsg,
- ERRLEN);
+ while((pwd = getpwent()) != NULL && !waserr) {
+ if(strncmp(prefix, pwd->pw_name, prefix_len) == 0) {
+ waserr = callback_fn(data, pwd->pw_name, pwd->pw_dir,
+ _err_get_msg(home->err), ERR_MSG_LEN);
+ };
+ };
/*
* Close the password file.
*/
endpwent();
};
-#endif
/*
* Under ksh ~+ stands for the absolute pathname of the current working
* directory.
*/
- if (!waserr) {
+ if(!waserr && strncmp(prefix, "+", prefix_len) == 0) {
const char *pwd = hd_getpwd(home);
if(pwd) {
- waserr = callback_fn(data, "+", pwd, home->errmsg, ERRLEN);
+ waserr = callback_fn(data, "+", pwd, _err_get_msg(home->err),ERR_MSG_LEN);
} else {
waserr = 1;
- strncpy(home->errmsg, "Cannot determine current directory.", ERRLEN);
- home->errmsg[ERRLEN] = '\0';
+ _err_record_msg(home->err, "Can't determine current directory.",
+ END_ERR_MSG);
};
};
return waserr;
@@ -397,3 +466,5 @@ static const char *hd_getpwd(HomeDir *home)
*/
return cwd;
}
+
+#endif /* ifndef WITHOUT_FILE_SYSTEM */
diff --git a/libtecla-1.4.1/homedir.h b/libtecla-1.6.1/homedir.h
index 5607802..0ad3e94 100644
--- a/libtecla-1.4.1/homedir.h
+++ b/libtecla-1.6.1/homedir.h
@@ -2,7 +2,7 @@
#define homedir_h
/*
- * Copyright (c) 2000, 2001 by Martin C. Shepherd.
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
*
* All rights reserved.
*
@@ -75,7 +75,7 @@ const char *_hd_last_home_dir_error(HomeDir *home);
*/
#define HOME_DIR_FN(fn) int (fn)(void *data, const char *usrnam, const char *homedir, char *errmsg, int maxerr)
-int _hd_scan_user_home_dirs(HomeDir *home, void *data,
+int _hd_scan_user_home_dirs(HomeDir *home, const char *prefix, void *data,
HOME_DIR_FN(*callback_fn));
#endif
diff --git a/libtecla-1.4.1/html/changes.html b/libtecla-1.6.1/html/changes.html
index b309a7b..9be5251 100644
--- a/libtecla-1.4.1/html/changes.html
+++ b/libtecla-1.6.1/html/changes.html
@@ -1,9 +1,1260 @@
-<HEAD><TITLE>The tecla library change log</TITLE></HEAD>
-<BODY bgcolor=add8e6><PRE>
+<html><head><title>The tecla library change log</title></head>
+<body bgcolor="#add8e6"><pre>
In the following log, modification dates are listed using the European
convention in which the day comes before the month (ie. DD/MM/YYYY).
The most recent modifications are listed first.
+31/10/2004 mcs@astro.caltech.edu (problem reported by Godfrey van der Linden)
+ getline.c
+ The gl_event_handler() function had the endif of a
+ conditional compilation clause in the wrong place. This
+ only upset the compiler on unusual systems that don't
+ have select(). The problem was seen under Mac OS X, due
+ to the configuration problem in 1.6.0 that caused the
+ configure script to mistakenly report that select wasn't
+ available.
+
+31/10/2004 mcs@astro.caltech.edu (info provided by Ivan Rayner)
+ configure.in configure Makefile.in
+ Ivan reported that under IRIX 6.5 it is necessary to add
+ -D_XOPEN_SOURCE=500 to the compiler flags, when compiling
+ the reentrant version of the library. Thus, whereas
+ previously I hardwired the value of DEFINES_R in
+ Makefile.in, I have now made this a variable in the
+ configure script, which is augmented with the above
+ addition, within an IRIX-specific switch clause.
+
+ Also apparently configure leaves the RANLIB variable
+ blank, instead of setting it to ":", so I have now
+ explicitly set this to ":", within the new IRIX clause of
+ the configure script.
+
+31/10/2004 mcs@astro.caltech.edu (info provided by Ivan Rayner)
+ getline.c
+ Under IRIX, the compiler warned that gl_read_unmasked()
+ was returning an int, which was then being assigned to an
+ enumeration type. This is techically fine, but it
+ highlighted the fact that I had meant to declare
+ gl_read_unmasked() to directly return the enumerated
+ type. I have now done so.
+
+26/09/2004 mcs@astro.caltech.edu
+ getline.c
+ Users can now turn off interactive command-line editing
+ by setting the TERM environment variable to the word "dumb".
+
+18/07/2004 mcs@astro.caltech.edu (problem noted by Michael MacFaden)
+ getline.c
+ Calling gl_terminal_size() on a system without support
+ for SIGWINCH caused a divide-by-zero error in an unintended
+ call to gl_erase_line(), because gl_update_size() was
+ incorrectly being called to query the terminal size,
+ instead of gl_query_size().
+
+18/07/2004 Padraig Brady (documented here by mcs@astro.caltech.edu)
+ getline.c
+ The suspend and termination signal-handlers installed by
+ gl_tty_signals(), were being installed swapped.
+
+03/06/2004 Mike Meaney (documented here by mcs@astro.caltech.edu)
+ getline.c
+ Mike pointed out the fact that the curses setupterm()
+ function is actually documented to exit the application
+ if an error occurs while its optional errret argument is
+ NULL. I hadn't noticed this, and because I didn't need
+ the extra information returned in the errret argument, I
+ was passing it a NULL. As suggested by Mike, I now pass
+ this argument a pointer to a dummy errret variable.
+
+23/05/2004 mcs@astro.caltech.edu (problem noted by John Beck)
+ man/func/cpl_complete_word.in
+ Some of the prototypes of functions and types documented
+ by the cpl_complete_word man page, weren't listed in the
+ Synopsis section of this man page. They are now listed
+ there.
+
+23/05/2004 mcs@astro.caltech.edu
+ getline.c man/func/gl_get_line.in
+ I have now added support for calling gl_normal_io() from
+ any callback functions that the application installs by
+ calling either gl_inactivity_timeout(), or gl_watch_fd().
+ Previously, if one of these callback functions called
+ gl_normal_io(), then after returning to gl_get_line(),
+ gl_get_line() would incorrectly assume that the terminal
+ was still in raw I/O mode. Now, gl_get_line() checks to
+ see if gl_normal_io() was called by the callback, and
+ if so, calls _gl_raw_io() to reinstate raw I/O mode.
+
+21/05/2004 mcs@astro.caltech.edu
+ configure.in configure
+ On Mac OS X the code that the configure script used to
+ check for select() failed due to missing symbols in
+ sys/select.h. Moving the inclusion of sys/select.h to
+ after the inclusion of sys/time.h, sys/types.h and
+ sys/unistd.h fixed this.
+
+11/05/2004 mcs@astro.caltech.edu
+ getline.c man/func/gl_get_line.in
+ If the line buffer returned by one call to gl_get_line()
+ was passed as the start_line argument of the next call to
+ gl_get_line(), then instead of the just-entered line
+ being presented back to the user for further editing, the
+ start_line argument was effectively ignored, because the
+ line buffer whose pointer was being passed back, was
+ being cleared before the start_line pointer was examined.
+ This appears to have been a case of me incorrectly
+ thinking that I had forgotten to initialize gl-&gt;line[]
+ and gl-&gt;ntotal in the gl_reset_input_line() function, and
+ then "fixing" this supposed omission. Removing this
+ erroneous fix, restored things to how they were meant to
+ be. To make it unlikely that I will make the same mistake
+ again, I have renamed the function from
+ gl_reset_input_line() to gl_reset_editor(), to stop it
+ looking as though it is meant to reset the contents of
+ the input line (that is what gl_truncate_buffer() is
+ for), explicitly stated that it doesn't clear the input
+ line, in the header comments of the function, and added a
+ prominent warning comment in the body of the function.
+
+ Also, since support for passing back the returned line
+ pointer via the start_line argument of the next call to
+ gl_get_line(), wasn't documented in the man page, but was
+ meant to be supported, and definitely used to work, I
+ have now amended the man page documentation of
+ gl_get_line() to explicitly state that this feature is
+ officially supported.
+
+2?/04/2004 Released 1.6.0
+
+22/04/2004 mcs@astro.caltech.edu (Fixed a bug reported by John Beck)
+ getline.c
+ When an error, signal, or other abnormal event aborted
+ gl_get_line(), the cleanup code that restored the
+ terminal to a sane state, also overwrote the value of
+ errno that was associated with the aborting event. An
+ I/O error occurring in the cleanup code would have also
+ overwritten the value to be returned by
+ gl_return_status(), and thus remove any possibility of
+ the caller finding out what really caused gl_get_line()
+ to abort. I have now written a new internal function
+ called, gl_record_status(), which records the completion
+ status to be returned by gl_return_status(), and the
+ value to assign to errno just before gl_get_line()
+ returns. This is called wherever code detects conditions
+ that require gl_get_line() to return early. The function
+ ensures that once an abnormal completion status has been
+ recorded for return, subsequent completions statuses
+ aren't recorded. This ensures that the caller sees the
+ original cause of the abnormal return, rather than any
+ error that occurs during cleaning up from this before
+ return.
+
+17/04/2004 mcs@astro.caltech.edu
+ getline.c
+ If an application's callback called gl_read_char() after
+ calling gl_normal_io(), it would inappropriately
+ redisplay the input line, when it called _gl_raw_io() to
+ temporarily switch the terminal back into raw mode.
+
+ To fix this, _gl_raw_io() now takes a new 'redisplay'
+ argument, which specifies whether or not to queue a
+ redisplay of the input line. I also created a new
+ gl-&gt;postpone flag, which is set by gl_normal_io(), and
+ cleared by _gl_raw_io() (when its redisplay argument is
+ true). When this flag is set, gl_flush_output() ignores
+ queued redisplays, as it generally should between calls
+ to gl_normal_io() and gl_raw_io(). Thus its effect is to
+ postpone redisplays while line editing is suspended.
+
+11/04/2004 mcs@astro.caltech.edu
+ history.c man/misc/tecla.in
+ History searches can now include the globbing operators
+ *, ?, []. When a search prefix is found to have at least
+ one of these characters, then only history lines that
+ completely match that pattern are returned.
+
+11/04/2004 mcs@astro.caltech.edu (issue raised by Mark Coiley)
+ getline.c ioutil.c
+ There appears to be a bug in Solaris's terminal I/O.
+ When the terminal file descriptor is placed in
+ non-blocking I/O mode, and the terminal is switched from
+ canonical to raw mode, characters that were previously
+ entered in canonical I/O mode don't become available to
+ be read until the user types one character more. Select()
+ incorrectly says that there are no characters available,
+ and read() returns EAGAIN. This is only a problem for
+ gl_get_line() when gl_get_line() is in non-blocking
+ server I/O mode, so most users won't have experienced any
+ problems with this.
+
+ The only way that I have found to get read() to return
+ the characters, without the user first having to type
+ another character, is to turn off non-blocking I/O before
+ calling read(). Select() still claims that there are no
+ characters available to be read, but read happily returns
+ them anyway. Fortunately, one can perform non-blocking
+ terminal reads without setting the non-blocking I/O flag
+ of the file descriptor, simply by setting the VTIME
+ terminal attribute to zero (which I already was
+ doing). Thus, when in non-blocking server I/O, I now turn
+ off the non-blocking I/O flag, attempt to read one
+ character and only if this fails, do I then call the
+ select() based event handler to implement any configured
+ non-zero timeout, before attempting the read again. Of
+ course the non-blocking I/O flag is still needed for
+ writing, so I only turn it off temporarily while reading.
+
+25/03/2004 mcs@astro.caltech.edu (bug reported by Gregory Harris)
+ Makefile.in
+ It appears that when in February, I patched Makefile.in
+ to add abolute paths to the install-sh shell-script,
+ I accidentally replaced install-sh with install.sh. I
+ corrected the name in the Makefile.
+
+25/03/2004 Gregory Harris (documented here by mcs)
+ configure.in configure
+ Greg added the configuration parameters needed to build
+ the shared version of the libtecla library under FreeBSD.
+
+25/03/2004 mcs@astro.caltech.edu
+ getline.c libtecla.h libtecla.map man/func/gl_get_line.in
+ man/func/gl_read_char.in
+ I wrote a public function called gl_read_char(). Unlike
+ gl_query_char(), this function neither prompts the user
+ for input, nor displays the character that was entered.
+ In fact it doesn't write anything to the terminal, and
+ takes pains not to disturb any incompletely entered
+ input line, and can safely be called from application
+ callback functions.
+
+21/03/2004 mcs@astro.caltech.edu
+ getline.c libtecla.h libtecla.map man/func/gl_get_line.in
+ man/func/gl_query_char.in
+ I wrote a public function called gl_query_char(), which
+ prompts the user and awaits a single-character reply,
+ without the user having to hit return.
+
+23/02/2004 mcs@astro.caltech.edu (bug reported by Gregory Harris)
+ configure.in configure getline.c enhance.c demo3.c
+ The configure script now checks for the sys/select.h
+ header file, and arranges for a C macro called
+ HAVE_SYS_SELECT_H to be set if it exists. Thus the files
+ that use select() now use this macro to conditionally
+ include sys/select.h where available. Apparently this
+ header is required under FreeBSD 5.1.
+
+23/02/2004 mcs@astro.caltech.edu
+ getline.c libtecla.h man/func/gl_get_line.in
+ I wrote two new public functions, gl_append_history() and
+ gl_automatic_history(). Together these allow the
+ application to take over the responsibility of adding
+ lines to the history list from gl_get_line(). I then
+ documented their functionality in the gl_get_line man
+ page.
+ Version 1.6.0
+ I incremented the minor version number of the library, to
+ comply with the requirement to do so when additions are
+ made to the public interface. See libtecla.map for
+ details.
+ libtecla.map
+ I added a new 1.6.0 group for the new minor version, and
+ added the above pair of functions to it.
+
+15/02/2004 mcs@astro.caltech.edu (fixes a bug reported by Satya Sahoo)
+ history.c
+ Calling gl_load_history() multiple times, eventually led
+ to a segmentation fault. This was due to the head of the
+ list of unused history string segments not getting
+ reset when the history buffer was cleared. While
+ debugging this problem I also noticed that the history
+ resizing function was way too complicated to verify, so
+ after fixing the above bug, I heavily simplified the
+ history resizing function, trading off a small reduction
+ in memory efficiency, for greatly improved clarity, and
+ thus made it much more verifiable and maintainable.
+
+14/02/2004 mcs@astro.caltech.edu (fixes a bug reported by Tim Burress).
+ getline.c
+ If gl_change_terminal() was first used to tell
+ gl_get_line to read input from a file, then called later
+ to tell it to read subsequent input from a terminal, no
+ prompt would be displayed for the first line of
+ interactive input. The problem was that on reaching the
+ end of the input file, gl_get_line() should have called
+ gl_abandon_line(), to tell the next call to gl_get_line()
+ to start inputting a new line from scratch. I have added
+ this now.
+
+14/02/2004 Krister Walfridsson (documented here by mcs@astro.caltech.edu)
+ Makefile.in
+ Krister noticed that I had failed to put $(srcdir)/ in front
+ of some invokations of install.sh. I have remedied this.
+ config.guess config.sub
+ I hadn't updated these for a long time, so apparently they
+ didn't recognise the BSD system that Krister was using.
+ I have now updated them to the versions that come with
+ autoconf-2.59.
+
+22/01/2004 mcs@astro.caltech.edu
+ keytab.c
+ When parsing key-binding specifications, backslash escaped
+ characters following ^ characters were not being expanded.
+ Thus ^\\ got interpretted as a control-\ character followed
+ by a \ character, rather than simply as a control-\
+ character.
+
+12/01/2004 mcs@astro.caltech.edu
+ cplfile.c cplmatch.c demo2.c demo3.c demo.c direader.c
+ expand.c getline.c history.c homedir.c pathutil.c pcache.c
+ configure.in configure INSTALL
+ The configuration script now takes a
+ "--without-file-system" argument. This is primarily for
+ intended for embedded systems that either don't have
+ filesystems, or where the file-system code in libtecla is
+ unwanted bloat. It sets the WITHOUT_FILE_SYSTEM
+ macro. This removes all code related to filesystem
+ access, including the entire public file-expansion,
+ file-completion and path-lookup facilities. Note that the
+ general word completion facility is still included, but
+ without the normally bundled file completion
+ callback. Actually the callback is still there, but it
+ reports no completions, regardless of what string you ask
+ it to complete.
+
+ This option is described in the INSTALL document.
+
+12/01/2004 mcs@astro.caltech.edu
+ getline.c configure.in configure INSTALL
+ The configuration script now takes a
+ "--without-file-actions" argument. This allows an
+ application author/installer to prevent users of
+ gl_get_line() from accessing the filesystem from the
+ builtin actions of gl_get_line(). It defines a macro
+ called HIDE_FILE_SYSTEM. This causes the
+ "expand-filename", "read-from-file", "read-init-files",
+ and "list-glob" action functions to be completely
+ removed. It also changes the default behavior of actions
+ such as "complete-word" and "list-or-eof" to show no
+ completions, instead of the normal default of showing
+ filename completions.
+
+ This option is described in the INSTALL document.
+
+11/01/2004 mcs@astro.caltech.edu
+ getline.c man/func/gl_get_line.in
+ In case an application's customized completion handler
+ needs to write to the terminal for some unforseen reason,
+ there needs to be a way for the it to cleanly suspend raw
+ line editing, before writing to the terminal, and the
+ caller then needs to be aware that it may need to
+ resurrect the input line when the callback returns. I
+ have now arranged that the completion callback functions
+ can call the gl_normal_io() function for this purpose,
+ and documented this in the gl_get_line() man page.
+
+11/01/2004 mcs@astro.caltech.edu (In response to a bug report by Satya Sahoo)
+ getline.c
+ The gl_configure_getline() function makes a malloc'd copy
+ of the names of the configuration files that it is asked
+ to read. Before the bug fix, if the application made one
+ or more calls to this function, the memory allocated by
+ the final call that it made before calling del_GetLine(),
+ wasn't being freed. Note that memory allocated in all but
+ the final call was being correctly freed, so the maximum
+ extent of the memory leak was the length of the file
+ name(s) passed in the final call to
+ gl_configure_getline(), and an application that didn't
+ call gl_configure_getline() didn't suffer any leak.
+
+20/12/2003 mcs@astro.caltech.edu
+ history.c
+ Ellen tested the history fix that I reported below, and
+ pointed out that it still had a problem. This turned out
+ to be because getline.c was making some incorrect
+ assumptions about the new behavior of history.c. This
+ problem and the previous one both revolved around how
+ search prefixes were stored and discarded, so I have now
+ re-written this part of the code. Previously the search
+ prefix was retained by looking for a line with that
+ prefix, and keeping a pointer to that line. This saved
+ memory, compared to storing a separate copy of the
+ prefix, but it led to all kinds of hairy
+ interdependencies, so I have now changed the code to keep
+ a separate copy of search prefixes. To keep the memory
+ requirements constant, the search prefix is stored in the
+ history buffer, like normal history lines, but not
+ referenced by the time-ordered history list. The prefix
+ can now be kept around indefinitely, until a new search
+ prefix is specified, regardless of changes to the
+ archived lines in the history buffer. This is actually
+ necessary to make the vi-mode re-search actions work
+ correctly. In particular, I no longer discard the search
+ prefix whenever a history search session ends. Also,
+ rather than have getline.c keep its own record of when a
+ history session is in progress, it now consults
+ history.c, so that failed assumptions can't cause the
+ kind of discrepancy that occurred before. For this to
+ work, getline.c now explicitly tells history.c to cancel
+ search sessions whenever it executes any non-history
+ action.
+
+14/12/2003 mcs@astro.caltech.edu (bug reported by Ellen Oschmann)
+ history.c
+ If one searched backwards for a prefix, then returned to
+ the original line, changed that line, then started
+ another backwards prefix search, getline incorrectly
+ discarded the new search prefix in the process of
+ throwing away its cached copy of the previous pre-search
+ input line. In other words getline was belatedly
+ cancelling a previous search, after a new search had
+ already partially begun, and thus messed up the new
+ search. The obvious fix was to arrange for the current
+ search to be cancelled whenever the history pointer
+ returns to its starting point, rather than waiting for
+ the next search to begin from there.
+
+14/12/2003 mcs@astro.caltech.edu
+ history.c
+ _glh_recall_line() was returning the last line in the
+ history buffer instead of the line requested by the
+ caller. This only affected the obscure "repeat-history"
+ action-function, which probably isn't used by anybody.
+
+09/12/2003 Version 1.5.0 released.
+
+28/09/2003 mcs@astro.caltech.edu
+ homedir.c
+ When the home directory of the login user is requested,
+ see if the HOME environment variable exists, and if so
+ return its value, rather than looking up the user's home
+ directory in the password file. This seems to be the
+ convention adopted by other unix programs that perform
+ tilde expansion, and it works around a strange problem,
+ where a third-party libtecla program, statically compiled
+ under an old version of RedHat, unexpectedly complained
+ that getpwd() returned an error when the program was run
+ under RedHat 9.
+
+01/09/2003 mcs@astro.caltech.edu
+ getline.c libtecla.h libtecla.map man/func/gl_get_line.in
+ man/func/gl_register_action.in.
+ It is now possible for an application to register
+ external functions as action functions. These actions are
+ initially bound to specified key-sequences, but if they
+ are registered before the user's configuration file is
+ loaded, they can also be re-bound by the user to
+ different key-sequences. The function used to register a
+ new action, is called gl_register_action(). Action
+ functions are passed a readonly copy of the input line
+ and the cursor position. They can display text to the
+ terminal, or perform other operations on the application
+ environment. Currently, they can't edit the input line or
+ move the cursor. This will require the future addition of
+ functions to queue the invokation of the built-in action
+ functions.
+
+26/08/2003 mcs@astro.caltech.edu
+ getline.c
+ I modified gl_update_buffer() to ensure that the cursor
+ stays within the input line after external line
+ modifications, and to queue a redisplay of the
+ potentially modified input line.
+
+21/07/2003 mcs@astro.caltech.edu
+ configure.in configure Makefile.in Makefile.stub INSTALL
+ By specifying --without-man-pages or --with-man-pages=no
+ as command-line arguments to the configure script, it is
+ now possible to have the configure script skip the
+ man-page preprocessing step, and arrange for the man-page
+ installation targets in the Makefile to do nothing. This
+ option is designed for people who embed libtecla within
+ other packages. It is also used by Makefile.stub when
+ the distclean target is specified.
+
+21/07/2003 mcs@astro.caltech.edu
+ configure.in configure
+ The previous workaround for recent versions of gcc
+ placing /usr/local/include at the start of the system
+ inlcude-file search path, broke something else. The fix
+ placed /usr/include before gcc's include area, which
+ meant that gcc's modified version of stdarg.h was being
+ ignored in deference to the version in /usr/include. I
+ have changed the fix to have gcc report the search path,
+ then have awk add options to CFLAGS to reorder this path,
+ plaing /usr/local/include at the end.
+
+ Also, under Solaris 9, including term.h without first
+ including curses.h results in complaints about undefined
+ symbols, such as bool. As a result the configure script's
+ test for term.h was failing. I have now modified it to
+ include curses.h in the test code that it uses to check
+ for term.h. In the process I also improved the tests for
+ curses.h and term.h to prevent an ncurses version of
+ term.h from being used with the system-default version of
+ curses.h.
+
+29/06/2003 mcs@astro.caltech.edu
+ Makefile.in direader.c homedir.c
+ On some systems (eg. linux) the _POSIX_C_SOURCE
+ feature-test macro is set by system headers, rather than
+ being an option set by a project's Makefile at
+ compilation time. In software, such as tecla, where the
+ definition of this macro is used as an indication of
+ whether to use the non-reentrant or reentrant versions of
+ system functions, this means that the reentrant functions
+ are always used, regardless of whether this macro is set
+ or not by the project Makefile. Thus, on such systems the
+ reentrant and non-reentrant versions of the tecla library
+ are essentially identical. This has a couple of
+ drawbacks. First, since thread-safe functions for
+ traversing the password file don't exist, the supposedly
+ non-reentrant version of the tecla library can't support
+ ambiguous tab-completion of usernames in ~username/
+ constructions. Secondly, on some systems the use of
+ reentrant system functions dictates the use of a shared
+ library that isn't needed for the non-reentrant
+ functions, thus making it more difficult to distribute
+ binary versions of the library.
+
+ To remedy this situation I have modified the DEFINES_R
+ variable in Makefile.in to arrange for the compiler to
+ define a C macro called PREFER_REENTRANT when it is
+ compiling the reentrant version of the tecla library.
+ This macro is now used in the source code to determine
+ when to require reentrant code. Whithin the source code,
+ wherever a potentially non-reentrant interface is used,
+ the existance of both this macro and a suitably valued
+ _POSIX_C_SOURCE macro, are tested for to see if a
+ reentrant alternative to the problem code should be used.
+
+22/06/2003 mcs@astro.caltech.edu
+ getline.c
+ I changed the way that redisplays are requested and
+ performed. Redisplays are now queued by calling
+ gl_queue_redisplay(), and subsequently performed by
+ gl_flush_output(), when the queue of already pending
+ output has been completely dispatched. This was necessary
+ to prevent event handlers from filling up the output
+ queue with redisplays, and it also simplifies a number of
+ things. In the process I removed the gl_queue_display()
+ function. I also wrote a gl_line_erased() function, which
+ is now called by all functions that erase the input
+ line. I also split the gl_abandon_line() function into
+ public and private callable parts, and used the private
+ version internally to arrange to discard the input line
+ after errors.
+
+ The raw_mode flag was not being initialized by new_GetLine().
+ It is now initialized to zero.
+
+ I removed the zapline flag, since using the endline flag to
+ communicate the desire to terminate the line, did the same
+ thing.
+
+ gl_terminal_move_cursor() now does nothing when the input
+ line isn't displayed.
+
+18/03/2003 mcs@astro.caltech.edu
+ getline.c
+ Fixed bug which was causing newlines not to be output
+ at the end of each newly entered line. I was
+ interpreting the gl-&gt;endline flag in conflicting ways in
+ two places. To fix this I have created a gl-&gt;displayed
+ flag. This flags whether an input line is currently
+ displayed.
+
+17/03/2003 mcs@astro.caltech.edu
+ getline.c libtecla.h man/func/gl_get_line.in
+ man/func/gl_erase_terminal.in libtecla.map
+ I added a new function that programs can call to clear
+ the terminal between calls to gl_get_line().
+
+11/03/2003 mcs@astro.caltech.edu
+ configure.in configure
+ Under linux when _POSIX_C_SOURCE is defined, getpwent()
+ and associated functions become undefined, because
+ _SVID_SOURCE and _BSD_SOURCE become undefined. Adding
+ these feature macros back to CFLAGS resolves this.
+
+06/03/2003 mcs@astro.caltech.edu
+ getline.c libtecla.map man/func/gl_get_line.in
+ Following the lead of Edward Chien, I wrote a function
+ called gl_bind_keyseq(), which binds a specified
+ key-sequence to a given action, or unbinds the
+ key-sequence.
+
+24/02/2003 mcs@astro.caltech.edu
+ getline.c libtecla.map man/func/cpl_complete_word.in
+ I implemented a simple function called
+ cpl_recall_matches(). This recalls the return value of
+ the last call to cpl_complete_word().
+
+19/01/2003 mcs@astro.caltech.edu
+ getline.c
+ The documented signal handling, fd event-handling,
+ inactivity timeout handling, and server-mode non-blocking
+ I/O features are now implemented for non-interactive
+ input streams, such as pipes and files.
+
+19/01/2003 mcs@astro.caltech.edu
+ getline.c libtecla.h man/func/gl_get_line.in demo3.c
+ I added a new return status enumerator to report
+ when an end-of-file condition causes gl_get_line()
+ to return NULL.
+
+13/01/2003 mcs@astro.caltech.edu
+ history.c
+ I rewrote the history facility. The previous
+ circular buffer implementation was a nightmare to change,
+ and it couldn't efficiently support certain newly
+ requested features. The new implementation stores history
+ lines in linked lists of fixed sized string segments,
+ taken from the buffer, with each line being reference
+ counted and recorded in a hash table. If the user enters
+ a line multiple times, only one copy of the line is now
+ stored. Not only does this make better use of the
+ available buffer space, but it also makes it easy to
+ ensure that a line whose prefix matches the current
+ search prefix, isn't returned more than once in sequence,
+ since we can simply see if the latest search result has
+ the same hash-table pointer as the previous one, rather
+ than having to compare strings. Another plus is that due
+ to the use of linked lists of nodes of fixed size line
+ segments, there is no longer any need to continually
+ shuffle the contents of the buffer in order to defragment
+ it. As far as the user is concerned, the visible
+ differences are as follows:
+
+ 1. If the user enters a given line multiple times in a
+ row, each one will be recorded in the history list,
+ and will thus be listed by gl_show_history(), and
+ saved in the history file. Previously only one line
+ was recorded when consecutive duplicates were entered.
+ This was a kludge to prevent history recall from
+ recalling the same line multiple times in a row. This
+ only achieved the desired result when not recalling by
+ prefix.
+
+ 2. Not only simple recall, but prefix-based history line
+ recalls now don't return the same line multiple times
+ in a row. As mentioned in (1) above, previously this
+ only worked when performing a simple recall, without a
+ search prefix.
+
+28/12/2002 mcs@astro.caltech.edu
+ getline.c
+ The one-line function, gl_buff_curpos_to_term_curpos()
+ was only being used by gl_place_cursor(), so I inlined it
+ in that function, and removed it.
+
+28/12/2002 mcs@astro.caltech.edu
+ getline.c
+ gl_suspend_process() was calling the application-level
+ gl_normal_io() and gl_raw_io() functions, where it should
+ have been calling the internal versions _gl_normal_io()
+ and _gl_raw_io().
+ Also gl_handle_signal() was masking and unmasking just
+ the signals of the first element of the gl[] array
+ argument. It now masks and unmasks all trappable signals.
+
+28/12/2002 mcs@astro.caltech.edu
+ getline.c
+ Now that the number of terminal characters used to
+ display the current input line, is recorded, the relative
+ line on which the last character of the input line
+ resides can be determined without having to call
+ gl_buff_curpos_to_term_curpos(). This is now used by
+ gl_normal_io() via gl_start_newline(), so there is now no
+ need for gl_buff_curpos_to_term_curpos() to be
+ async-signal safe. I have thus removed the annoying
+ gl-&gt;cwidth[] array, and gl_buff_curpos_to_term_curpos()
+ now calls gl_width_of_char() directly again. There is
+ also now no need for the gl_line_of_char_start() and
+ gl_line_of_char_end() functions, so I have removed them.
+
+28/12/2002 mcs@astro.caltech.edu
+ getline.c
+ Unfortunately it turns out that the terminfo/termcap
+ control sequence which is defined to delete everything
+ from the current position to the end of the terminal, is
+ only defined to work when at the start of a terminal
+ line. In gnome terminals in RedHat 8.0, if it is used
+ within a terminal line, it erases the whole terminal
+ line, rather than just what follows the cursor. Thus to
+ portably truncate the displayed input line it is
+ necessary to first use the control sequence which deletes
+ from the cursor position to the end of the line, then if
+ there are more terminal lines, move to the start of the
+ next line, and use the delete to end-of-terminal control
+ sequence, then restore the cursor position. This requires
+ that one know how many physical terminal lines are used
+ by the current input line, so I now keep a record of the
+ number of characters so far displayed to the terminal
+ following the start of the prompt, and the new
+ gl_truncate_display() function uses this information to
+ truncate the displayed input line from the current cursor
+ position.
+
+28/12/2002 mcs@astro.caltech.edu
+ getline.c
+ gl_start_newline() now moves to an empty line following
+ the input line, rather than just to the next line. It
+ also arranges for the input line to be redisplayed before
+ editing resumes. A major user of this is gl_print_info(),
+ which now need not be followed by an explicit call to
+ gl_redisplay(), since the terminal input loop in
+ gl_get_input_line() ensures that gl_redisplay() is called
+ after any action function that asserts gl-&gt;redisplay.
+ Also, all functions that erase the displayed input line
+ can now call the gl_erase_line() function, which is
+ designed to work correctly even when a terminal resize
+ invalidates the horizontal cursor position. Finally, the
+ new gl_queue_display() function is now used by functions
+ that need to arrange for the input line to be displayed
+ from scratch after the displayed line has been erased or
+ invalidated by other text being written to the terminal.
+ All of these changes are aimed at reducing the number of
+ places that directly modify gl-&gt;term_curpos and
+ gl-&gt;redisplay.
+
+22/12/2002 Markus Gyger (logged here by mcs)
+ Makefile.in update_html
+ In places where echo and sed were being used to extract
+ the base names of files, Markus substituted the basename
+ command. He also replaced explicit cp and chmod commands
+ with invokations of the install-sh script.
+ configure.in
+ Use $target_os and $target_cpu, where appropriate,
+ instead of $target.
+ configure.in
+ The Solaris man function and library man pages should
+ be in sections 3lib and 3tecla respectively, only in
+ Solaris version 2.8 and above.
+ configure.in
+ Markus provided values for the man page configuration
+ variables for HPUX.
+ man/*/*.in
+ I had missed parameterizing man page section numbers in
+ the man page titles, Markus corrected this.
+ man/func/libtecla_version.in
+ Fixed incorrect section number in the link to the
+ libtecla man page.
+ homedir.c
+ When compiled to be reentrant, although one can't use the
+ non-reentrant getpwent() function to scan the password
+ file for username completions, one can at least see if
+ the prefix being completed is a valid username, and if
+ the username of the current user minimally matches the
+ prefix, and if so list them. I simplified Markus'
+ modification by adding a prefix argument to the
+ _hd_scan_user_home_dirs() function, and redefining the
+ function description accordingly, such that now it
+ reports only those password file entries who's usernames
+ minimally match the specified prefix. Without this, it
+ would have been necessary to peak inside the private data
+ argument passed in by cf_complete_username().
+ Markus also provided code which under Solaris uses the
+ non-reentrant interfaces if the reentrant version of the
+ library isn't linked with the threads library.
+
+19/12/2002 mcs@astro.caltech.edu
+ Makefile.in
+ Markus pointed out that LDFLAGS was being picked up by
+ the configure script, but not then being interpolated
+ into te Makefile. I have thus added the necessary
+ assignment to Makefile.in and arranged for the value of
+ LDFLAGS to be passed on to recursive make's. I also did
+ the same for CPPFLAGS, which had also been omitted.
+
+18/12/2002 mcs@astro.caltech.edu
+ man/* man/*/* configure.in configure Makefile.in
+ update_html
+ It turns out that the assignment of man page sections to
+ topics differs somewhat from system to system, so this is
+ another thing that needs to be configured by the main
+ configuration script, rather than being hardwired. All
+ man pages have now been moved into suitably named
+ topic-specific sub-directories of the top-level man
+ directory, and instead of having a numeric suffix, now
+ have the .in suffix, since they are now preprocessed by
+ the configure script, in the same fashion as Makefile.in.
+ Whithin these *.in versions of the man pages, and within
+ Makefile.in, the installation subdirectory (eg. man1) and
+ the file-name suffix (eg. 1), are written using
+ configuration macros, so that they get expanded to the
+ appropriate tokens when the configure script is run. In
+ principle, the man pages could also take advantage of
+ other configuration macros, such as the one which expands
+ to the library installation directory, to include full
+ path names to installed files in the documentation, so in
+ the future this feature could have more uses than just
+ that of parameterizing man page sections.
+
+18/12/2002 mcs@astro.caltech.edu
+ man3 man3/* Makefile.in html/index.html update_html
+ Markus suggested splitting the gl_get_line(3) man page
+ into user and developer sections, and also pointed out
+ that the enhance man page should be in section 1, not
+ section 3. I have thus created a top-level man
+ directory in which to place the various sections, and
+ moved the man3 directory into it. The enhance.3 man page
+ is now in man/man1/enhance.1. I have extracted all
+ user-oriented sections from the gl_get_line(3) man page
+ and placed them in a new man7/tecla.7 man page.
+
+18/12/2002 mcs@astro.caltech.edu
+ getline.c
+ Terminal resizing was broken in normal mode, due to
+ me forcing the terminal cursor position to zero in the
+ wrong place in gl_check_caught_signal().
+
+14/12/2002 Markus Gyger (logged here by mcs)
+ configure.in configure
+ Under Solaris, recent versions of gcc search
+ /usr/local/include for header files before the system
+ directories. This caused a problem if ncurses was
+ installed under Solaris, since the termcap.h include file
+ in /usr/local/include ended up being used at compile
+ time, whereas the system default version of the curses
+ library was used at link time. Since the two libraries
+ declare tputs() differently, this evoked a complaint from
+ gcc. Markus came up with a way to force Gnu cpp to move
+ /usr/local/include to the end of the system-include-file
+ search path, where it belongs.
+
+13/12/2002 mcs@astro.caltech.edu
+ man3/gl_io_mode.3
+ I rewrote the man page which documents the new non-blocking
+ server I/O mode.
+
+12/12/2002 mcs@astro.caltech.edu
+ demo3.c
+ I wrote a new version of demo3.c, using signal handlers
+ that call gl_handle_signal() and gl_abandon_line(), where
+ previously in this demo, these functions were called from
+ the application code.
+
+05/12/2002 mcs@astro.caltech.edu
+ getline.c
+ gl_normal_io(), gl_raw_io() and gl_handle_signal() and
+ gl_abandon_line() are now signal safe, provided that
+ signal handlers that call them are installed with sa_mask's
+ that block all other signals who's handlers call them.
+ This is the case if gl_tty_signals() is used to install
+ signal handlers that call any of these functions.
+
+ A major stumbling block that had to be overcome was that
+ gl_displayed_char_width() calls isprint(), which can't
+ safely be called from a signal handler (eg. under linux,
+ the is*() functions all use thread-specific data
+ facilities to support per-thread locales, and the
+ thread-specific data facilities aren't signal safe). To
+ work around this, all functions that modify the
+ input-line buffer, now do so via accessor functions which
+ also maintain a parallel array of character widths, for
+ use by gl_buff_curpos_to_term_curpos() in place of
+ gl_displayed_char_width(). Other minor problems were the
+ need to avoid tputs(), who's signal safety isn't defined.
+
+05/12/2002 Eric Norum (logged here by mcs@astro.caltech.edu)
+ configure.in
+ Eric provided the configuration information needed
+ to build shared libraries under Darwin (Max OS X).
+
+05/12/2002 Richard Mlynarik (logged here by mcs@astro.caltech.edu)
+ configure.in
+ AC_PROG_RANLIB gets the wrong version of ranlib when
+ cross compiling, so has now been replaced by an
+ invokation of AC_CHECK_TOOL. In addition, AC_CHECK_TOOL
+ is also now used to find an appropriate version of LD.
+
+05/12/2002 mcs@astro.caltech.edu (based on patch by Pankaj Rathore)
+ getline.c libtecla.h libtecla.map man3/gl_get_line.3
+ The new gl_set_term_size() function provides a way
+ to tell gl_get_line() about changes in the size of
+ the terminal in cases where the values returned by
+ ioctl(TIOCGWINSZ) isn't correct.
+
+05/12/2002 mcs@astro.caltech.edu
+ getline.c
+ Rather than calling sprintf() to see how much space would
+ be needed to print a given number in octal, I wrote a
+ gl_octal_width() function, for use by
+ gl_displayed_char_width(). This makes the latter
+ function async signal safe.
+
+05/12/2002 mcs@astro.caltech.edu
+ chrqueue.c
+ Whenever the buffer is exhausted, and getting a new
+ buffer node would require a call to malloc(), attempt
+ to flush the buffer to the terminal. In blocking I/O
+ mode this means that the buffer never grows. In
+ non-blocking I/O mode, it just helps keep the buffer
+ size down.
+
+05/12/2002 mcs@astro.caltech.edu
+ freelist.h freelist.c
+ The new _idle_FreeListNodes() function queries the
+ number of nodes in the freelist which aren't currently
+ in use.
+
+05/12/2002 mcs@astro.caltech.edu
+ Makefile.stub
+ This now accepts all of the targets that the configured
+ makefile does, and after configuring the latter makefile,
+ it invokes it with the same options.
+
+03/12/2002 mcs@astro.caltech.edu
+ mans3/gl_io_mode.3
+ I completed the man page for all of the new functions
+ related to non-blocking I/O.
+
+01/12/2002 mcs@astro.caltech.edu
+ man3/gl_get_line.3
+ I wrote a long section on reliable signal handling,
+ explaining how gl_get_line() does this, how to make
+ use of this in a program, and how to handle signals
+ reliably when faced with other blocking functions.
+ This basically documents what I have learnt about
+ signal handling while working on this library.
+
+01/12/2002 mcs@astro.caltech.edu
+ getline.c man3/gl_get_line.3
+ In non-blocking server mode, the gl_replace_prompt()
+ function can now be used between calls to gl_get_line()
+ if the application wants to change the prompt of the
+ line that is being edited.
+
+01/12/2002 mcs@astro.caltech.edu
+ man3/gl_get_line.3
+ I documented the new gl_return_status() and
+ gl_error_message() functions.
+
+01/12/2002 mcs@astro.caltech.edu
+ getline.c man3/gl_get_line.3
+ Added SIGPOLL and SIGXFSZ to the list of signals that
+ are trapped by default. These are process termination
+ signals, so the terminal needs to be restored to a
+ usable state before they terminate the process.
+
+27/11/2002 mcs@astro.caltech.edu
+ getline.c libtecla.h
+ Completed the essential changes needed to support
+ non-blocking server-I/O mode.
+
+ The new gl_io_mode() function allows one to switch to
+ and from non-blocking server-I/O mode.
+
+ The new gl_raw_io() function is used in non-blocking
+ server-I/O mode to switch the terminal into non-blocking
+ raw I/O mode.
+
+ The new gl_normal_io() function is used in non-blocking
+ server-I/O mode to switch the restore the terminal to
+ a normal, blocking state. This is used to suspend line
+ input before suspending the process or writing messages
+ to the terminal.
+
+ The new gl_tty_signals() function installs specified
+ signals handlers for all signals that suspend, terminate
+ or resume processes, and also for signals that indicate
+ that the terminal has been resized. This not only saves
+ the application from having to keep its own ifdef'd list
+ of such signals, of which there are many, but it also
+ makes sure that these signal handlers are registered
+ correctly. This includes using the sa_mask member of each
+ sigaction structure to ensure that only one of these
+ handlers runs at a time. This is essential to avoid the
+ signal handlers all trying to simultaneously modify
+ shared global data.
+
+ The new gl_handle_signal() function is provided for
+ responding (from application level) to signals caught by
+ the application. It handles process suspension, process
+ termination and terminal resize signals.
+
+ The new gl_pending_io() function tells the application
+ what direction of I/O gl_get_line() is currently waiting
+ for.
+
+ In non-blocking server I/O mode, the new
+ gl_abandon_line() function can be called between calls to
+ gl_get_line() to discard an input line and force the next
+ call to gl_get_line() to start the input of a new line.
+
+ Also, in non-blocking server-I/O gl_get_line() doesn't
+ attempt to do anything but return when one of the signals
+ that it is configured to catch is caught. This is
+ necessary because when in this mode, the application is
+ required to handle these signals when gl_get_line() is
+ running, and the default configuration of most of these
+ signals in gl_get_line() is to restore the terminal then
+ call the application signal handlers. This would be a
+ case of too many cooks spoiling the broth, so in this
+ mode, gl_get_line() always defers to the application's
+ signal handlers.
+
+26/11/2002 mcs@astro.caltech.edu
+ getline.c libtecla.h
+ I implemented a couple of new functions to support
+ reliable signal handling, as now documented
+ (see above) in the gl_get_line(3) man page.
+
+ The new gl_catch_blocked() function tells gl_get_line()
+ to unblock all configured signals around calls to
+ long-running functions, not only those that aren't
+ blocked when gl_get_line() is called. This allows
+ the caller to implement reliable signal handling,
+ since the unblocking is only done from within code
+ protected by sigsetjmp(), which avoids race conditions.
+
+ The new gl_list_signals() function fills a provided
+ sigset_t with the set of signals that gl_get_line() is
+ currently configured to catch. This allows callers to
+ block said signals, such that they are only unblocked by
+ gl_get_line() when it is waiting for I/O. When used in
+ conjunction with the gl_catch_blocked() function, this
+ removes the potential for race conditions.
+
+ Also, when gl_get_line() installs its signal handler,
+ it uses the sa_mask member of the sigaction structure
+ to ensure that only one instance of this signal handler
+ will ever be executing at a time.
+
+25/11/2002 mcs@astro.caltech.edu (bug reported by Pankaj Rathore)
+ getline.c
+ When any history recall action was invoked when the
+ input line buffer was full, an error message would be
+ displayed complaining about the length of the string
+ in the line input buffer being inconsistent with the
+ specified allocated size. This was because instead of
+ sending the allocated size of the input line, I was
+ sending the length excluding the element that is
+ reserved for the '\0' terminator. Sending it the
+ correct size corrected the problem.
+
+24/11/2002 mcs@astro.caltech.edu
+ getline.c
+ All public functions which take GetLine objects as
+ arguments now block signals on entry and restore the
+ signal mask on return. This was an attempt to make it
+ safe to call getline functions from signal handlers, but
+ the fact is that the functions that I really wanted this
+ to apply to, potentially call malloc(), so this currently
+ isn't the case.
+
+23/11/2002 mcs@astro.caltech.edu
+ getline.c libtecla.h
+ The new gl_return_status() function returns an enumerated
+ return status which can be used to query what caused
+ gl_get_line() to return.
+
+22/11/2002 mcs@astro.caltech.edu
+ Most existing .c and .h files, plus errmsg.c errmsg.h
+ Makefile.rules
+ Until now, many library functions would report error
+ messages to stderr. This isn't appropriate for library
+ functions, so in place of this behavior, error messages
+ are now recorded in internal ErrMsg objects, and passed
+ between modules via new module-specific error querying
+ functions. In addition, errno is now set appropriately.
+ Thus when gl_get_line() and related functions return an
+ error, strerror() can be used to look up system errors,
+ and gl_error_message() can be used to recover a higher level
+ error message. Note that error messages that are
+ responses to user actions continue to be reported to the
+ terminal, as before.
+
+21/11/2002 mcs@astro.caltech.edu
+ getline.c keytab.h keytab.c Makefile.rules
+ I wrote a new version of _kt_lookup_binding() that didn't
+ require the caller to have access to the innards of a
+ KeyTab object. This then enabled me to move the definition
+ of KeyTab objects into keytab.c and make the typedef in
+ keytab.h opaque. Many nested includes were also moved from
+ keytab.h into keytab.c.
+
+05/11/2002 mcs@astro.caltech.edu
+ getline.c libtecla.map libtecla.h demo3.c
+ I split the old gl_resize_terminal() function into
+ two parts, gl_query_size() and gl_update_size(), with
+ the latter calling the former to get the new terminal
+ size.
+
+05/11/2002 mcs@astro.caltech.edu
+ getline.c
+ I fixed a long time bug in the terminal resizing code.
+ When the cursor wasn't on the last terminal line of the
+ input line, the resizing code would redisplay the
+ the line one or more lines above where it should be
+ restored. This was due to an error in the calculation of
+ the number of lines above the cursor position.
+
+04/11/2002 mcs@astro.caltech.edu
+ demo.c demo2.c demo3.c
+ I used the new gl_display_text() function to display
+ introductory text at the startup of each of the demo
+ programs. The text is enclosed within a box of asterixes,
+ drawn dynamically to fit within the confines of the
+ available terminal width.
+
+04/11/2002 mcs@astro.caltech.edu
+ libtecla.h getline.c ioutil.c ioutil.h Makefile.rules
+ libtecla.map man3/gl_get_line.3 man3/gl_display_text.3
+ Needing a way to display introductory text intelligently
+ in the demo programs, I wrote and documented the
+ gl_display_text() function. This justifies arbitrary
+ length text within the bounds of the terminal width,
+ with or without optional indentation, prefixes and
+ suffixes.
+
+03/11/2002 mcs@astro.caltech.edu
+ demo3.c Makefile.rules
+ I wrote a new demonstration program. This program acts
+ exactly like the main demonstration program, except that
+ it uses an external event loop instead of using the
+ gl_get_line() internal event loop. This is thus an example
+ of the new non-blocking server I/O facility.
+
+02/11/2002 mcs@astro.caltech.edu
+ getline.c keytab.c keytab.h libtecla.h man3/gl_get_line.3
+ man3/gl_completion_action.3
+ I added the ability to register additional word
+ completion actions via the new function
+ gl_completion_action(). All action functions now take a
+ new (void *data) argument, which is stored with the
+ function in the symbol table of actions. The new
+ gl_completion_action() function uses this feature to
+ record dynamically allocated objects containing the
+ specified completion function and callback data along
+ with either the gl_complete_word() action function, or
+ the gl_list_completions() action function. These two
+ actions continue to use the builtin completion functions
+ when their data pointer is NULL.
+
+20/10/2002 mcs@astro.caltech.edu
+ The following are changes merged from the non-blocking
+ gl_get_line() development branch.
+
+ getline.c
+ I wrote a gl_start_newline() function, to replace all of
+ the explicit calls to output \r\n to stdout.
+
+ Informational messages are now written to the terminal
+ using a new variadic function called gl_print_info().
+ This starts a newline, writes string arguments until a
+ special argument, GL_END_INFO, is seen, then starts
+ another newline.
+
+ Changed _output_ to _print_ in the following function
+ names gl_output_control_sequence(), gl_output_char(),
+ gl_output_string() and gl_output_raw_string().
+
+ gl_print_raw_string() now has a length argument, so that
+ strings that aren't terminated with '\0' can be printed.
+
+ The display of the initial contents of a new line to be
+ edited has been moved into a new function called
+ gl_present_line().
+
+ The gl_get_input_line() function now takes the prompt
+ string as an argument so that gl_replace_prompt() can be
+ called from within this function instead of from
+ gl_get_line().
+
+ Keyboard input is now buffered in a persistent buffer in
+ the parent GetLine object. gl_read_character() checks
+ this for unprocessed characters in preference to calling
+ gl_read_terminal() to append characters to it. A new
+ function, gl_discard_chars(), removes processed
+ characters from this buffer. This change is in
+ preparation for a non-blocking version of gl_get_line(),
+ where partially input key-sequences must be stored
+ between calls to gl_get_line().
+
+ getline.c getline.h history.c history.h cplmatch.c \
+ cplmatch.h expand.c expand.h
+ All terminal output from gl_get_line() is now routed
+ through a GL_WRITE_FN() callback function called
+ gl_write_fn. Internal functions in cplmatch.c,
+ expand.c and history.c have been created which take
+ such callbacks to write output. These are used both
+ by functions in getline.c, to display file completions,
+ expansions, history etc, and as the internals of existing
+ public functions in these files that print to stdio
+ streams. In the latter case an internal stdio
+ GL_WRITE_FN() callback is substituted, so that the
+ functions behave as before.
+
+ getline.c chrqueue.c chrqueue.h
+ The gl_write_fn() callback used by gl_get_line() now
+ writes to a queue, implemented in chrqueue.c. This queue
+ is implemented as a list of blocks of buffer segments,
+ the number of which shrink and grow as
+ needed. The contents of the queue are flushed to the
+ terminal via another GL_WRITE_FN() callback passed to the
+ queue object. Currently gl_get_line() passes an internal
+ function assigned to gl-&gt;flush_fn, called
+ gl_flush_terminal(), which writes the contents of the
+ queue to the terminal, and knows how to handle both
+ blocking and non-blocking I/O. The output queue is
+ designed to be flushed to the terminal incrementally, and
+ thereby also facilitates non-blocking I/O.
+
+ getline.c getline.h
+ gl_get_line() now reads all input via the GL_READ_FN()
+ callback, assigned to gl-&gt;read_fn. Currently this is
+ set to an internal function called gl_read_terminal(),
+ which knows how to handle both blocking and
+ non-blocking I/O.
+
+ getline.c libtecla.h
+ The new gl_set_nonblocking() function can be used to
+ enable or disable non-blocking I/O. The default is still
+ blocking I/O. In non-blocking mode, the terminal is told
+ not to wait when either reading or writing would block.
+ gl_get_line() then returns, with a return value of NULL,
+ but with the terminal left in raw mode, so that the
+ caller's event loop can detect key presses. The caller
+ should call gl_return_status() to check whether the NULL
+ return value was due to an error, lack of input, or
+ inability to write to the terminal without waiting. If
+ either reading or writing was said to have blocked, the
+ user then should check for I/O readiness in the specified
+ direction before calling gl_get_line() again to
+ incrementally build up the input line.
+
+05/08/2002 mcs@astro.caltech.edu
+ man3/gl_get_line.3 man3/gl_inactivity_timeout.3
+ I documented the new gl_inactivity_timeout() function.
+
+08/07/2002 mcs@astro.caltech.edu
+ libtecla.h getline.c libtecla.map
+ I added a new gl_inactivity_timeout() function. On
+ systems that have the select system call, this provides
+ the option of registering a function that is then called
+ whenever no I/O activity has been seen for more than a
+ specified period of time. Like the gl_watch_fd()
+ facility, timeout callbacks return a code which tells
+ gl_get_line() how to proceed after the timeout has been
+ handled.
+
+04/07/2002 mcs@astro.caltech.edu (based on a bug report from Michael MacFaden)
+ getline.c
+ The internal event handler wasn't responding to write
+ events on client file descriptors, due to a typo which
+ resulted in read events being checked for twice, and
+ writes not checked for at all.
+ pathutil.c
+ The amount of space to allocate for pathnames is supposed
+ to come from PATH_MAX in limits.h, but I had neglected to
+ include limits.h. This went unnoticed because on most
+ systems the equivalent number is deduced by calling
+ pathconf(). Apparently under NetBSD this function doesn't
+ work correctly over NFS mounts.
+
+30/05/2002 Version 1.4.1 released.
+
25/05/2002 mcs@astro.caltech.edu (based on suggestions by Paul Smith)
pathutil.c
Apparently, under QNX pathconf("/",_PC_PATH_MAX) returns
@@ -23,6 +1274,21 @@ The most recent modifications are listed first.
already doing futher up in the file, so I have just
removed the errant include line.
+07/05/2002 mcs@astro.caltech.edu (async development branch only)
+ getline.c
+ gl_read_character() now caches and reads unprocessed
+ characters from a key-press lookahead buffer. Whenever
+ gl_intepret_char() receives a new character which makes
+ an initially promising key-sequence no longer match the
+ prefix of any binding, it now simply discards the first
+ character from the key-press buffer and resets the buffer
+ pointer so that the next call to gl_read_character()
+ returns the character that followed it, from the buffer.
+ getline.c
+ The part of gl_get_input_line() which preloads, displays
+ and prepares to edit a new input line, has now been moved
+ into a function called gl_present_line().
+
12/02/2002 mcs@astro.caltech.edu
getline.c configure.in configure
Mac OS X doesn't have a term.h or termcap.h, but it does
@@ -170,7 +1436,7 @@ The most recent modifications are listed first.
getline.c man3/gl_get_line.3
gl_get_line() by default now prints any 8-bit printable
characters that don't match keybindings. Previously
- characters > 127 were only printed if preceded by the
+ characters &gt; 127 were only printed if preceded by the
literal-next action. Alternatively, by placing the
command literal_if_printable in the tecla configuration
file, all printable characters are treated as literal
@@ -198,7 +1464,7 @@ The most recent modifications are listed first.
all be displayable. Now isprint() is consulted, and if it
says that a character isn't printable, the character code
is displayed in octal like \307. In non-C locales, some
- characters with values > 127 are displayable, and
+ characters with values &gt; 127 are displayable, and
isprint() tells gl_get_line() which are and which aren't.
27/11/2001 mcs@astro.caltech.edu
@@ -207,7 +1473,7 @@ The most recent modifications are listed first.
are now cast to (int)(unsigned char). Previously they
were cast to (int), which doesn't correctly conform to
the requirements of the C standard, and could cause
- problems for characters with values > 127 on systems
+ problems for characters with values &gt; 127 on systems
with signed char's.
26/11/2001 mcs@astro.caltech.edu
@@ -603,7 +1869,7 @@ The most recent modifications are listed first.
17/05/2001 mcs@astro.catlech.edu
getline.c
- Under Linux, calling fflush(gl->output_fd) hangs if
+ Under Linux, calling fflush(gl-&gt;output_fd) hangs if
terminal output has been suspended with ^S. With the
tecla library taking responsability for reading the stop
and start characters this was a problem, because once
@@ -629,8 +1895,8 @@ The most recent modifications are listed first.
12/05/2001 Tim Eliseo (logged here by mcs)
getline.c
- Don't reset gl->number until after calling an action
- function. By looking at whether gl->number is <0 or
+ Don't reset gl-&gt;number until after calling an action
+ function. By looking at whether gl-&gt;number is &lt;0 or
not, action functions can then tell whether the count
that they were passed was explicitly specified by the
user, as opposed to being defaulted to 1.
@@ -651,12 +1917,12 @@ The most recent modifications are listed first.
getline.c
The test in gl_add_char_to_line() for detecting
when overwriting a character with a wider character,
- had a < where it needed a >. Overwriting with a wider
+ had a &lt; where it needed a &gt;. Overwriting with a wider
character thus overwrote trailing characters. Tim also
removed a redundant copy of the character into the
line buffer.
getline.c
- gl_cursor_left() and gl->cursor_right() were executing
+ gl_cursor_left() and gl-&gt;cursor_right() were executing
a lot of redundant code, when the existing call to the
recently added gl_place_cursor() function, does all that
is necessary.
@@ -749,7 +2015,7 @@ The most recent modifications are listed first.
getline.c
In gl_get_input_line(), don't redundantly copy the
- start_line if start_line == gl->line.
+ start_line if start_line == gl-&gt;line.
30/04/2001 Version 1.3.0 released.
@@ -819,7 +2085,7 @@ The most recent modifications are listed first.
ef_expand_file().
I also fixed the example in the man page, which cited
- exp->file instead of exp->files, and changed the
+ exp-&gt;file instead of exp-&gt;files, and changed the
dangerous name 'exp' with 'expn'.
keytab.c:
Key-binding tables start with 100 elements, and are
@@ -1071,7 +2337,7 @@ The most recent modifications are listed first.
doing it again is fast.
man3/pca_lookup_file.3
I added a man page documenting the new PathCache module.
- man3/<many-new-files>.3
+ man3/&lt;many-new-files&gt;.3
I have added man pages for all of the functions in each
of the modules. These 1-line pages use the .so directive
to redirect nroff to the man page of the parent module.
@@ -1237,7 +2503,7 @@ The most recent modifications are listed first.
details.
getline.c man/gl_get_line.3
- Markus noted that my choice of M-< for the default
+ Markus noted that my choice of M-&lt; for the default
binding of read-from-file, could be confusing, since
readline binds this to beginning-of-history. I have
thus rebound it to ^X^F (ie. like find-file in emacs).
@@ -1245,7 +2511,7 @@ The most recent modifications are listed first.
getline.c history.c history.h man/gl_get_line.3
I have now implemented equivalents of the readline
beginning-of-history and end-of-history actions.
- These are bound to M-< and M-> respectively.
+ These are bound to M-&lt; and M-&gt; respectively.
history.c history.h
I Moved the definition of the GlHistory type, and
@@ -1257,7 +2523,7 @@ The most recent modifications are listed first.
getline.c man/gl_get_line.3
I added a "read-from-file" action function and bound it
- by default to M-<. This causes gl_get_line() to
+ by default to M-&lt;. This causes gl_get_line() to
temporarily return input from the file who's name
precedes the cursor.
@@ -1492,4 +2758,4 @@ The most recent modifications are listed first.
In the description of the ~/.teclarc configuration file,
I had omitted the 'bind' command word in the example
entry. I have now remedied this.
-</PRE></BODY>
+</pre></body></html>
diff --git a/libtecla-1.6.1/html/cpl_complete_word.html b/libtecla-1.6.1/html/cpl_complete_word.html
new file mode 100644
index 0000000..0c976c0
--- /dev/null
+++ b/libtecla-1.6.1/html/cpl_complete_word.html
@@ -0,0 +1,382 @@
+<head>
+<title>Manual Page</title>
+</head>
+<body>
+<pre>
+<a href="cpl_complete_word.html"><b>cpl_complete_word</b></a> <a href="cpl_complete_word.html"><b>cpl_complete_word</b></a>
+
+
+
+</pre><h2>NAME</h2><pre>
+ cpl_complete_word, cfc_file_start, cfc_literal_escapes,
+ cfc_set_check_fn, cpl_add_completion, cpl_file_completions,
+ cpl_last_error, cpl_list_completions, cpl_recall_matches,
+ cpl_record_error, del_CplFileConf, del_WordCompletion, new_CplFileConf,
+ new_WordCompletion - lookup possible completions for a word
+
+</pre><h2>SYNOPSIS</h2><pre>
+ #include &lt;stdio.h&gt;
+ #include &lt;libtecla.h&gt;
+
+ WordCompletion *new_WordCompletion(void);
+
+ WordCompletion *del_WordCompletion(WordCompletion *cpl);
+
+
+ #define CPL_MATCH_FN(fn) int (fn)(WordCompletion *cpl, \
+ void *data, \
+ const char *line, \
+ int word_end)
+ typedef CPL_MATCH_FN(CplMatchFn);
+
+ CPL_MATCH_FN(cpl_file_completions);
+
+
+ CplMatches *cpl_complete_word(WordCompletion *cpl,
+ const char *line,
+ int word_end, void *data,
+ CplMatchFn *match_fn);
+
+ CplMatches *cpl_recall_matches(WordCompletion *cpl);
+
+ int cpl_list_completions(CplMatches *result, FILE *fp,
+ int term_width);
+
+ int cpl_add_completion(WordCompletion *cpl,
+ const char *line, int word_start,
+ int word_end, const char *suffix,
+ const char *type_suffix,
+ const char *cont_suffix);
+
+ void cpl_record_error(WordCompletion *cpl,
+ const char *errmsg);
+
+ const char *cpl_last_error(WordCompletion *cpl);
+
+
+ #define CPL_CHECK_FN(fn) int (fn)(void *data, \
+ const char *pathname)
+
+ typedef CPL_CHECK_FN(CplCheckFn);
+
+ CPL_CHECK_FN(cpl_check_exe);
+
+ CplFileConf *new_CplFileConf(void);
+
+ CplFileConf *del_CplFileConf(CplFileConf *cfc);
+
+ void cfc_literal_escapes(CplFileConf *cfc, int literal);
+
+ void cfc_file_start(CplFileConf *cfc, int start_index);
+
+ void cfc_set_check_fn(CplFileConf *cfc, CplCheckFn *chk_fn,
+ void *chk_data);
+
+
+
+</pre><h2>DESCRIPTION</h2><pre>
+ The cpl_complete_word() function is part of the tecla library (see the
+ <a href="libtecla.html"><b>libtecla</b></a> man page). It is usually called behind the
+ scenes by <a href="gl_get_line.html"><b>gl_get_line</b></a>, but can also be called sepa-
+ rately.
+
+ Given an input line containing an incomplete word to be completed, it
+ calls a user-provided callback function (or the provided file-comple-
+ tion callback function) to look up all possible completion suffixes for
+ that word. The callback function is expected to look backward in the
+ line, starting from the specified cursor position, to find the start of
+ the word to be completed, then to look up all possible completions of
+ that word and record them, one at a time by calling cpl_add_comple-
+ tion().
+
+
+ Descriptions of the functions of this module are as follows:
+
+ WordCompletion *new_WordCompletion(void)
+
+ This function creates the resources used by the cpl_complete_word()
+ function. In particular, it maintains the memory that is used to return
+ the results of calling cpl_complete_word().
+
+ WordCompletion *del_WordCompletion(WordCompletion *cpl)
+
+ This function deletes the resources that were returned by a previous
+ call to new_WordCompletion(). It always returns NULL (ie. a deleted
+ object). It does nothing if the cpl argument is NULL.
+
+ The callback functions which lookup possible completions should be
+ defined with the following macro (which is defined in libtecla.h).
+
+ #define CPL_MATCH_FN(fn) int (fn)(WordCompletion *cpl, \
+ void *data, \
+ const char *line, \
+ int word_end)
+
+ Functions of this type are called by cpl_complete_word(), and all of
+ the arguments of the callback are those that were passed to said func-
+ tion. In particular, the line argument contains the input line contain-
+ ing the word to be completed, and word_end is the index of the charac-
+ ter that follows the last character of the incomplete word within this
+ string. The callback is expected to look backwards from word_end for
+ the start of the incomplete word. What constitutes the start of a word
+ clearly depends on the application, so it makes sense for the callback
+ to take on this responsibility. For example, the builtin filename com-
+ pletion function looks backwards until it hits an unescaped space, or
+ the start of the line. Having found the start of the word, the call-
+ back should then lookup all possible completions of this word, and
+ record each completion via separate calls to cpl_add_completion(). If
+ the callback needs access to an application-specific symbol table, it
+ can pass it and any other data that it needs, via the data argument.
+ This removes any need for globals.
+
+ The callback function should return 0 if no errors occur. On failure it
+ should return 1, and register a terse description of the error by call-
+ ing cpl_record_error().
+
+ void cpl_record_error(WordCompletion *cpl,
+ const char *errmsg);
+
+ The last error message recorded by calling cpl_record_error(), can sub-
+ sequently be queried by calling cpl_last_error(), as described later.
+
+ int cpl_add_completion(WordCompletion *cpl,
+ const char *line, int word_start,
+ int word_end, const char *suffix,
+ const char *type_suffix,
+ const char *cont_suffix);
+
+ The cpl_add_completion() function is called zero or more times by the
+ completion callback function to record each possible completion in the
+ specified WordCompletion object. These completions are subsequently
+ returned by cpl_complete_word(), as described later. The cpl, line, and
+ word_end arguments should be those that were passed to the callback
+ function. The word_start argument should be the index within the input
+ line string of the start of the word that is being completed. This
+ should equal word_end if a zero-length string is being completed. The
+ suffix argument is the string that would have to be appended to the
+ incomplete word to complete it. If this needs any quoting (eg. the
+ addition of backslashes before special charaters) to be valid within
+ the displayed input line, this should be included. A copy of the suffix
+ string is allocated internally, so there is no need to maintain your
+ copy of the string after cpl_add_completion() returns.
+
+ Note that in the array of possible completions which the cpl_com-
+ plete_word() function returns, the suffix recorded by cpl_add_comple-
+ tion() is listed along with the concatentation of this suffix with the
+ word that lies between word_start and word_end in the input line.
+
+ The type_suffix argument specifies an optional string to be appended to
+ the completion if it is displayed as part of a list of completions by
+ cpl_list_completions(). The intention is that this indicate to the user
+ the type of each completion. For example, the file completion function
+ places a directory separator after completions that are directories, to
+ indicate their nature to the user. Similary, if the completion were a
+ function, you could indicate this to the user by setting type_suffix to
+ "()". Note that the type_suffix string isn't copied, so if the argument
+ isn't a literal string between speech marks, be sure that the string
+ remains valid for at least as long as the results of cpl_com-
+ plete_word() are needed.
+
+ The cont_suffix is a continuation suffix to append to the completed
+ word in the input line if this is the only completion. This is some-
+ thing that isn't part of the completion itself, but that gives the user
+ an indication about how they might continue to extend the token. For
+ example, the file-completion callback function adds a directory separa-
+ tor if the completed word is a directory. If the completed word were a
+ function name, you could similarly aid the user by arranging for an
+ open parenthesis to be appended.
+
+ CplMatches *cpl_complete_word(WordCompletion *cpl,
+ const char *line,
+ int word_end, void *data,
+ CplMatchFn *match_fn);
+
+ The cpl_complete_word() is normally called behind the scenes by
+ <a href="gl_get_line.html"><b>gl_get_line</b></a>, but can also be called separately if you
+ separately allocate a WordCompletion object. It performs word comple-
+ tion, as described at the beginning of this section. Its first argument
+ is a resource object previously returned by new_WordCompletion(). The
+ line argument is the input line string, containing the word to be com-
+ pleted. The word_end argument contains the index of the character in
+ the input line, that just follows the last character of the word to be
+ completed. When called by gl_get_line(), this is the character over
+ which the user pressed TAB. The match_fn argument is the function
+ pointer of the callback function which will lookup possible completions
+ of the word, as described above, and the data argument provides a way
+ for the application to pass arbitrary data to the callback function.
+
+ If no errors occur, the cpl_complete_word() function returns a pointer
+ to a CplMatches container, as defined below. This container is allo-
+ cated as part of the cpl object that was passed to cpl_complete_word(),
+ and will thus change on each call which uses the same cpl argument.
+
+ typedef struct {
+ char *completion; /* A matching completion */
+ /* string */
+ char *suffix; /* The part of the */
+ /* completion string which */
+ /* would have to be */
+ /* appended to complete the */
+ /* original word. */
+ const char *type_suffix; /* A suffix to be added when */
+ /* listing completions, to */
+ /* indicate the type of the */
+ /* completion. */
+ } CplMatch;
+
+ typedef struct {
+ char *suffix; /* The common initial part */
+ /* of all of the completion */
+ /* suffixes. */
+ const char *cont_suffix; /* Optional continuation */
+ /* string to be appended to */
+ /* the sole completion when */
+ /* nmatch==1. */
+ CplMatch *matches; /* The array of possible */
+ /* completion strings, */
+ /* sorted into lexical */
+ /* order. */
+ int nmatch; /* The number of elements in */
+ /* the above matches[] */
+ /* array. */
+ } CplMatches;
+
+ If an error occurs during completion, cpl_complete_word() returns NULL.
+ A description of the error can be acquired by calling the
+ cpl_last_error() function.
+
+ const char *cpl_last_error(WordCompletion *cpl);
+
+ The cpl_last_error() function returns a terse description of the error
+ which occurred on the last call to cpl_complete_word() or cpl_add_com-
+ pletion().
+
+ CplMatches *cpl_recall_matches(WordCompletion *cpl);
+
+ As a convenience, the return value of the last call to cpl_com-
+ plete_word() can be recalled at a later time by calling
+ cpl_recall_matches(). If cpl_complete_word() returned NULL, so will
+ cpl_recall_matches().
+
+ int cpl_list_completions(CplMatches *result, FILE *fp,
+ int terminal_width);
+
+ When the cpl_complete_word() function returns multiple possible comple-
+ tions, the cpl_list_completions() function can be called upon to list
+ them, suitably arranged across the available width of the terminal. It
+ arranges for the displayed columns of completions to all have the same
+ width, set by the longest completion. It also appends the type_suffix
+ strings that were recorded with each completion, thus indicating their
+ types to the user.
+
+
+</pre><h2>THE BUILT-IN FILENAME-COMPLETION CALLBACK</h2><pre>
+ By default the <a href="gl_get_line.html"><b>gl_get_line</b></a> function, passes the follow-
+ ing completion callback function to cpl_complete_word(). This function
+ can also be used separately, either by sending it to cpl_com-
+ plete_word(), or by calling it directly from your own completion call-
+ back function.
+
+ CPL_MATCH_FN(cpl_file_completions);
+
+ Certain aspects of the behavior of this callback can be changed via its
+ data argument. If you are happy with its default behavior you can pass
+ NULL in this argument. Otherwise it should be a pointer to a CplFile-
+ Conf object, previously allocated by calling new_CplFileConf().
+
+ CplFileConf *new_CplFileConf(void);
+
+ CplFileConf objects encapsulate the configuration parameters of
+ cpl_file_completions(). These parameters, which start out with default
+ values, can be changed by calling the accessor functions described
+ below.
+
+ By default, the cpl_file_completions() callback function searches back-
+ wards for the start of the filename being completed, looking for the
+ first un-escaped space or the start of the input line. If you wish to
+ specify a different location, call cfc_file_start() with the index at
+ which the filename starts in the input line. Passing start_index=-1 re-
+ enables the default behavior.
+
+ void cfc_file_start(CplFileConf *cfc, int start_index);
+
+ By default, when cpl_file_completions() looks at a filename in the
+ input line, each lone backslash in the input line is interpreted as
+ being a special character which removes any special significance of the
+ character which follows it, such as a space which should be taken as
+ part of the filename rather than delimiting the start of the filename.
+ These backslashes are thus ignored while looking for completions, and
+ subsequently added before spaces, tabs and literal backslashes in the
+ list of completions. To have unescaped backslashes treated as normal
+ characters, call cfc_literal_escapes() with a non-zero value in its
+ literal argument.
+
+ void cfc_literal_escapes(CplFileConf *cfc, int literal);
+
+ By default, cpl_file_completions() reports all files who's names start
+ with the prefix that is being completed. If you only want a selected
+ subset of these files to be reported in the list of completions, you
+ can arrange this by providing a callback function which takes the full
+ pathname of a file, and returns 0 if the file should be ignored, or 1
+ if the file should be included in the list of completions. To register
+ such a function for use by cpl_file_completions(), call
+ cfc_set_check_fn(), and pass it a pointer to the function, together
+ with a pointer to any data that you would like passed to this callback
+ whenever it is called. Your callback can make its decisions based on
+ any property of the file, such as the filename itself, whether the file
+ is readable, writable or executable, or even based on what the file
+ contains.
+
+ #define CPL_CHECK_FN(fn) int (fn)(void *data, \
+ const char *pathname)
+ typedef CPL_CHECK_FN(CplCheckFn);
+
+ void cfc_set_check_fn(CplFileConf *cfc,
+ CplCheckFn *chk_fn, void *chk_data);
+
+ The cpl_check_exe() function is a provided callback of the above type,
+ for use with cpl_file_completions(). It returns non-zero if the file-
+ name that it is given represents a normal file that the user has exe-
+ cute permission to. You could use this to have cpl_file_completions()
+ only list completions of executable files.
+
+ When you have finished with a CplFileConf variable, you can pass it to
+ the del_CplFileConf() destructor function to reclaim its memory.
+
+ CplFileConf *del_CplFileConf(CplFileConf *cfc);
+
+
+
+</pre><h2>THREAD SAFETY</h2><pre>
+ In multi-threaded programs, you should use the libtecla_r.a version of
+ the library. This uses POSIX reentrant functions where available (hence
+ the _r suffix), and disables features that rely on non-reentrant system
+ functions. In the case of this module, the only disabled feature is
+ username completion in ~username/ expressions, in cpl_file_comple-
+ tions().
+
+ Using the libtecla_r.a version of the library, it is safe to use the
+ facilities of this module in multiple threads, provided that each
+ thread uses a separately allocated WordCompletion object. In other
+ words, if two threads want to do word completion, they should each call
+ new_WordCompletion() to allocate their own completion objects.
+
+
+</pre><h2>FILES</h2><pre>
+ libtecla.a - The tecla library
+ libtecla.h - The tecla header file.
+
+
+</pre><h2>SEE ALSO</h2><pre>
+ <a href="libtecla.html"><b>libtecla</b></a>, <a href="gl_get_line.html"><b>gl_get_line</b></a>, <a href="ef_expand_file.html"><b>ef_expand_file</b></a>,
+ <a href="pca_lookup_file.html"><b>pca_lookup_file</b></a>
+
+
+</pre><h2>AUTHOR</h2><pre>
+ Martin Shepherd (mcs@astro.caltech.edu)
+
+
+
+ <a href="cpl_complete_word.html"><b>cpl_complete_word</b></a>
+</pre>
+</body>
diff --git a/libtecla-1.6.1/html/ef_expand_file.html b/libtecla-1.6.1/html/ef_expand_file.html
new file mode 100644
index 0000000..c780cf6
--- /dev/null
+++ b/libtecla-1.6.1/html/ef_expand_file.html
@@ -0,0 +1,213 @@
+<head>
+<title>Manual Page</title>
+</head>
+<body>
+<pre>
+<a href="ef_expand_file.html"><b>ef_expand_file</b></a> <a href="ef_expand_file.html"><b>ef_expand_file</b></a>
+
+
+
+</pre><h2>NAME</h2><pre>
+ ef_expand_file, del_ExpandFile, ef_last_error, ef_list_expansions,
+ new_ExpandFile - expand filenames containing ~user/$envvar and wildcard
+ expressions
+
+</pre><h2>SYNOPSIS</h2><pre>
+ #include &lt;libtecla.h&gt;
+
+ ExpandFile *new_ExpandFile(void);
+
+ ExpandFile *del_ExpandFile(ExpandFile *ef);
+
+ FileExpansion *ef_expand_file(ExpandFile *ef,
+ const char *path,
+ int pathlen);
+
+ int ef_list_expansions(FileExpansion *result, FILE *fp,
+ int term_width);
+
+ const char *ef_last_error(ExpandFile *ef);
+
+
+</pre><h2>DESCRIPTION</h2><pre>
+ The ef_expand_file() function is part of the tecla library (see the
+ <a href="libtecla.html"><b>libtecla</b></a> man page). It expands a specified filename,
+ converting ~user/ and ~/ expressions at the start of the filename to
+ the corresponding home directories, replacing $envvar with the value of
+ the corresponding environment variable, and then, if there are any
+ wildcards, matching these against existing filenames. Backslashes in
+ the input filename are interpreted as escaping any special meanings of
+ the characters that follow them. Only backslahes that are themselves
+ preceded by backslashes are preserved in the expanded filename.
+
+ In the presence of wildcards, the returned list of filenames only
+ includes the names of existing files which match the wildcards. Other-
+ wise, the original filename is returned after expansion of tilde and
+ dollar expressions, and the result is not checked against existing
+ files. This mimics the file-globbing behavior of the unix tcsh shell.
+
+ The supported wildcards and their meanings are:
+ * - Match any sequence of zero or more characters.
+ ? - Match any single character.
+ [chars] - Match any single character that appears in
+ 'chars'. If 'chars' contains an expression of
+ the form a-b, then any character between a and
+ b, including a and b, matches. The '-'
+ character looses its special meaning as a
+ range specifier when it appears at the start
+ of the sequence of characters. The ']'
+ character also looses its significance as the
+ terminator of the range expression if it
+ appears immediately after the opening '[', at
+ which point it is treated one of the
+ characters of the range. If you want both '-'
+ and ']' to be part of the range, the '-'
+ should come first and the ']' second.
+
+ [^chars] - The same as [chars] except that it matches any
+ single character that doesn't appear in
+ 'chars'.
+
+ Note that wildcards never match the initial dot in filenames that start
+ with '.'. The initial '.' must be explicitly specified in the filename.
+ This again mimics the globbing behavior of most unix shells, and its
+ rational is based in the fact that in unix, files with names that start
+ with '.' are usually hidden configuration files, which are not listed
+ by default by the ls command.
+
+ The following is a complete example of how to use the file expansion
+ function.
+
+ #include &lt;stdio.h&gt;
+ #include &lt;libtecla.h&gt;
+
+ int main(int argc, char *argv[])
+ {
+ ExpandFile *ef; /* The expansion resource object */
+ char *filename; /* The filename being expanded */
+ FileExpansion *expn; /* The results of the expansion */
+ int i;
+
+ ef = new_ExpandFile();
+ if(!ef)
+ return 1;
+
+ for(arg = *(argv++); arg; arg = *(argv++)) {
+ if((expn = ef_expand_file(ef, arg, -1)) == NULL) {
+ fprintf(stderr, "Error expanding %s (%s).\n", arg,
+ ef_last_error(ef));
+ } else {
+ printf("%s matches the following files:\n", arg);
+ for(i=0; i&lt;expn-&gt;nfile; i++)
+ printf(" %s\n", expn-&gt;files[i]);
+ }
+ }
+
+ ef = del_ExpandFile(ef);
+ return 0;
+ }
+
+ Descriptions of the functions used above are as follows:
+
+ ExpandFile *new_ExpandFile(void)
+
+ This function creates the resources used by the ef_expand_file() func-
+ tion. In particular, it maintains the memory that is used to record the
+ array of matching filenames that is returned by ef_expand_file(). This
+ array is expanded as needed, so there is no built in limit to the num-
+ ber of files that can be matched.
+
+ ExpandFile *del_ExpandFile(ExpandFile *ef)
+
+ This function deletes the resources that were returned by a previous
+ call to new_ExpandFile(). It always returns NULL (ie a deleted object).
+ It does nothing if the ef argument is NULL.
+
+ A container of the following type is returned by ef_expand_file().
+
+ typedef struct {
+ int exists; /* True if the files in files[] exist */
+ int nfile; /* The number of files in files[] */
+ char **files; /* An array of 'nfile' filenames. */
+ } FileExpansion;
+
+ FileExpansion *ef_expand_file(ExpandFile *ef,
+ const char *path,
+ int pathlen)
+
+ The ef_expand_file() function performs filename expansion, as docu-
+ mented at the start of this section. Its first argument is a resource
+ object returned by new_ExpandFile(). A pointer to the start of the
+ filename to be matched is passed via the path argument. This must be a
+ normal NUL terminated string, but unless a length of -1 is passed in
+ pathlen, only the first pathlen characters will be used in the filename
+ expansion. If the length is specified as -1, the whole of the string
+ will be expanded.
+
+ The function returns a pointer to a container who's contents are the
+ results of the expansion. If there were no wildcards in the filename,
+ the nfile member will be 1, and the exists member should be queried if
+ it is important to know if the expanded file currently exists or not.
+ If there were wildcards, then the contained files[] array will contain
+ the names of the nfile existing files that matched the wildcarded file-
+ name, and the exists member will have the value 1. Note that the
+ returned container belongs to the specified ef object, and its contents
+ will change on each call, so if you need to retain the results of more
+ than one call to ef_expand_file(), you should either make a private
+ copy of the returned results, or create multiple file-expansion
+ resource objects via multiple calls to new_ExpandFile().
+
+ On error, NULL is returned, and an explanation of the error can be
+ determined by calling ef_last_error(ef).
+
+ const char *ef_last_error(ExpandFile *ef)
+
+ This function returns the message which describes the error that
+ occurred on the last call to ef_expand_file(), for the given (Expand-
+ File *ef) resource object.
+
+ int ef_list_expansions(FileExpansion *result, FILE *fp,
+ int terminal_width);
+
+ The ef_list_expansions() function provides a convenient way to list the
+ filename expansions returned by ef_expand_file(). Like the unix ls com-
+ mand, it arranges the filenames into equal width columns, each column
+ having the width of the largest file. The number of columns used is
+ thus determined by the length of the longest filename, and the speci-
+ fied terminal width. Beware that filenames that are longer than the
+ specified terminal width are printed without being truncated, so output
+ longer than the specified terminal width can occur. The list is written
+ to the stdio stream specified by the fp argument.
+
+
+</pre><h2>THREAD SAFETY</h2><pre>
+ In multi-threaded programs, you should use the libtecla_r.a version of
+ the library. This uses POSIX reentrant functions where available (hence
+ the _r suffix), and disables features that rely on non-reentrant system
+ functions. Currently there are no features disabled in this module.
+
+ Using the libtecla_r.a version of the library, it is safe to use the
+ facilities of this module in multiple threads, provided that each
+ thread uses a separately allocated ExpandFile object. In other words,
+ if two threads want to do file expansion, they should each call
+ new_ExpandFile() to allocate their own file-expansion objects.
+
+
+</pre><h2>FILES</h2><pre>
+ libtecla.a - The tecla library
+ libtecla.h - The tecla header file.
+
+
+</pre><h2>SEE ALSO</h2><pre>
+ <a href="libtecla.html"><b>libtecla</b></a>, <a href="gl_get_line.html"><b>gl_get_line</b></a>, <a href="cpl_complete_word.html"><b>cpl_complete_word</b></a>,
+ <a href="pca_lookup_file.html"><b>pca_lookup_file</b></a>
+
+
+</pre><h2>AUTHOR</h2><pre>
+ Martin Shepherd (mcs@astro.caltech.edu)
+
+
+
+ <a href="ef_expand_file.html"><b>ef_expand_file</b></a>
+</pre>
+</body>
diff --git a/libtecla-1.6.1/html/enhance.html b/libtecla-1.6.1/html/enhance.html
new file mode 100644
index 0000000..62b4e2f
--- /dev/null
+++ b/libtecla-1.6.1/html/enhance.html
@@ -0,0 +1,75 @@
+<head>
+<title>Manual Page</title>
+</head>
+<body>
+<pre>
+<a href="enhance.html"><b>enhance</b></a> <a href="enhance.html"><b>enhance</b></a>
+
+
+
+</pre><h2>NAME</h2><pre>
+ enhance - A program that adds command-line editing to third party pro-
+ grams.
+
+</pre><h2>SYNOPSIS</h2><pre>
+ enhance command [ argument ... ]
+
+
+</pre><h2>DESCRIPTION</h2><pre>
+ The enhance program provides enhanced command-line editing facilities
+ to users of third party applications, to which one doesn't have any
+ source code. It does this by placing a pseudo-terminal between the
+ application and the real terminal. It uses the tecla command-line edit-
+ ing library to read input from the real terminal, then forwards each
+ just completed input line to the application via the pseudo-terminal.
+ All output from the application is forwarded back unchanged to the real
+ terminal.
+
+ Whenever the application stops generating output for more than a tenth
+ of a second, the enhance program treats the latest incomplete output
+ line as the prompt, and redisplays any incompleted input line that the
+ user has typed after it. Note that the small delay, which is impercep-
+ tible to the user, isn't necessary for correct operation of the pro-
+ gram. It is just an optimization, designed to stop the input line from
+ being redisplayed so often that it slows down output.
+
+ Note that the user-level command-line editing facilities provided by
+ the Tecla library are documented in the <a href="tecla.html"><b>tecla</b></a> man page
+
+
+</pre><h2>DEFICIENCIES</h2><pre>
+ The one major problem that hasn't been solved yet, is how to deal with
+ applications that change whether typed input is echo'd by their con-
+ trolling terminal. For example, programs that ask for a password, such
+ as ftp and telnet, temporarily tell their controlling terminal not to
+ echo what the user types. Since this request goes to the application
+ side of the psuedo terminal, the enhance program has no way of knowing
+ that this has happened, and continues to echo typed input to its con-
+ trolling terminal, while the user types their password.
+
+ Furthermore, before executing the host application, the enhance program
+ initially sets the pseudo terminal to noecho mode, so that everything
+ that it sends to the program doesn't get redundantly echoed. If a pro-
+ gram that switches to noecho mode explicitly restores echoing after-
+ wards, rather than restoring the terminal modes that were previously in
+ force, then subsequently, every time that you enter a new input line, a
+ duplicate copy will be displayed on the next line.
+
+
+</pre><h2>FILES</h2><pre>
+ libtecla.a - The tecla library.
+ ~/.teclarc - The tecla personal customization file.
+
+
+</pre><h2>SEE ALSO</h2><pre>
+ <a href="tecla.html"><b>tecla</b></a>, <a href="libtecla.html"><b>libtecla</b></a>
+
+
+</pre><h2>AUTHOR</h2><pre>
+ Martin Shepherd (mcs@astro.caltech.edu)
+
+
+
+ <a href="enhance.html"><b>enhance</b></a>
+</pre>
+</body>
diff --git a/libtecla-1.6.1/html/gl_get_line.html b/libtecla-1.6.1/html/gl_get_line.html
new file mode 100644
index 0000000..3df39d6
--- /dev/null
+++ b/libtecla-1.6.1/html/gl_get_line.html
@@ -0,0 +1,1996 @@
+<head>
+<title>Manual Page</title>
+</head>
+<body>
+<pre>
+<a href="gl_get_line.html"><b>gl_get_line</b></a> <a href="gl_get_line.html"><b>gl_get_line</b></a>
+
+
+
+</pre><h2>NAME</h2><pre>
+ gl_get_line, new_GetLine, del_GetLine, gl_customize_completion,
+ gl_change_terminal, gl_configure_getline, gl_load_history, gl_save_his-
+ tory, gl_group_history, gl_show_history, gl_watch_fd, gl_inactiv-
+ ity_timeout, gl_terminal_size, gl_set_term_size, gl_resize_history,
+ gl_limit_history, gl_clear_history, gl_toggle_history, gl_lookup_his-
+ tory, gl_state_of_history, gl_range_of_history, gl_size_of_history,
+ gl_echo_mode, gl_replace_prompt, gl_prompt_style, gl_ignore_signal,
+ gl_trap_signal, gl_last_signal, gl_completion_action, gl_display_text,
+ gl_return_status, gl_error_message, gl_catch_blocked, gl_list_signals,
+ gl_bind_keyseq, gl_erase_terminal, gl_automatic_history, gl_append_his-
+ tory, gl_query_char, gl_read_char - allow the user to compose an input
+ line
+
+</pre><h2>SYNOPSIS</h2><pre>
+ #include &lt;stdio.h&gt;
+ #include &lt;libtecla.h&gt;
+
+ GetLine *new_GetLine(size_t linelen, size_t histlen);
+
+ GetLine *del_GetLine(GetLine *gl);
+
+ char *gl_get_line(GetLine *gl, const char *prompt,
+ const char *start_line, int start_pos);
+
+ int gl_query_char(GetLine *gl, const char *prompt,
+ char defchar);
+
+ int gl_read_char(GetLine *gl);
+
+ int gl_customize_completion(GetLine *gl, void *data,
+ CplMatchFn *match_fn);
+
+ int gl_change_terminal(GetLine *gl, FILE *input_fp,
+ FILE *output_fp, const char *term);
+
+ int gl_configure_getline(GetLine *gl,
+ const char *app_string,
+ const char *app_file,
+ const char *user_file);
+
+ int gl_bind_keyseq(GetLine *gl, GlKeyOrigin origin,
+ const char *keyseq, const char *action);
+
+ int gl_save_history(GetLine *gl, const char *filename,
+ const char *comment, int max_lines);
+
+ int gl_load_history(GetLine *gl, const char *filename,
+ const char *comment);
+
+ int gl_watch_fd(GetLine *gl, int fd, GlFdEvent event,
+ GlFdEventFn *callback, void *data);
+
+ int gl_inactivity_timeout(GetLine *gl, GlTimeoutFn *callback,
+ void *data, unsigned long sec,
+ unsigned long nsec);
+
+ int gl_group_history(GetLine *gl, unsigned stream);
+
+ int gl_show_history(GetLine *gl, FILE *fp,
+ const char *fmt, int all_groups,
+ int max_lines);
+
+ int gl_resize_history(GetLine *gl, size_t bufsize);
+
+ void gl_limit_history(GetLine *gl, int max_lines);
+
+ void gl_clear_history(GetLine *gl, int all_groups);
+
+ void gl_toggle_history(GetLine *gl, int enable);
+
+ GlTerminalSize gl_terminal_size(GetLine *gl,
+ int def_ncolumn,
+ int def_nline);
+
+ int gl_set_term_size(GetLine *gl, int ncolumn, int nline);
+
+ int gl_lookup_history(GetLine *gl, unsigned long id,
+ GlHistoryLine *hline);
+
+ void gl_state_of_history(GetLine *gl,
+ GlHistoryState *state);
+
+ void gl_range_of_history(GetLine *gl,
+ GlHistoryRange *range);
+
+ void gl_size_of_history(GetLine *gl, GlHistorySize *size);
+
+ void gl_echo_mode(GetLine *gl, int enable);
+
+ void gl_replace_prompt(GetLine *gl, const char *prompt);
+
+ void gl_prompt_style(GetLine *gl, GlPromptStyle style);
+
+ int gl_ignore_signal(GetLine *gl, int signo);
+
+ int gl_trap_signal(GetLine *gl, int signo, unsigned flags,
+ GlAfterSignal after, int errno_value);
+
+ int gl_last_signal(GetLine *gl);
+
+ int gl_completion_action(GetLine *gl,
+ void *data, CplMatchFn *match_fn,
+ int list_only, const char *name,
+ const char *keyseq);
+
+ int gl_register_action(GetLine *gl, void *data,
+ GlActionFn *fn, const char *name,
+ const char *keyseq);
+
+ int gl_display_text(GetLine *gl, int indentation,
+ const char *prefix,
+ const char *suffix, int fill_char,
+ int def_width, int start,
+ const char *string);
+
+ GlReturnStatus gl_return_status(GetLine *gl);
+
+ const char *gl_error_message(GetLine *gl, char *buff,
+ size_t n);
+
+ void gl_catch_blocked(GetLine *gl);
+
+ int gl_list_signals(GetLine *gl, sigset_t *set);
+
+ int gl_append_history(GetLine *gl, const char *line);
+
+ int gl_automatic_history(GetLine *gl, int enable);
+
+
+
+</pre><h2>DESCRIPTION</h2><pre>
+ The gl_get_line() function is part of the tecla library (see the libte-
+ cla(@LIBR_MANEXT@) man page). If the user is typing at a terminal, each
+ call prompts them for an line of input, then provides interactive edit-
+ ing facilities, similar to those of the unix tcsh shell. In addition to
+ simple command-line editing, it supports recall of previously entered
+ command lines, TAB completion of file names, and in-line wild-card
+ expansion of filenames. Documentation of both the user-level command-
+ line editing features and all user configuration options, can be found
+ in the <a href="tecla.html"><b>tecla</b></a> man page. This man page concerns itself
+ with documentation for programmers interested in using this library in
+ their application.
+
+
+</pre><h2>AN EXAMPLE</h2><pre>
+ The following shows a complete example of how to use the gl_get_line()
+ function to get input from the user:
+
+ #include &lt;stdio.h&gt;
+ #include &lt;locale.h&gt;
+ #include &lt;libtecla.h&gt;
+
+ int main(int argc, char *argv[])
+ {
+ char *line; /* The line that the user typed */
+ GetLine *gl; /* The gl_get_line() resource object */
+
+ setlocale(LC_CTYPE, ""); /* Adopt the user's choice */
+ /* of character set. */
+
+ gl = new_GetLine(1024, 2048);
+ if(!gl)
+ return 1;
+
+ while((line=gl_get_line(gl, "$ ", NULL, -1)) != NULL &amp;&amp;
+ strcmp(line, "exit\n") != 0)
+ printf("You typed: %s\n", line);
+
+ gl = del_GetLine(gl);
+ return 0;
+ }
+
+ In the example, first the resources needed by the gl_get_line() func-
+ tion are created by calling new_GetLine(). This allocates the memory
+ used in subsequent calls to the gl_get_line() function, including the
+ history buffer for recording previously entered lines. Then one or more
+ lines are read from the user, until either an error occurs, or the user
+ types exit. Then finally the resources that were allocated by new_Get-
+ Line(), are returned to the system by calling del_GetLine(). Note the
+ use of the NULL return value of del_GetLine() to make gl NULL. This is
+ a safety precaution. If the program subsequently attempts to pass gl to
+ gl_get_line(), said function will complain, and return an error,
+ instead of attempting to use the deleted resource object.
+
+
+
+</pre><h2>THE FUNCTIONS USED IN THE EXAMPLE</h2><pre>
+ The descriptions of the functions used in the example are as follows:
+
+ GetLine *new_GetLine(size_t linelen, size_t histlen)
+
+ This function creates the resources used by the gl_get_line() function
+ and returns an opaque pointer to the object that contains them. The
+ maximum length of an input line is specified via the linelen argument,
+ and the number of bytes to allocate for storing history lines is set by
+ the histlen argument. History lines are stored back-to-back in a single
+ buffer of this size. Note that this means that the number of history
+ lines that can be stored at any given time, depends on the lengths of
+ the individual lines. If you want to place an upper limit on the num-
+ ber of lines that can be stored, see the gl_limit_history() function
+ described later. If you don't want history at all, specify histlen as
+ zero, and no history buffer will be allocated.
+
+ On error, a message is printed to stderr and NULL is returned.
+
+ GetLine *del_GetLine(GetLine *gl)
+
+ This function deletes the resources that were returned by a previous
+ call to new_GetLine(). It always returns NULL (ie a deleted object). It
+ does nothing if the gl argument is NULL.
+
+ char *gl_get_line(GetLine *gl, const char *prompt,
+ const char *start_line, int start_pos);
+
+ The gl_get_line() function can be called any number of times to read
+ input from the user. The gl argument must have been previously returned
+ by a call to new_GetLine(). The prompt argument should be a normal NUL
+ terminated string, specifying the prompt to present the user with. By
+ default prompts are displayed literally, but if enabled with the
+ gl_prompt_style() function (see later), prompts can contain directives
+ to do underlining, switch to and from bold fonts, or turn highlighting
+ on and off.
+
+ If you want to specify the initial contents of the line, for the user
+ to edit, pass the desired string via the start_line argument. You can
+ then specify which character of this line the cursor is initially posi-
+ tioned over, using the start_pos argument. This should be -1 if you
+ want the cursor to follow the last character of the start line. If you
+ don't want to preload the line in this manner, send start_line as NULL,
+ and set start_pos to -1. Note that the line pointer returned by one
+ call to gl_get_line() can be passed back to the next call to
+ gl_get_line() via the start_line. This allows the application to take
+ the last entered line, and if it contains an error, to then present it
+ back to the user for re-editing, with the cursor initially positioned
+ where the error was encountered.
+
+ The gl_get_line() function returns a pointer to the line entered by the
+ user, or NULL on error or at the end of the input. The returned pointer
+ is part of the specified gl resource object, and thus should not be
+ free'd by the caller, or assumed to be unchanging from one call to the
+ next. When reading from a user at a terminal, there will always be a
+ newline character at the end of the returned line. When standard input
+ is being taken from a pipe or a file, there will similarly be a newline
+ unless the input line was too long to store in the internal buffer. In
+ the latter case you should call gl_get_line() again to read the rest of
+ the line. Note that this behavior makes gl_get_line() similar to
+ fgets(). In fact when stdin isn't connected to a termi-
+ nal,gl_get_line() just calls fgets().
+
+
+</pre><h2>THE RETURN STATUS OF GL_GET_LINE</h2><pre>
+ As described above, the gl_get_line() function has two possible return
+ values; a pointer to the completed input line, or NULL. Extra informa-
+ tion about what caused gl_get_line() to return is available both by
+ inspecting errno, and by calling the gl_return_status() function.
+
+
+ GlReturnStatus gl_return_status(GetLine *gl);
+
+
+ The following are the possible enumerated values that this function
+ returns.
+
+
+ GLR_NEWLINE - The last call to gl_get_line()
+ successfully returned a completed
+ input line.
+
+ GLR_BLOCKED - gl_get_line() was in non-blocking
+ server mode, and returned early to
+ avoid blocking the process while
+ waiting for terminal I/O. The
+ gl_pending_io() function can be
+ used to see what type of I/O
+ gl_get_line() was waiting for.
+ (see the <a href="gl_io_mode.html"><b>gl_io_mode</b></a> man page
+ for details).
+
+ GLR_SIGNAL - A signal was caught by
+ gl_get_line() that had an
+ after-signal disposition of
+ GLS_ABORT (See gl_trap_signal()).
+
+ GLR_TIMEOUT - The inactivity timer expired while
+ gl_get_line() was waiting for
+ input, and the timeout callback
+ function returned GLTO_ABORT.
+ See gl_inactivity_timeout() for
+ information about timeouts.
+
+ GLR_FDABORT - An application I/O callack returned
+ GLFD_ABORT (see gl_watch_fd()).
+
+ GLR_EOF - End of file reached. This can happen
+ when input is coming from a file or a
+ pipe, instead of the terminal. It also
+ occurs if the user invokes the
+ list-or-eof or del-char-or-list-or-eof
+ actions at the start of a new line.
+
+ GLR_ERROR - An unexpected error caused
+ gl_get_line() to abort (consult
+ errno and/or
+ gl_error_message() for details.
+
+
+ When gl_return_status() returns GLR_ERROR, and the value of errno isn't
+ sufficient to explain what happened, you can use the gl_error_message()
+ function to request a description of the last error that occurred.
+
+
+ const char *gl_error_message(GetLine *gl, char *buff,
+ size_t n);
+
+
+ The return value is a pointer to the message that occurred. If the buff
+ argument is NULL, this will be a pointer to a buffer within gl, who's
+ value will probably change on the next call to any function associated
+ with gl_get_line(). Otherwise, if a non-NULL buff argument is provided,
+ the error message, including a '\0' terminator, will be written within
+ the first n elements of this buffer, and the return value will be a
+ pointer to the first element of this buffer. If the message won't fit
+ in the provided buffer, it will be truncated to fit.
+
+
+</pre><h2>OPTIONAL PROMPT FORMATTING</h2><pre>
+ Whereas by default the prompt string that you specify is displayed lit-
+ erally, without any special interpretation of the characters within it,
+ the gl_prompt_style() function can be used to enable optional format-
+ ting directives within the prompt.
+
+ void gl_prompt_style(GetLine *gl, GlPromptStyle style);
+
+ The style argument, which specifies the formatting style, can take any
+ of the following values:
+
+ GL_FORMAT_PROMPT - In this style, the formatting
+ directives described below, when
+ included in prompt strings, are
+ interpreted as follows:
+
+ %B - Display subsequent
+ characters with a bold
+ font.
+ %b - Stop displaying characters
+ with the bold font.
+ %F - Make subsequent characters
+ flash.
+ %f - Turn off flashing
+ characters.
+ %U - Underline subsequent
+ characters.
+ %u - Stop underlining
+ characters.
+ %P - Switch to a pale (half
+ brightness) font.
+ %p - Stop using the pale font.
+ %S - Highlight subsequent
+ characters (also known as
+ standout mode).
+ %s - Stop highlighting
+ characters.
+ %V - Turn on reverse video.
+ %v - Turn off reverse video.
+ %% - Display a single %
+ character.
+
+ For example, in this mode, a prompt
+ string like "%UOK%u$ " would
+ display the prompt "OK$ ",
+ but with the OK part
+ underlined.
+
+ Note that although a pair of
+ characters that starts with a %
+ character, but doesn't match any of
+ the above directives is displayed
+ literally, if a new directive is
+ subsequently introduced which does
+ match, the displayed prompt will
+ change, so it is better to always
+ use %% to display a literal %.
+
+ Also note that not all terminals
+ support all of these text
+ attributes, and that some substitute
+ a different attribute for missing
+ ones.
+
+ GL_LITERAL_PROMPT - In this style, the prompt string is
+ printed literally. This is the
+ default style.
+
+
+</pre><h2>ALTERNATE CONFIGURATION SOURCES</h2><pre>
+ As mentioned above, by default users have the option of configuring the
+ behavior of gl_get_line() via a configuration file called .teclarc in
+ their home directories. The fact that all applications share this same
+ configuration file is both an advantage and a disadvantage. In most
+ cases it is an advantage, since it encourages uniformity, and frees the
+ user from having to configure each application separately. In some
+ applications, however, this single means of configuration is a problem.
+ This is particularly true of embedded software, where there's no
+ filesystem to read a configuration file from, and also in applications
+ where a radically different choice of keybindings is needed to emulate
+ a legacy keyboard interface. To cater for such cases, the following
+ function allows the application to control where configuration informa-
+ tion is read from.
+
+
+ int gl_configure_getline(GetLine *gl,
+ const char *app_string,
+ const char *app_file,
+ const char *user_file);
+
+
+ It allows the configuration commands that would normally be read from a
+ user's ~/.teclarc file, to be read from any or none of, a string, an
+ application specific configuration file, and/or a user-specific config-
+ uration file. If this function is called before the first call to
+ gl_get_line(), the default behavior of reading ~/.teclarc on the first
+ call to gl_get_line() is disabled, so all configuration must be
+ achieved using the configuration sources specified with this function.
+
+ If app_string != NULL, then it is interpreted as a string containing
+ one or more configuration commands, separated from each other in the
+ string by embedded newline characters. If app_file != NULL then it is
+ interpreted as the full pathname of an application-specific configura-
+ tion file. If user_file != NULL then it is interpreted as the full
+ pathname of a user-specific configuration file, such as ~/.teclarc. For
+ example, in the following call,
+
+
+ gl_configure_getline(gl, "edit-mode vi \n nobeep",
+ "/usr/share/myapp/teclarc",
+ "~/.teclarc");
+
+
+ the app_string argument causes the calling application to start in vi
+ edit-mode, instead of the default emacs mode, and turns off the use of
+ the terminal bell by the library. It then attempts to read system-wide
+ configuration commands from an optional file called
+ /usr/share/myapp/teclarc, then finally reads user-specific configura-
+ tion commands from an optional .teclarc file in the user's home direc-
+ tory. Note that the arguments are listed in ascending order of prior-
+ ity, with the contents of app_string being potentially overriden by
+ commands in app_file, and commands in app_file potentially being over-
+ riden by commands in user_file.
+
+ You can call this function as many times as needed, the results being
+ cumulative, but note that copies of any filenames specified via the
+ app_file and user_file arguments are recorded internally for subsequent
+ use by the read-init-files key-binding function, so if you plan to call
+ this function multiple times, be sure that the last call specifies the
+ filenames that you want re-read when the user requests that the config-
+ uration files be re-read.
+
+ Individual key sequences can also be bound and unbound using the
+ gl_bind_keyseq() function.
+
+
+ int gl_bind_keyseq(GetLine *gl, GlKeyOrigin origin,
+ const char *keyseq,
+ const char *action);
+
+
+ The origin argument specifies the priority of the binding, according to
+ who it is being established for, and must be one of the following two
+ values.
+
+ GL_USER_KEY - The user requested this key-binding.
+ GL_APP_KEY - This is a default binding set by the
+ application.
+
+ When both user and application bindings for a given key-sequence have
+ been specified, the user binding takes precedence. The application's
+ binding is subsequently reinstated if the user's binding is later
+ unbound via either another to this function, or a call to gl_config-
+ ure_getline().
+
+ The keyseq argument specifies the key-sequence to be bound or unbound,
+ and is expressed in the same way as in a ~/.teclarc configuration file.
+ The action argument must either be a string containing the name of the
+ action to bind the key-sequence to, or it must be NULL or "" to unbind
+ the key-sequence.
+
+
+</pre><h2>CUSTOMIZED WORD COMPLETION</h2><pre>
+ If in your application, you would like to have TAB completion complete
+ other things in addition to or instead of filenames, you can arrange
+ this by registering an alternate completion callback function, via a
+ call to the gl_customize_completion() function.
+
+ int gl_customize_completion(GetLine *gl, void *data,
+ CplMatchFn *match_fn);
+
+ The data argument provides a way for your application to pass arbi-
+ trary, application-specific information to the callback function. This
+ is passed to the callback every time that it is called. It might for
+ example, point to the symbol table from which possible completions are
+ to be sought. The match_fn argument specifies the callback function to
+ be called. The CplMatchFn function type is defined in libtecla.h, as is
+ a CPL_MATCH_FN() macro that you can use to declare and prototype call-
+ back functions. The declaration and responsibilities of callback func-
+ tions are described in depth in the <a href="cpl_complete_word.html"><b>cpl_complete_word</b></a>
+ man page.
+
+ In brief, the callback function is responsible for looking backwards in
+ the input line, back from the point at which the user pressed TAB, to
+ find the start of the word being completed. It then must lookup possi-
+ ble completions of this word, and record them one by one in the Word-
+ Completion object that is passed to it as an argument, by calling the
+ cpl_add_completion() function. If the callback function wishes to pro-
+ vide filename completion in addition to its own specific completions,
+ it has the option of itself calling the builtin file-name completion
+ callback. This also, is documented in the cpl_com-
+ plete_word(@FUNC_MANEXT@) man page.
+
+ Note that if you would like gl_get_line() to return the current input
+ line when a successful completion is been made, you can arrange this
+ when you call cpl_add_completion(), by making the last character of the
+ continuation suffix a newline character. If you do this, the input line
+ will be updated to display the completion, together with any
+ contiuation suffix up to the newline character, then gl_get_line() will
+ return this input line.
+
+
+ If, for some reason, your callback function needs to write something to
+ the terminal, it must call gl_normal_io() before doing so. This will
+ start a new line after the input line that is currently being edited,
+ reinstate normal terminal I/O, and tell gl_get_line() that the input
+ line will need to be redrawn when the callback returns.
+
+
+</pre><h2>ADDING COMPLETION ACTIONS</h2><pre>
+ In the previous section the ability to customize the behavior of the
+ only default completion action, complete-word, was described. In this
+ section the ability to install additional action functions, so that
+ different types of word completion can be bound to different key-
+ sequences, is described. This is achieved by using the gl_comple-
+ tion_action() function.
+
+
+ int gl_completion_action(GetLine *gl,
+ void *data, CplMatchFn *match_fn,
+ int list_only, const char *name,
+ const char *keyseq);
+
+
+ The data and match_fn arguments are as described in the cpl_com-
+ plete_word man page, and specify the callback function that should be
+ invoked to identify possible completions. The list_only argument
+ determines whether the action that is being defined should attempt to
+ complete the word as far as possible in the input line before display-
+ ing any possible ambiguous completions, or whether it should simply
+ display the list of possible completions without touching the input
+ line. The former option is selected by specifying a value of 0, and the
+ latter by specifying a value of 1. The name argument specifies the name
+ by which configuration files and future invokations of this function
+ should refer to the action. This must either be the name of an existing
+ completion action to be changed, or be a new unused name for a new
+ action. Finally, the keyseq argument specifies the default key-sequence
+ to bind the action to. If this is NULL, no new keysequence will be
+ bound to the action.
+
+ Beware that in order for the user to be able to change the key-sequence
+ that is bound to actions that are installed in this manner, when you
+ call gl_completion_action() to install a given action for the first
+ time, you should do this between calling new_GetLine() and the first
+ call to gl_get_line(). Otherwise, when the user's configuration file
+ is read on the first call to gl_get_line(), the name of the your addi-
+ tional action won't be known, and any reference to it in the configura-
+ tion file will generate an error.
+
+ As discussed for gl_customize_completion(), if your callback function,
+ for some reason, needs to write anything to the terminal, it must call
+ gl_normal_io() before doing so.
+
+
+</pre><h2>DEFINING CUSTOM ACTIONS</h2><pre>
+ Although the built-in key-binding actions are sufficient for the needs
+ of most applications, occasionally a specialized application may need
+ to define one or more custom actions, bound to application-specific
+ key-sequences. For example, a sales application would benefit from hav-
+ ing a key-sequence that displayed the part name that corresponded to a
+ part number preceding the cursor. Such a feature is clearly beyond the
+ scope of the built-in action functions. So for such special cases, the
+ gl_register_action() function is provided.
+
+
+ int gl_register_action(GetLine *gl, void *data,
+ GlActionFn *fn, const char *name,
+ const char *keyseq);
+
+
+ This function lets the application register an external function, fn,
+ that will thereafter be called whenever either the specified key-
+ sequence, keyseq, is entered by the user, or the user enters any other
+ key-sequence that the user subsequently binds to the specified action
+ name, name, in their configuration file. The data argument can be a
+ pointer to anything that the application wishes to have passed to the
+ action function, fn, whenever that function is invoked.
+
+ The action function, fn, should be declared using the following macro,
+ which is defined in libtecla.h.
+
+
+ #define GL_ACTION_FN(fn) GlAfterAction (fn)(GetLine *gl, \
+ void *data, int count, size_t curpos, \
+ const char *line)
+
+
+ The gl and data arguments are those that were previously passed to
+ gl_register_action() when the action function was registered. The count
+ argument is a numeric argument which the user has the option of enter-
+ ing using the digit-argument action, before invoking the action. If the
+ user doesn't enter a number, then the count argument is set to 1. Nomi-
+ nally this argument is interpreted as a repeat count, meaning that the
+ action should be repeated that many times. In practice however, for
+ some actions a repeat count makes little sense. In such cases, actions
+ can either simply ignore the count argument, or use its value for a
+ different purpose.
+
+ A copy of the current input line is passed in the read-only line argu-
+ ment. The current cursor position within this string is given by the
+ index contained in the curpos argument. Note that direct manipulation
+ of the input line and the cursor position is not permitted. This is
+ because the rules dicated by various modes, such as vi mode versus
+ emacs mode, no-echo mode, and insert mode versus overstrike mode etc,
+ make it too complex for an application writer to write a conforming
+ editing action, as well as constrain future changes to the internals of
+ gl_get_line(). A potential solution to this dilema would be to allow
+ the action function to edit the line using the existing editing
+ actions. This is currently under consideration.
+
+ If the action function wishes to write text to the terminal, without
+ this getting mixed up with the displayed text of the input line, or
+ read from the terminal without having to handle raw terminal I/O, then
+ before doing either of these operations, it must temporarily suspend
+ line editing by calling the gl_normal_io() function. This function
+ flushes any pending output to the terminal, moves the cursor to the
+ start of the line that follows the last terminal line of the input
+ line, then restores the terminal to a state that is suitable for use
+ with the C stdio facilities. The latter includes such things as restor-
+ ing the normal mapping of \n to \r\n, and, when in server mode, restor-
+ ing the normal blocking form of terminal I/O. Having called this func-
+ tion, the action function can read from and write to the terminal with-
+ out the fear of creating a mess. It isn't necessary for the action
+ function to restore the original editing environment before it returns.
+ This is done automatically by gl_get_line() after the action function
+ returns. The following is a simple example of an action function which
+ writes the sentence "Hello world" on a new terminal line after the line
+ being edited. When this function returns, the input line is redrawn on
+ the line that follows the "Hello world" line, and line editing resumes.
+
+
+ static GL_ACTION_FN(say_hello_fn)
+ {
+ if(gl_normal_io(gl)) /* Temporarily suspend editing */
+ return GLA_ABORT;
+ printf("Hello world\n");
+ return GLA_CONTINUE;
+ }
+
+
+ Action functions must return one of the following values, to tell
+ gl_get_line() how to procede.
+
+
+ GLA_ABORT - Cause gl_get_line() to return NULL.
+ GLA_RETURN - Cause gl_get_line() to return the
+ completed input line.
+ GLA_CONTINUE - Resume command-line editing.
+
+
+ Note that the name argument of gl_register_action() specifies the name
+ by which a user can refer to the action in their configuration file.
+ This allows them to re-bind the action to an alternate key-seqeunce. In
+ order for this to work, it is necessary to call gl_register_action()
+ between calling new_GetLine() and the first call to gl_get_line().
+
+
+</pre><h2>HISTORY FILES</h2><pre>
+ To save the contents of the history buffer before quitting your appli-
+ cation, and subsequently restore them when you next start the applica-
+ tion, the following functions are provided.
+
+
+ int gl_save_history(GetLine *gl, const char *filename,
+ const char *comment, int max_lines);
+ int gl_load_history(GetLine *gl, const char *filename,
+ const char *comment);
+
+
+ The filename argument specifies the name to give the history file when
+ saving, or the name of an existing history file, when loading. This may
+ contain home-directory and environment variable expressions, such as
+ "~/.myapp_history" or "$HOME/.myapp_history".
+
+ Along with each history line, extra information about it, such as when
+ it was entered by the user, and what its nesting level is, is recorded
+ as a comment preceding the line in the history file. Writing this as a
+ comment allows the history file to double as a command file, just in
+ case you wish to replay a whole session using it. Since comment pre-
+ fixes differ in different languages, the comment argument is provided
+ for specifying the comment prefix. For example, if your application
+ were a unix shell, such as the bourne shell, you would specify "#"
+ here. Whatever you choose for the comment character, you must specify
+ the same prefix to gl_load_history() that you used when you called
+ gl_save_history() to write the history file.
+
+ The max_lines must be either -1 to specify that all lines in the his-
+ tory list be saved, or a positive number specifying a ceiling on how
+ many of the most recent lines should be saved.
+
+ Both fuctions return non-zero on error, after writing an error message
+ to stderr. Note that gl_load_history() does not consider the non-exis-
+ tence of a file to be an error.
+
+
+</pre><h2>MULTIPLE HISTORY LISTS</h2><pre>
+ If your application uses a single GetLine object for entering many dif-
+ ferent types of input lines, you may wish gl_get_line() to distinguish
+ the different types of lines in the history list, and only recall lines
+ that match the current type of line. To support this requirement,
+ gl_get_line() marks lines being recorded in the history list with an
+ integer identifier chosen by the application. Initially this identi-
+ fier is set to 0 by new_GetLine(), but it can be changed subsequently
+ by calling gl_group_history().
+
+
+ int gl_group_history(GetLine *gl, unsigned id);
+
+
+ The integer identifier id can be any number chosen by the application,
+ but note that gl_save_history() and gl_load_history() preserve the
+ association between identifiers and historical input lines between pro-
+ gram invokations, so you should choose fixed identifiers for the dif-
+ ferent types of input line used by your application.
+
+ Whenever gl_get_line() appends a new input line to the history list,
+ the current history identifier is recorded with it, and when it is
+ asked to recall a historical input line, it only recalls lines that are
+ marked with the current identifier.
+
+
+</pre><h2>DISPLAYING HISTORY</h2><pre>
+ The history list can be displayed by calling gl_show_history().
+
+
+ int gl_show_history(GetLine *gl, FILE *fp,
+ const char *fmt,
+ int all_groups,
+ int max_lines);
+
+
+ This displays the current contents of the history list to the stdio
+ output stream fp. If the max_lines argument is greater than or equal to
+ zero, then no more than this number of the most recent lines will be
+ displayed. If the all_groups argument is non-zero, lines from all his-
+ tory groups are displayed. Otherwise just those of the currently
+ selected history group are displayed. The format string argument, fmt,
+ determines how the line is displayed. This can contain arbitrary char-
+ acters which are written verbatim, interleaved with any of the follow-
+ ing format directives:
+
+ %D - The date on which the line was originally
+ entered, formatted like 2001-11-20.
+ %T - The time of day when the line was entered,
+ formatted like 23:59:59.
+ %N - The sequential entry number of the line in
+ the history buffer.
+ %G - The number of the history group which the
+ line belongs to.
+ %% - A literal % character.
+ %H - The history line itself.
+
+ Thus a format string like "%D %T %H0 would output something like:
+
+ 2001-11-20 10:23:34 Hello world
+
+ Note the inclusion of an explicit newline character in the format
+ string.
+
+
+</pre><h2>LOOKING UP HISTORY</h2><pre>
+ The gl_lookup_history() function allows the calling application to look
+ up lines in the history list.
+
+
+ typedef struct {
+ const char *line; /* The requested historical */
+ /* line. */
+ unsigned group; /* The history group to which */
+ /* the line belongs. */
+ time_t timestamp; /* The date and time at which */
+ /* the line was originally */
+ /* entered. */
+ } GlHistoryLine;
+
+ int gl_lookup_history(GetLine *gl, unsigned long id,
+ GlHistoryLine *hline);
+
+
+ The id argument indicates which line to look up, where the first line
+ that was entered in the history list after new_GetLine() was called, is
+ denoted by 0, and subsequently entered lines are denoted with succes-
+ sively higher numbers. Note that the range of lines currently preserved
+ in the history list can be queried by calling the gl_range_of_history()
+ function, described later. If the requested line is in the history
+ list, the details of the line are recorded in the variable pointed to
+ by the hline argument, and 1 is returned. Otherwise 0 is returned, and
+ the variable pointed to by hline is left unchanged.
+
+ Beware that the string returned in hline-&gt;line is part of the history
+ buffer, so it must not be modified by the caller, and will be recycled
+ on the next call to any function that takes gl as its argument. There-
+ fore you should make a private copy of this string if you need to keep
+ it around.
+
+
+</pre><h2>MANUAL HISTORY ARCHIVAL</h2><pre>
+ By default, whenever a line is entered by the user, it is automatically
+ appended to the history list, just before gl_get_line() returns the
+ line to the caller. This is convenient for the majority of applica-
+ tions, but there are also applications that need finer grained control
+ over what gets added to the history list. In such cases, the automatic
+ addition of entered lines to the history list can be turned off by
+ calling the gl_automatic_history() function.
+
+
+ int gl_automatic_history(GetLine *gl, int enable);
+
+
+ If this function is called with its enable argument set to 0,
+ gl_get_line() won't automatically archive subsequently entered lines.
+ Automatic archiving can be reenabled at a later time, by calling this
+ function again, with its enable argument set to 1. While automatic
+ history archiving is disabled, the calling application can use the
+ gl_append_history() to append lines to the history list as needed.
+
+
+ int gl_append_history(GetLine *gl, const char *line);
+
+
+ The line argument specifies the line to be added to the history list.
+ This must be a normal ' ' terminated string. If this string contains
+ any newline characters, the line that gets archived in the history list
+ will be terminated by the first of these. Otherwise it will be termi-
+ nated by the ' ' terminator. If the line is longer than the maximum
+ input line length, that was specified when new_GetLine() was called,
+ when the line is recalled, it will get truncated to the actual
+ gl_get_line() line length.
+
+ If successful, gl_append_history() returns 0. Otherwise it returns non-
+ zero, and sets errno to one of the following values.
+
+
+ EINVAL - One of the arguments passed to
+ gl_append_history() was NULL.
+ ENOMEM - The specified line was longer than the allocated
+ size of the history buffer (as specified when
+ new_GetLine() was called), so it couldn't be
+ archived.
+
+
+ A textual description of the error can optionally be obtained by call-
+ ing gl_error_message(). Note that after such an error, the history list
+ remains in a valid state to receive new history lines, so there is lit-
+ tle harm in simply ignoring the return status of gl_append_history().
+
+
+</pre><h2>MISCELLANEOUS HISTORY CONFIGURATION</h2><pre>
+ If you wish to change the size of the history buffer that was origi-
+ nally specified in the call to new_GetLine(), you can do so with the
+ gl_resize_history() function.
+
+
+ int gl_resize_history(GetLine *gl, size_t histlen);
+
+
+ The histlen argument specifies the new size in bytes, and if you spec-
+ ify this as 0, the buffer will be deleted.
+
+ As mentioned in the discussion of new_GetLine(), the number of lines
+ that can be stored in the history buffer, depends on the lengths of the
+ individual lines. For example, a 1000 byte buffer could equally store
+ 10 lines of average length 100 bytes, or 2 lines of average length 50
+ bytes. Although the buffer is never expanded when new lines are added,
+ a list of pointers into the buffer does get expanded when needed to
+ accomodate the number of lines currently stored in the buffer. To place
+ an upper limit on the number of lines in the buffer, and thus a ceiling
+ on the amount of memory used in this list, you can call the
+ gl_limit_history() function.
+
+
+ void gl_limit_history(GetLine *gl, int max_lines);
+
+
+ The max_lines should either be a positive number &gt;= 0, specifying an
+ upper limit on the number of lines in the buffer, or be -1 to cancel
+ any previously specified limit. When a limit is in effect, only the
+ max_lines most recently appended lines are kept in the buffer. Older
+ lines are discarded.
+
+ To discard lines from the history buffer, use the gl_clear_history()
+ function.
+
+ void gl_clear_history(GetLine *gl, int all_groups);
+
+ The all_groups argument tells the function whether to delete just the
+ lines associated with the current history group (see gl_group_his-
+ tory()), or all historical lines in the buffer.
+
+ The gl_toggle_history() function allows you to toggle history on and
+ off without losing the current contents of the history list.
+
+
+ void gl_toggle_history(GetLine *gl, int enable);
+
+
+ Setting the enable argument to 0 turns off the history mechanism, and
+ setting it to 1 turns it back on. When history is turned off, no new
+ lines will be added to the history list, and history lookup key-bind-
+ ings will act as though there is nothing in the history buffer.
+
+
+</pre><h2>QUERYING HISTORY INFORMATION</h2><pre>
+ The configured state of the history list can be queried with the
+ gl_history_state() function.
+
+
+ typedef struct {
+ int enabled; /* True if history is enabled */
+ unsigned group; /* The current history group */
+ int max_lines; /* The current upper limit on the */
+ /* number of lines in the history */
+ /* list, or -1 if unlimited. */
+ } GlHistoryState;
+
+ void gl_state_of_history(GetLine *gl,
+ GlHistoryState *state);
+
+ On return, the status information is recorded in the variable pointed
+ to by the state argument.
+
+ The gl_range_of_history() function returns the number and range of
+ lines in the history list.
+
+
+ typedef struct {
+ unsigned long oldest; /* The sequential entry number */
+ /* of the oldest line in the */
+ /* history list. */
+ unsigned long newest; /* The sequential entry number */
+ /* of the newest line in the */
+ /* history list. */
+ int nlines; /* The number of lines in the */
+ /* history list. */
+ } GlHistoryRange;
+
+ void gl_range_of_history(GetLine *gl, GlHistoryRange *range);
+
+ The return values are recorded in the variable pointed to by the range
+ argument. If the nlines member of this structure is greater than zero,
+ then the oldest and newest members report the range of lines in the
+ list, and newest=oldest+nlines-1. Otherwise they are both zero.
+
+ The gl_size_of_history() function returns the total size of the history
+ buffer and the amount of the buffer that is currently occupied.
+
+ typedef struct {
+ size_t size; /* The size of the history buffer */
+ /* (bytes). */
+ size_t used; /* The number of bytes of the */
+ /* history buffer that are */
+ /* currently occupied. */
+ } GlHistorySize;
+
+ void gl_size_of_history(GetLine *gl, GlHistorySize *size);
+
+ On return, the size information is recorded in the variable pointed to
+ by the size argument.
+
+
+</pre><h2>CHANGING TERMINALS</h2><pre>
+ The new_GetLine() constructor function assumes that input is to be read
+ from stdin, and output written to stdout. The following function allows
+ you to switch to different input and output streams.
+
+ int gl_change_terminal(GetLine *gl, FILE *input_fp,
+ FILE *output_fp, const char *term);
+
+ The gl argument is the object that was returned by new_GetLine(). The
+ input_fp argument specifies the stream to read from, and output_fp
+ specifies the stream to be written to. Only if both of these refer to a
+ terminal, will interactive terminal input be enabled. Otherwise
+ gl_get_line() will simply call fgets() to read command input. If both
+ streams refer to a terminal, then they must refer to the same terminal,
+ and the type of this terminal must be specified via the term argument.
+ The value of the term argument is looked up in the terminal information
+ database (terminfo or termcap), in order to determine which special
+ control sequences are needed to control various aspects of the termi-
+ nal. new_GetLine() for example, passes the return value of
+ getenv("TERM") in this argument. Note that if one or both of input_fp
+ and output_fp don't refer to a terminal, then it is legal to pass NULL
+ instead of a terminal type.
+
+ Note that if you want to pass file descriptors to gl_change_terminal(),
+ you can do this by creating stdio stream wrappers using the POSIX
+ fdopen() function.
+
+
+</pre><h2>EXTERNAL EVENT HANDLING</h2><pre>
+ By default, gl_get_line() doesn't return until either a complete input
+ line has been entered by the user, or an error occurs. In programs that
+ need to watch for I/O from other sources than the terminal, there are
+ two options.
+
+
+ 1. Use the functions described in the
+ <a href="gl_io_mode.html"><b>gl_io_mode</b></a> man page to switch
+ gl_get_line() into non-blocking server mode. In this mode,
+ gl_get_line() becomes a non-blocking, incremental
+ line-editing function that can safely be called from
+ an external event loop. Although this is a very
+ versatile method, it involves taking on some
+ responsibilities that are normally performed behind
+ the scenes by gl_get_line().
+
+ 2. While gl_get_line() is waiting for keyboard
+ input from the user, you can ask it to also watch for
+ activity on arbitrary file descriptors, such as
+ network sockets, pipes etc, and have it call functions
+ of your choosing when activity is seen. This works on
+ any system that has the select() system call,
+ which is most, if not all flavors of unix.
+
+
+ Registering a file descriptor to be watched by gl_get_line() involves
+ calling the gl_watch_fd() function.
+
+
+ int gl_watch_fd(GetLine *gl, int fd, GlFdEvent event,
+ GlFdEventFn *callback, void *data);
+
+
+ If this returns non-zero, then it means that either your arguments are
+ invalid, or that this facility isn't supported on the host system.
+
+ The fd argument is the file descriptor to be watched. The event argu-
+ ment specifies what type of activity is of interest, chosen from the
+ following enumerated values:
+
+
+ GLFD_READ - Watch for the arrival of data to be read.
+ GLFD_WRITE - Watch for the ability to write to the file
+ descriptor without blocking.
+ GLFD_URGENT - Watch for the arrival of urgent
+ out-of-band data on the file descriptor.
+
+
+ The callback argument is the function to call when the selected
+ activity is seen. It should be defined with the following macro, which
+ is defined in libtecla.h.
+
+
+ #define GL_FD_EVENT_FN(fn) GlFdStatus (fn)(GetLine *gl, \
+ void *data, int fd, \
+ GlFdEvent event)
+
+ The data argument of the gl_watch_fd() function is passed to the call-
+ back function for its own use, and can point to anything you like,
+ including NULL. The file descriptor and the event argument are also
+ passed to the callback function, and this potentially allows the same
+ callback function to be registered to more than one type of event
+ and/or more than one file descriptor. The return value of the callback
+ function should be one of the following values.
+
+
+ GLFD_ABORT - Tell gl_get_line() to abort. When this
+ happens, gl_get_line() returns
+ NULL, and a following call to
+ gl_return_status() will return
+ GLR_FDABORT. Note that if the
+ application needs errno always to
+ have a meaningful value when
+ gl_get_line() returns NULL,
+ the callback function should set
+ errno appropriately.
+ GLFD_REFRESH - Redraw the input line then continue
+ waiting for input. Return this if
+ your callback wrote to the terminal.
+ GLFD_CONTINUE - Continue to wait for input, without
+ redrawing the line.
+
+ Note that before calling the callback, gl_get_line() blocks most sig-
+ nals, and leaves its own signal handlers installed, so if you need to
+ catch a particular signal you will need to both temporarily install
+ your own signal handler, and unblock the signal. Be sure to re-block
+ the signal (if it was originally blocked) and reinstate the original
+ signal handler, if any, before returning.
+
+
+
+ If the callback function needs to read or write to the terminal, it
+ should ideally first call gl_normal_io(gl) to temporarily suspend line
+ editing. This will restore the terminal to canonical, blocking-I/O,
+ mode, and move the cursor to the start of a new terminal line. Later,
+ when the callback returns, gl_get_line() will notice that gl_nor-
+ mal_io() was called, redisplay the input line and resume editing. Note
+ that in this case the return values, GLFD_REFRESH and GLFD_CONTINUE are
+ equivalent.
+
+
+
+ To support cases where the callback function calls a third-party func-
+ tion which occasionally and u0prisicre-enabledesbeforee themicallback
+ automatic conversion of "0 to "
+ function is called. If the callack knows that the third-party function
+ wrote to the terminal, it should then return the GLFD_REFRESH return
+ value, to tell gl_get_line() to redisplay the input line.
+
+
+
+ To remove a callback function that you previously registered for a
+ given file descriptor and event, simply call gl_watch_fd() with the
+ same file descriptor and event arguments, but with a callback argument
+ of 0. The data argument is ignored in this case.
+
+
+</pre><h2>SETTING AN INACTIVITY TIMEOUT</h2><pre>
+ On systems with the select() system call, the gl_inactivity_timeout()
+ function can be used to set or cancel an inactivity timeout. Inactivity
+ in this case refers both to keyboard input, and to I/O on any file
+ descriptors registered by prior and subsequent calls to gl_watch_fd().
+ On oddball systems that don't have select(), this call has no effect.
+
+
+ int gl_inactivity_timeout(GetLine *gl, GlTimeoutFn *callback,
+ void *data, unsigned long sec,
+ unsigned long nsec);
+
+
+ The timeout is specified in the form of an integral number of seconds
+ and an integral number of nanoseconds, via the sec and nsec arguments
+ respectively. Subsequently, whenever no activity is seen for this time
+ period, the function specified via the callback argument is called. The
+ data argument of gl_inactivity_timeout() is passed verbatim to this
+ callback function whenever it is invoked, and can thus be used to pass
+ arbitrary application-specific information to the callback. The follow-
+ ing macro is provided in libtecla.h for applications to use to declare
+ and prototype timeout callback functions.
+
+
+ #define GL_TIMEOUT_FN(fn) \
+ GlAfterTimeout (fn)(GetLine *gl, void *data)
+
+
+ On returning, the application's callback is expected to return one of
+ the following enumerators to tell gl_get_line() how to procede after
+ the timeout has been handled by the callback.
+
+
+ GLTO_ABORT - Tell gl_get_line() to abort. When
+ this happens, gl_get_line() will
+ return NULL, and a following call
+ to gl_return_status() will return
+ GLR_TIMEOUT. Note that if the
+ application needs errno always to
+ have a meaningful value when
+ gl_get_line() returns NULL,
+ the callback function should set
+ errno appropriately.
+ GLTO_REFRESH - Redraw the input line, then continue
+ waiting for input. You should return
+ this value if your callback wrote to the
+ terminal without having first called
+ gl_normal_io(gl).
+ GLTO_CONTINUE - In normal blocking-I/O mode, continue to
+ wait for input, without redrawing the
+ user's input line.
+ In non-blocking server I/O mode (see
+ <a href="gl_io_mode.html"><b>gl_io_mode</b></a>), cause gl_get_line()
+ to act as though I/O blocked. This means
+ that gl_get_line() will immediately
+ return NULL, and a following call
+ to gl_return_status() will return
+ GLR_BLOCKED.
+
+
+ Note that before calling the callback, gl_get_line() blocks most sig-
+ nals, and leaves its own signal handlers installed, so if you need to
+ catch a particular signal you will need to both temporarily install
+ your own signal handler, and unblock the signal. Be sure to re-block
+ the signal (if it was originally blocked) and reinstate the original
+ signal handler, if any, before returning.
+
+
+
+ If the callback function needs to read or write to the terminal, it
+ should ideally first call gl_normal_io(gl) to temporarily suspend line
+ editing. This will restore the terminal to canonical, blocking-I/O,
+ mode, and move the cursor to the start of a new terminal line. Later,
+ when the callback returns, gl_get_line() will notice that gl_nor-
+ mal_io() was called, redisplay the input line and resume editing. Note
+ that in this case the return values, GLTO_REFRESH and GLTO_CONTINUE are
+ equivalent.
+
+
+
+ To support cases where the callback function calls a third-party func-
+ tion which occasionally and u0prisicre-enabledesbeforee themicallback
+ automatic conversion of "0 to "
+ function is called. If the callack knows that the third-party function
+ wrote to the terminal, it should then return the GLTO_REFRESH return
+ value, to tell gl_get_line() to redisplay the input line.
+
+
+
+ Note that although the timeout argument includes a nano-second compo-
+ nent, few computer clocks presently have resolutions that are finer
+ than a few milliseconds, so asking for less than a few milliseconds is
+ equivalent to requesting zero seconds on a lot of systems. If this
+ would be a problem, you should base your timeout selection on the
+ actual resolution of the host clock (eg. by calling
+ sysconf(_SC_CLK_TCK)).
+
+
+
+ To turn off timeouts, simply call gl_inactivity_timeout() with a call-
+ back argument of 0. The data argument is ignored in this case.
+
+
+</pre><h2>SIGNAL HANDLING DEFAULTS</h2><pre>
+ By default, the gl_get_line() function intercepts a number of signals.
+ This is particularly important for signals which would by default ter-
+ minate the process, since the terminal needs to be restored to a usable
+ state before this happens. In this section, the signals that are
+ trapped by default, and how gl_get_line() responds to them, is
+ described. Changing these defaults is the topic of the following sec-
+ tion.
+
+ When the following subset of signals are caught, gl_get_line() first
+ restores the terminal settings and signal handling to how they were
+ before gl_get_line() was called, resends the signal, to allow the call-
+ ing application's signal handlers to handle it, then if the process
+ still exists, gl_get_line() returns NULL and sets errno as specified
+ below.
+
+
+ SIGINT - This signal is generated both by the keyboard
+ interrupt key (usually ^C), and the keyboard
+ break key.
+
+ errno=EINTR
+
+ SIGHUP - This signal is generated when the controlling
+ terminal exits.
+
+ errno=ENOTTY
+
+ SIGPIPE - This signal is generated when a program attempts
+ to write to a pipe who's remote end isn't being
+ read by any process. This can happen for example
+ if you have called gl_change_terminal() to
+ redirect output to a pipe hidden under a pseudo
+ terminal.
+
+ errno=EPIPE
+
+ SIGQUIT - This signal is generated by the keyboard quit
+ key (usually ^\).
+
+ errno=EINTR
+
+ SIGABRT - This signal is generated by the standard C,
+ abort() function. By default it both
+ terminates the process and generates a core
+ dump.
+
+ errno=EINTR
+
+ SIGTERM - This is the default signal that the UN*X
+ kill command sends to processes.
+
+ errno=EINTR
+
+ Note that in the case of all of the above signals, POSIX mandates that
+ by default the process is terminated, with the addition of a core dump
+ in the case of the SIGQUIT signal. In other words, if the calling
+ application doesn't override the default handler by supplying its own
+ signal handler, receipt of the corresponding signal will terminate the
+ application before gl_get_line() returns.
+
+ If gl_get_line() aborts with errno set to EINTR, you can find out what
+ signal caused it to abort, by calling the following function.
+
+ int gl_last_signal(const GetLine *gl);
+
+ This returns the numeric code (eg. SIGINT) of the last signal that was
+ received during the most recent call to gl_get_line(), or -1 if no sig-
+ nals were received.
+
+ On systems that support it, when a SIGWINCH (window change) signal is
+ received, gl_get_line() queries the terminal to find out its new size,
+ redraws the current input line to accomodate the new size, then returns
+ to waiting for keyboard input from the user. Unlike other signals, this
+ signal isn't resent to the application.
+
+ Finally, the following signals cause gl_get_line() to first restore the
+ terminal and signal environment to that which prevailed before
+ gl_get_line() was called, then resend the signal to the application. If
+ the process still exists after the signal has been delivered, then
+ gl_get_line() then re-establishes its own signal handlers, switches the
+ terminal back to raw mode, redisplays the input line, and goes back to
+ awaiting terminal input from the user.
+
+ SIGCONT - This signal is generated when a suspended
+ process is resumed.
+
+ SIGPOLL - On SVR4 systems, this signal notifies the
+ process of an asynchronous I/O event. Note
+ that under 4.3+BSD, SIGIO and SIGPOLL are
+ the same. On other systems, SIGIO is ignored
+ by default, so gl_get_line() doesn't
+ trap it by default.
+
+ SIGPWR - This signal is generated when a power failure
+ occurs (presumably when the system is on a
+ UPS).
+
+ SIGALRM - This signal is generated when a timer
+ expires.
+
+ SIGUSR1 - An application specific signal.
+
+ SIGUSR2 - Another application specific signal.
+
+ SIGVTALRM - This signal is generated when a virtual
+ timer expires (see man setitimer(2)).
+
+ SIGXCPU - This signal is generated when a process
+ exceeds its soft CPU time limit.
+
+ SIGXFSZ - This signal is generated when a process
+ exceeds its soft file-size limit.
+
+ SIGTSTP - This signal is generated by the terminal
+ suspend key, which is usually ^Z, or the
+ delayed terminal suspend key, which is
+ usually ^Y.
+
+ SIGTTIN - This signal is generated if the program
+ attempts to read from the terminal while the
+ program is running in the background.
+
+ SIGTTOU - This signal is generated if the program
+ attempts to write to the terminal while the
+ program is running in the background.
+
+
+ Obviously not all of the above signals are supported on all systems, so
+ code to support them is conditionally compiled into the tecla library.
+
+ Note that if SIGKILL or SIGPOLL, which by definition can't be caught,
+ or any of the hardware generated exception signals, such as SIGSEGV,
+ SIGBUS and SIGFPE, are received and unhandled while gl_get_line() has
+ the terminal in raw mode, the program will be terminated without the
+ terminal having been restored to a usable state. In practice, job-con-
+ trol shells usually reset the terminal settings when a process relin-
+ quishes the controlling terminal, so this is only a problem with older
+ shells.
+
+
+</pre><h2>CUSTOMIZED SIGNAL HANDLING</h2><pre>
+ The previous section listed the signals that gl_get_line() traps by
+ default, and described how it responds to them. This section describes
+ how to both add and remove signals from the list of trapped signals,
+ and how to specify how gl_get_line() should respond to a given signal.
+
+ If you don't need gl_get_line() to do anything in response to a signal
+ that it normally traps, you can tell to gl_get_line() to ignore that
+ signal by calling gl_ignore_signal().
+
+ int gl_ignore_signal(GetLine *gl, int signo);
+
+ The signo argument is the number of the signal (eg. SIGINT) that you
+ want to have ignored. If the specified signal isn't currently one of
+ those being trapped, this function does nothing.
+
+ The gl_trap_signal() function allows you to either add a new signal to
+ the list that gl_get_line() traps, or modify how it responds to a sig-
+ nal that it already traps.
+
+ int gl_trap_signal(GetLine *gl, int signo, unsigned flags,
+ GlAfterSignal after, int errno_value);
+
+ The signo argument is the number of the signal that you wish to have
+ trapped. The flags argument is a set of flags which determine the envi-
+ ronment in which the application's signal handler is invoked, the after
+ argument tells gl_get_line() what to do after the application's signal
+ handler returns, and errno_value tells gl_get_line() what to set errno
+ to if told to abort.
+
+ The flags argument is a bitwise OR of zero or more of the following
+ enumerators:
+
+ GLS_RESTORE_SIG - Restore the caller's signal
+ environment while handling the
+ signal.
+
+ GLS_RESTORE_TTY - Restore the caller's terminal settings
+ while handling the signal.
+
+ GLS_RESTORE_LINE - Move the cursor to the start of the
+ line following the input line before
+ invoking the application's signal
+ handler.
+
+ GLS_REDRAW_LINE - Redraw the input line when the
+ application's signal handler returns.
+
+ GLS_UNBLOCK_SIG - Normally, if the calling program has
+ a signal blocked (man sigprocmask),
+ gl_get_line() does not trap that
+ signal. This flag tells gl_get_line()
+ to trap the signal and unblock it for
+ the duration of the call to
+ gl_get_line().
+
+ GLS_DONT_FORWARD - If this flag is included, the signal
+ will not be forwarded to the signal
+ handler of the calling program.
+
+ Two commonly useful flag combinations are also enumerated as follows:
+
+ GLS_RESTORE_ENV = GLS_RESTORE_SIG | GLS_RESTORE_TTY |
+ GLS_REDRAW_LINE
+
+ GLS_SUSPEND_INPUT = GLS_RESTORE_ENV | GLS_RESTORE_LINE
+
+
+ If your signal handler, or the default system signal handler for this
+ signal, if you haven't overridden it, never either writes to the termi-
+ nal, nor suspends or terminates the calling program, then you can
+ safely set the flags argument to 0.
+
+ If your signal handler always writes to the terminal, reads from it, or
+ suspends or terminates the program, you should specify the flags argu-
+ ment as GL_SUSPEND_INPUT, so that:
+
+ 1. The cursor doesn't get left in the middle of the input
+ line.
+ 2. So that the user can type in input and have it echoed.
+ 3. So that you don't need to end each output line with
+ \r\n, instead of just \n.
+
+ The GL_RESTORE_ENV combination is the same as GL_SUSPEND_INPUT, except
+ that it doesn't move the cursor, and if your signal handler doesn't
+ read or write anything to the terminal, the user won't see any visible
+ indication that a signal was caught. This can be useful if you have a
+ signal handler that only occasionally writes to the terminal, where
+ using GL_SUSPEND_LINE would cause the input line to be unnecessarily
+ duplicated when nothing had been written to the terminal. Such a sig-
+ nal handler, when it does write to the terminal, should be sure to
+ start a new line at the start of its first write, by writing a new line
+ before returning. If the signal arrives while the user is entering a
+ line that only occupies a signal terminal line, or if the cursor is on
+ the last terminal line of a longer input line, this will have the same
+ effect as GL_SUSPEND_INPUT. Otherwise it will start writing on a line
+ that already contains part of the displayed input line. This doesn't
+ do any harm, but it looks a bit ugly, which is why the GL_SUSPEND_INPUT
+ combination is better if you know that you are always going to be writ-
+ ting to the terminal.
+
+ The after argument, which determines what gl_get_line() does after the
+ application's signal handler returns (if it returns), can take any one
+ of the following values:
+
+ GLS_RETURN - Return the completed input line, just as
+ though the user had pressed the return
+ key.
+
+ GLS_ABORT - Cause gl_get_line() to abort. When
+ this happens, gl_get_line() returns
+ NULL, and a following call to
+ gl_return_status() will return
+ GLR_SIGNAL. Note that if the
+ application needs errno always to
+ have a meaningful value when
+ gl_get_line() returns NULL,
+ the callback function should set
+ errno appropriately.
+ GLS_CONTINUE - Resume command line editing.
+
+ The errno_value argument is intended to be combined with the GLS_ABORT
+ option, telling gl_get_line() what to set the standard errno variable
+ to before returning NULL to the calling program. It can also, however,
+ be used with the GL_RETURN option, in case you wish to have a way to
+ distinguish between an input line that was entered using the return
+ key, and one that was entered by the receipt of a signal.
+
+
+</pre><h2>RELIABLE SIGNAL HANDLING</h2><pre>
+ Signal handling is suprisingly hard to do reliably without race condi-
+ tions. In gl_get_line() a lot of care has been taken to allow applica-
+ tions to perform reliable signal handling around gl_get_line(). This
+ section explains how to make use of this.
+
+ As an example of the problems that can arise if the application isn't
+ written correctly, imagine that one's application has a SIGINT signal
+ handler that sets a global flag. Now suppose that the application tests
+ this flag just before invoking gl_get_line(). If a SIGINT signal hap-
+ pens to be received in the small window of time between the statement
+ that tests the value of this flag, and the statement that calls
+ gl_get_line(), then gl_get_line() will not see the signal, and will not
+ be interrupted. As a result, the application won't be able to respond
+ to the signal until the user gets around to finishing entering the
+ input line and gl_get_line() returns. Depending on the application,
+ this might or might not be a disaster, but at the very least it would
+ puzzle the user.
+
+ The way to avoid such problems is to do the following.
+
+ 1. If needed, use the gl_trap_signal() function to
+ configure gl_get_line() to abort when important
+ signals are caught.
+
+ 2. Configure gl_get_line() such that if any of the
+ signals that it catches are blocked when
+ gl_get_line() is called, they will be unblocked
+ automatically during times when gl_get_line() is
+ waiting for I/O. This can be done either
+ on a per signal basis, by calling the
+ gl_trap_signal() function, and specifying the
+ GLS_UNBLOCK attribute of the signal, or globally by
+ calling the gl_catch_blocked() function.
+
+
+ void gl_catch_blocked(GetLine *gl);
+
+
+ This function simply adds the GLS_UNBLOCK attribute
+ to all of the signals that it is currently configured to
+ trap.
+
+ 3. Just before calling gl_get_line(), block delivery
+ of all of the signals that gl_get_line() is
+ configured to trap. This can be done using the POSIX
+ sigprocmask() function in conjunction with the
+ gl_list_signals() function.
+
+
+ int gl_list_signals(GetLine *gl, sigset_t *set);
+
+
+ This function returns the set of signals that it is
+ currently configured to catch in the set argument,
+ which is in the form required by sigprocmask().
+
+ 4. In the example, one would now test the global flag that
+ the signal handler sets, knowing that there is now no
+ danger of this flag being set again until
+ gl_get_line() unblocks its signals while performing
+ I/O.
+
+ 5. Eventually gl_get_line() returns, either because
+ a signal was caught, an error occurred, or the user
+ finished entering their input line.
+
+ 6. Now one would check the global signal flag again, and if
+ it is set, respond to it, and zero the flag.
+
+ 7. Use sigprocmask() to unblock the signals that were
+ blocked in step 3.
+
+ The same technique can be used around certain POSIX signal-aware func-
+ tions, such as sigsetjmp() and sigsuspend(), and in particular, the
+ former of these two functions can be used in conjunction with sig-
+ longjmp() to implement race-condition free signal handling around other
+ long-running system calls. The way to do this, is explained next, by
+ showing how gl_get_line() manages to reliably trap signals around calls
+ to functions like read() and select() without race conditions.
+
+ The first thing that gl_get_line() does, whenever it is called, is to
+ use the POSIX sigprocmask() function to block the delivery of all of
+ the signals that it is currently configured to catch. This is redundant
+ if the application has already blocked them, but it does no harm. It
+ undoes this step just before returning.
+
+ Whenever gl_get_line() needs to call read() or select() to wait for
+ input from the user, it first calls the POSIX sigsetjmp() function,
+ being sure to specify a non-zero value for its savesigs argument. The
+ reason for the latter argument will become clear shortly.
+
+ If sigsetjmp() returns zero, gl_get_line() then does the following.
+
+
+ a. It uses the POSIX sigaction() function to register
+ a temporary signal handler to all of the signals that it
+ is configured to catch. This signal handler does two
+ things.
+
+ 1. It records the number of the signal that was received
+ in a file-scope variable.
+
+ 2. It then calls the POSIX siglongjmp()
+ function using the buffer that was passed to
+ sigsetjmp() for its first argument, and
+ a non-zero value for its second argument.
+
+ When this signal handler is registered, the sa_mask
+ member of the struct sigaction act argument of the
+ call to sigaction() is configured to contain all of
+ the signals that gl_get_line() is catching. This
+ ensures that only one signal will be caught at once by
+ our signal handler, which in turn ensures that multiple
+ instances of our signal handler don't tread on each
+ other's toes.
+
+ b. Now that the signal handler has been set up,
+ gl_get_line() unblocks all of the signals that it
+ is configured to catch.
+
+ c. It then calls the read() or select() system
+ calls to wait for keyboard input.
+
+ d. If this system call returns (ie. no signal is received),
+ gl_get_line() blocks delivery of the signals of
+ interest again.
+
+ e. It then reinstates the signal handlers that were
+ displaced by the one that was just installed.
+
+
+ Alternatively, if sigsetjmp() returns non-zero, this means that one of
+ the signals being trapped was caught while the above steps were execut-
+ ing. When this happens, gl_get_line() does the following.
+
+ First, note that when a call to siglongjmp() causes sigsetjmp() to
+ return, provided that the savesigs argument of sigsetjmp() was non-
+ zero, as specified above, the signal process mask is restored to how it
+ was when sigsetjmp() was called. This is the important difference
+ between sigsetjmp() and the older problematic setjmp(), and is the
+ essential ingredient that makes it possible to avoid signal handling
+ race conditions. Because of this we are guaranteed that all of the
+ signals that we blocked before calling sigsetjmp() are blocked again as
+ soon as any signal is caught. The following statements, which are then
+ executed, are thus guaranteed to be executed without any further sig-
+ nals being caught.
+
+ 1. If so instructed by the gl_get_line() configuration
+ attributes of the signal that was caught,
+ gl_get_line() restores the terminal attributes to
+ the state that they had when gl_get_line() was
+ called. This is particularly important for signals that
+ suspend or terminate the process, since otherwise the
+ terminal would be left in an unusable state.
+
+ 2. It then reinstates the application's signal handlers.
+
+ 3. Then it uses the C standard-library raise()
+ function to re-send the application the signal that
+ was caught.
+
+ 3. Next it unblocks delivery of the signal that we just
+ sent. This results in the signal that was just sent
+ via raise(), being caught by the application's
+ original signal handler, which can now handle it as it
+ sees fit.
+
+ 4. If the signal handler returns (ie. it doesn't terminate
+ the process), gl_get_line() blocks delivery of the
+ above signal again.
+
+ 5. It then undoes any actions performed in the first of the
+ above steps, and redisplays the line, if the signal
+ configuration calls for this.
+
+ 6. gl_get_line() then either resumes trying to
+ read a character, or aborts, depending on the
+ configuration of the signal that was caught.
+
+ What the above steps do in essence is to take asynchronously delivered
+ signals and handle them synchronously, one at a time, at a point in the
+ code where gl_get_line() has complete control over its environment.
+
+
+</pre><h2>THE TERMINAL SIZE</h2><pre>
+ On most systems the combination of the TIOCGWINSZ ioctl and the SIG-
+ WINCH signal is used to maintain an accurate idea of the terminal size.
+ The terminal size is newly queried every time that gl_get_line() is
+ called and whenever a SIGWINCH signal is received.
+
+ On the few systems where this mechanism isn't available, at startup
+ new_GetLine() first looks for the LINES and COLUMNS environment vari-
+ ables. If these aren't found, or they contain unusable values, then if
+ a terminal information database like terminfo or termcap is available,
+ the default size of the terminal is looked up in this database. If this
+ too fails to provide the terminal size, a default size of 80 columns by
+ 24 lines is used.
+
+ Even on systems that do support ioctl(TIOCGWINSZ), if the terminal is
+ on the other end of a serial line, the terminal driver generally has no
+ way of detecting when a resize occurs or of querying what the current
+ size is. In such cases no SIGWINCH is sent to the process, and the
+ dimensions returned by ioctl(TIOCGWINSZ) aren't correct. The only way
+ to handle such instances is to provide a way for the user to enter a
+ command that tells the remote system what the new size is. This command
+ would then call the gl_set_term_size() function to tell gl_get_line()
+ about the change in size.
+
+
+ int gl_set_term_size(GetLine *gl, int ncolumn, int nline);
+
+
+ The ncolumn and nline arguments are used to specify the new dimensions
+ of the terminal, and must not be less than 1. On systems that do sup-
+ port ioctl(TIOCGWINSZ), this function first calls ioctl(TIOCSWINSZ) to
+ tell the terminal driver about the change in size. In non-blocking
+ server-I/O mode, if a line is currently being input, the input line is
+ then redrawn to accomodate the changed size. Finally the new values are
+ recorded in gl for future use by gl_get_line().
+
+ The gl_terminal_size() function allows you to query the current size of
+ the terminal, and install an alternate fallback size for cases where
+ the size isn't available. Beware that the terminal size won't be
+ available if reading from a pipe or a file, so the default values can
+ be important even on systems that do support ways of finding out the
+ terminal size.
+
+ typedef struct {
+ int nline; /* The terminal has nline lines */
+ int ncolumn; /* The terminal has ncolumn columns */
+ } GlTerminalSize;
+
+ GlTerminalSize gl_terminal_size(GetLine *gl,
+ int def_ncolumn,
+ int def_nline);
+
+ This function first updates gl_get_line()'s fallback terminal dimen-
+ sions, then records its findings in the return value.
+
+ The def_ncolumn and def_nline specify the default number of terminal
+ columns and lines to use if the terminal size can't be determined via
+ ioctl(TIOCGWINSZ) or environment variables.
+
+
+</pre><h2>HIDING WHAT YOU TYPE</h2><pre>
+ When entering sensitive information, such as passwords, it is best not
+ to have the text that you are entering echoed on the terminal. Fur-
+ thermore, such text should not be recorded in the history list, since
+ somebody finding your terminal unattended could then recall it, or
+ somebody snooping through your directories could see it in your history
+ file. With this in mind, the gl_echo_mode() function allows you to tog-
+ gle on and off the display and archival of any text that is subse-
+ quently entered in calls to gl_get_line().
+
+
+ int gl_echo_mode(GetLine *gl, int enable);
+
+
+ The enable argument specifies whether entered text should be visible or
+ not. If it is 0, then subsequently entered lines will not be visible on
+ the terminal, and will not be recorded in the history list. If it is 1,
+ then subsequent input lines will be displayed as they are entered, and
+ provided that history hasn't been turned off via a call to gl_tog-
+ gle_history(), then they will also be archived in the history list.
+ Finally, if the enable argument is -1, then the echoing mode is left
+ unchanged, which allows you to non-destructively query the current set-
+ ting via the return value. In all cases, the return value of the func-
+ tion is 0 if echoing was disabled before the function was called, and 1
+ if it was enabled.
+
+ When echoing is turned off, note that although tab completion will
+ invisibly complete your prefix as far as possible, ambiguous comple-
+ tions will not be displayed.
+
+
+</pre><h2>SINGLE CHARACTER QUERIES</h2><pre>
+ Using gl_get_line() to query the user for a single character reply, is
+ inconvenient for the user, since they must hit the enter or return key
+ before the character that they typed is returned to the program. Thus
+ the gl_query_char() function has been provided for single character
+ queries like this.
+
+
+ int gl_query_char(GetLine *gl, const char *prompt,
+ char defchar);
+
+
+ This function displays the specified prompt at the start of a new line,
+ and waits for the user to type a character. When the user types a char-
+ acter, gl_query_char() displays it to the right of the prompt, starts a
+ newline, then returns the character to the calling program. The return
+ value of the function is the character that was typed. If the read had
+ to be aborted for some reason, EOF is returned instead. In the latter
+ case, the application can call the previously documented gl_return_sta-
+ tus(), to find out what went wrong. This could, for example, have been
+ the reception of a signal, or the optional inactivity timer going off.
+
+ If the user simply hits enter, the value of the defchar argument is
+ substituted. This means that when the user hits either newline or
+ return, the character specified in defchar, is displayed after the
+ prompt, as though the user had typed it, as well as being returned to
+ the calling application. If such a replacement is not important, simply
+ pass '0 as the value of defchar.
+
+ If the entered character is an unprintable character, it is displayed
+ symbolically. For example, control-A is displayed as ^A, and characters
+ beyond 127 are displayed in octal, preceded by a backslash.
+
+ As with gl_get_line(), echoing of the entered character can be disabled
+ using the gl_echo_mode() function.
+
+ If the calling process is suspended while waiting for the user to type
+ their response, the cursor is moved to the line following the prompt
+ line, then when the process resumes, the prompt is redisplayed, and
+ gl_query_char() resumes waiting for the user to type a character.
+
+ Note that in non-blocking server mode, (see <a href="gl_io_mode.html"><b>gl_io_mode</b></a>),
+ if an incomplete input line is in the process of being read when
+ gl_query_char() is called, the partial input line is discarded, and
+ erased from the terminal, before the new prompt is displayed. The next
+ call to gl_get_line() will thus start editing a new line.
+
+
+</pre><h2>READING RAW CHARACTERS</h2><pre>
+ Whereas the gl_query_char() function visibly prompts the user for a
+ character, and displays what they typed, the gl_read_char() function
+ reads a signal character from the user, without writing anything to the
+ terminal, or perturbing any incompletely entered input line. This means
+ that it can be called not only from between calls to gl_get_line(), but
+ also from callback functions that the application has registered to be
+ called by gl_get_line().
+
+
+ int gl_read_char(GetLine *gl);
+
+
+ On success, the return value of gl_read_char() is the character that
+ was read. On failure, EOF is returned, and the gl_return_status() func-
+ tion can be called to find out what went wrong. Possibilities include
+ the optional inactivity timer going off, the receipt of a signal that
+ is configured to abort gl_get_line(), or terminal I/O blocking, when in
+ non-blocking server-I/O mode.
+
+ Beware that certain keyboard keys, such as function keys, and cursor
+ keys, usually generate at least 3 characters each, so a single call to
+ gl_read_char() won't be enough to identify such keystrokes.
+
+
+</pre><h2>CLEARING THE TERMINAL</h2><pre>
+ The calling program can clear the terminal by calling gl_erase_termi-
+ nal(). In non-blocking server-I/O mode, this function also arranges for
+ the current input line to be redrawn from scratch when gl_get_line() is
+ next called.
+
+
+ int gl_erase_terminal(GetLine *gl);
+
+
+
+</pre><h2>DISPLAYING TEXT DYNAMICALLY</h2><pre>
+ Between calls to gl_get_line(), the gl_display_text() function provides
+ a convenient way to display paragraphs of text, left-justified and
+ split over one or more terminal lines according to the constraints of
+ the current width of the terminal. Examples of the use of this function
+ may be found in the demo programs, where it is used to display intro-
+ ductions. In those examples the advanced use of optional prefixes, suf-
+ fixes and filled lines to draw a box around the text is also illus-
+ trated.
+
+
+ int gl_display_text(GetLine *gl, int indentation,
+ const char *prefix,
+ const char *suffix, int fill_char,
+ int def_width, int start,
+ const char *string);
+
+ If gl isn't currently connected to a terminal, for example if the out-
+ put of a program that uses gl_get_line() is being piped to another pro-
+ gram or redirected to a file, then the value of the def_width parameter
+ is used as the terminal width.
+
+ The indentation argument specifies the number of characters to use to
+ indent each line of ouput. The fill_char argument specifies the charac-
+ ter that will be used to perform this indentation.
+
+ The prefix argument can either be NULL, or be a string to place at the
+ beginning of each new line (after any indentation). Similarly, the
+ suffix argument can either be NULL, or be a string to place at the end
+ of each line. The suffix is placed flush against the right edge of the
+ terminal, and any space between its first character and the last word
+ on that line is filled with the character specified via the fill_char
+ argument. Normally the fill-character is a space.
+
+ The start argument tells gl_display_text() how many characters have
+ already been written to the current terminal line, and thus tells it
+ the starting column index of the cursor. Since the return value of
+ gl_display_text() is the ending column index of the cursor, by passing
+ the return value of one call to the start argument of the next call, a
+ paragraph that is broken between more than one string can be composed
+ by calling gl_display_text() for each successive portion of the para-
+ graph. Note that literal newline characters are necessary at the end of
+ each paragraph to force a new line to be started.
+
+ On error, gl_display_text() returns -1.
+
+
+</pre><h2>CALLBACK FUNCTION FACILITIES</h2><pre>
+ Unless otherwise stated, callback functions, such as tab completion
+ callbacks and event callbacks should not call any functions in this
+ module. The following functions, however, are designed specifically to
+ be used by callback functions.
+
+ Calling the gl_replace_prompt() function from a callback tells
+ gl_get_line() to display a different prompt when the callback returns.
+ Except in non-blocking server mode, it has no effect if used between
+ calls to gl_get_line(). In non-blocking server mode (see the
+ <a href="gl_io_mode.html"><b>gl_io_mode</b></a> man page, when used between two calls to
+ gl_get_line() that are operating on the same input line, the current
+ input line will be re-drawn with the new prompt on the following call
+ to gl_get_line().
+
+
+ void gl_replace_prompt(GetLine *gl, const char *prompt);
+
+
+
+</pre><h2>INTERNATIONAL CHARACTER SETS</h2><pre>
+ Since libtecla version 1.4.0, gl_get_line() has been 8-bit clean. This
+ means that all 8-bit characters that are printable in the user's cur-
+ rent locale are now displayed verbatim and included in the returned
+ input line. Assuming that the calling program correctly contains a
+ call like the following,
+
+ setlocale(LC_CTYPE, "");
+
+ then the current locale is determined by the first of the environment
+ variables LC_CTYPE, LC_ALL, and LANG, that is found to contain a valid
+ locale name. If none of these variables are defined, or the program
+ neglects to call setlocale, then the default C locale is used, which is
+ US 7-bit ASCII. On most unix-like platforms, you can get a list of
+ valid locales by typing the command:
+
+ locale -a
+
+ at the shell prompt. Further documentation on how the user can make use
+ of this to enter international characters can be found in the
+ <a href="tecla.html"><b>tecla</b></a> man page.
+
+
+</pre><h2>THREAD SAFETY</h2><pre>
+ In a multi-threaded program, you should use the libtecla_r.a version of
+ the library. This uses reentrant versions of system functions, where
+ available. Unfortunately neither terminfo nor termcap were designed to
+ be reentrant, so you can't safely use the functions of the getline mod-
+ ule in multiple threads (you can use the separate file-expansion and
+ word-completion modules in multiple threads, see the corresponding man
+ pages for details). However due to the use of POSIX reentrant functions
+ for looking up home directories etc, it is safe to use this module from
+ a single thread of a multi-threaded program, provided that your other
+ threads don't use any termcap or terminfo functions.
+
+
+</pre><h2>FILES</h2><pre>
+ libtecla.a - The tecla library
+ libtecla.h - The tecla header file.
+ ~/.teclarc - The personal tecla customization file.
+
+
+</pre><h2>SEE ALSO</h2><pre>
+ <a href="libtecla.html"><b>libtecla</b></a>, <a href="gl_io_mode.html"><b>gl_io_mode</b></a>, <a href="tecla.html"><b>tecla</b></a>, <a href="ef_expand_file.html"><b>ef_expand_file</b></a>,
+ <a href="cpl_complete_word.html"><b>cpl_complete_word</b></a>, <a href="pca_lookup_file.html"><b>pca_lookup_file</b></a>
+
+
+</pre><h2>AUTHOR</h2><pre>
+ Martin Shepherd (mcs@astro.caltech.edu)
+
+
+
+ <a href="gl_get_line.html"><b>gl_get_line</b></a>
+</pre>
+</body>
diff --git a/libtecla-1.6.1/html/gl_io_mode.html b/libtecla-1.6.1/html/gl_io_mode.html
new file mode 100644
index 0000000..98c15a7
--- /dev/null
+++ b/libtecla-1.6.1/html/gl_io_mode.html
@@ -0,0 +1,509 @@
+<head>
+<title>Manual Page</title>
+</head>
+<body>
+<pre>
+<a href="gl_io_mode.html"><b>gl_io_mode</b></a> <a href="gl_io_mode.html"><b>gl_io_mode</b></a>
+
+
+
+</pre><h2>NAME</h2><pre>
+ gl_io_mode, gl_raw_io, gl_normal_io, gl_tty_signals, gl_abandon_line,
+ gl_handle_signal, gl_pending_io - How to use gl_get_line() from an
+ external event loop.
+
+</pre><h2>SYNOPSIS</h2><pre>
+ #include &lt;libtecla.h&gt;
+
+ int gl_io_mode(GetLine *gl, GlIOMode mode);
+
+ int gl_raw_io(GetLine *gl);
+
+ int gl_normal_io(GetLine *gl);
+
+ int gl_tty_signals(void (*term_handler)(int),
+ void (*susp_handler)(int),
+ void (*cont_handler)(int),
+ void (*size_handler)(int));
+
+ void gl_abandon_line(GetLine *gl);
+
+ void gl_handle_signal(int signo, GetLine *gl, int ngl);
+
+ GlPendingIO gl_pending_io(GetLine *gl);
+
+
+
+</pre><h2>DESCRIPTION</h2><pre>
+ The gl_get_line() function, which is documented separately in the
+ <a href="gl_get_line.html"><b>gl_get_line</b></a> man page, supports two different I/O modes.
+ These are selected by calling the gl_io_mode() function.
+
+
+ int gl_io_mode(GetLine *gl, GlIOMode mode);
+
+
+ The mode argument of this function specifies the new I/O mode, and must
+ be one of the following.
+
+
+ GL_NORMAL_MODE - Select the normal blocking-I/O mode.
+ In this mode gl_get_line()
+ doesn't return until either an error
+ occurs of the user finishes entering a
+ new line. This mode is the focus of
+ the <a href="gl_get_line.html"><b>gl_get_line</b></a> man page.
+
+ GL_SERVER_MODE - Select non-blocking server I/O mode.
+ In this mode, since non-blocking
+ terminal I/O is used, the entry of
+ each new input line typically requires
+ many calls to gl_get_line() from
+ an external I/O-driven event loop.
+ This mode is the focus of this man
+ page.
+
+
+ Newly created GetLine objects start in normal I/O mode, so to switch to
+ non-blocking server mode requires an initial call to gl_io_mode().
+
+
+</pre><h2>SERVER I/O MODE</h2><pre>
+ In non-blocking server I/O mode, the application is required to have an
+ event loop which calls gl_get_line() whenever the terminal file
+ descriptor can do the type I/O that gl_get_line() is waiting for. To
+ determine which type of I/O gl_get_line() is waiting for, the applica-
+ tion calls the gl_pending_io() function.
+
+
+ GlPendingIO gl_pending_io(GetLine *gl);
+
+
+ The return value of this function is one of the following two enumer-
+ ated values.
+
+
+ GLP_READ - gl_get_line() is waiting to write a
+ character to the terminal.
+
+ GLP_WRITE - gl_get_line() is waiting to read a
+ character from the keyboad.
+
+
+ If the application is using either the select() or poll() system calls
+ to watch for I/O on a group of file descriptors, then it should call
+ the gl_pending_io() function before each call to these functions to see
+ which direction of I/O it should tell them to watch for, and configure
+ their arguments accordingly. In the case of the select() system call,
+ this means using the FD_SET() macro to add the terminal file descriptor
+ either to the set of file descriptors to be watched for readability, or
+ the set to be watched for writability.
+
+ As in normal I/O mode, the return value of gl_get_line() is either a
+ pointer to a completed input line, or NULL. However, whereas in normal
+ I/O mode a NULL return value always means that an error occurred, in
+ non-blocking server mode, NULL is also returned when gl_get_line()
+ can't read or write to the terminal without blocking. Thus in non-
+ blocking server mode, in order to determine when a NULL return value
+ signifies that an error occurred or not, it is necessary to call the
+ gl_return_status() function. If this function returns the enumerated
+ value, GLR_BLOCKED, as documented in the <a href="gl_get_line.html"><b>gl_get_line</b></a> man
+ page, this means that gl_get_line() is waiting for I/O, and no error
+ has occurred.
+
+ When gl_get_line() returns NULL and gl_return_status() indicates that
+ this is due to blocked terminal I/O, the application should call
+ gl_get_line() again when the type of I/O reported by gl_pending_io()
+ becomes possible. The prompt, start_line and start_pos arguments of
+ gl_get_line() will be ignored on these calls. If you need to change
+ the prompt of the line that is currently being edited, then you can
+ call the gl_replace_prompt() function (documented in the
+ <a href="gl_get_line.html"><b>gl_get_line</b></a> man page) between calls to gl_get_line().
+
+
+</pre><h2>GIVING UP THE TERMINAL</h2><pre>
+ A complication that is unique to non-blocking server mode is that it
+ requires that the terminal be left in raw mode between calls to
+ gl_get_line(). If this weren't the case, the external event loop
+ wouldn't be able to detect individual key-presses, and the basic line
+ editing implemented by the terminal driver would clash with the editing
+ provided by gl_get_line(). What this means is that any time that the
+ terminal needs to be used for other things than entering a new input
+ line with gl_get_line(), it needs to be restored to a usable state. In
+ particular, whenever the process is suspended or terminated, the termi-
+ nal must be returned to a normal state. If this isn't done, then
+ depending on the characteristics of the shell that was used to invoke
+ the program, the user may end up with a hung terminal. To this end, the
+ gl_normal_io() function is provided for switching the terminal back to
+ the state that it was in when raw mode was last established.
+
+
+ int gl_normal_io(GetLine *gl);
+
+
+ What this function does is first flush any pending output to the termi-
+ nal, then move the cursor to the start of the terminal line which fol-
+ lows the end of the incompletely entered input line. At this point it
+ is safe to suspend or terminate the process, and it is safe for the
+ application to read and write to the terminal. To resume entry of the
+ input line, the application should call the gl_raw_io() function.
+
+
+ int gl_raw_io(GetLine *gl);
+
+
+ This function starts a new line, redisplays the partially completed
+ input line (if any), restores the cursor position within this line to
+ where it was when gl_normal_io() was called, then switches back to raw,
+ non-blocking terminal mode ready to continue entry of the input line
+ when gl_get_line() is next called.
+
+ Note that in non-blocking server mode, if gl_get_line() is called after
+ a call to gl_normal_io(), without an intervening call to gl_raw_io(),
+ gl_get_line() will call gl_raw_mode() itself, and the terminal will
+ remain in this mode when gl_get_line() returns.
+
+
+</pre><h2>SIGNAL HANDLING</h2><pre>
+ In the previous section it was pointed out that in non-blocking server
+ mode, the terminal must be restored to a sane state whenever a signal
+ is received that either suspends or terminates the process. In normal
+ I/O mode, this is done for you by gl_get_line(), but in non-blocking
+ server mode, since the terminal is left in raw mode between calls to
+ gl_get_line(), this signal handling has to be done by the application.
+ Since there are many signals that can suspend or terminate a process,
+ as well as other signals that are important to gl_get_line(), such as
+ the SIGWINCH signal, which tells it when the terminal size has changed,
+ the gl_tty_signals() function is provided for installing signal han-
+ dlers for all pertinent signals.
+
+
+ int gl_tty_signals(void (*term_handler)(int),
+ void (*susp_handler)(int),
+ void (*cont_handler)(int),
+ void (*size_handler)(int));
+
+
+ What this does is use gl_get_line()'s internal list of signals to
+ assign specified signal handlers to groups of signals. The arguments of
+ this function are as follows.
+
+
+ term_handler - This is the signal handler that is to be
+ used to trap signals that by default
+ terminate any process that receives
+ them (eg. SIGINT or SIGTERM).
+
+ susp_handler - This is the signal handler that is to be
+ used to trap signals that by default
+ suspend any process that receives them,
+ (eg. SIGTSTP or SIGTTOU).
+
+ cont_handler - This is the signal handler that is to be
+ used to trap signals that are usually
+ sent when a process resumes after being
+ suspended (usually SIGCONT). Beware that there is
+ nothing to stop a user from sending one of these
+ signals at other times.
+
+ size_handler - This signal handler is used to trap
+ signals that are sent to processes when
+ their controlling terminals are resized
+ by the user (eg. SIGWINCH).
+
+
+ These arguments can all be the same, if so desired, and you can specify
+ SIG_IGN (ignore this signal) or SIG_DFL (use the system-provided
+ default signal handler) instead of a function where pertinent. In par-
+ ticular, it is rarely useful to trap SIGCONT, so the cont_handler argu-
+ ment will usually be SIG_DFL or SIG_IGN.
+
+ The gl_tty_signals() function uses the POSIX sigaction() function to
+ install these signal handlers, and it is careful to use the sa_mask
+ member of each sigaction structure to ensure that only one of these
+ signals is ever delivered at a time. This guards against different
+ instances of these signal handlers from simultaneously trying to write
+ to common global data, such as a shared sigsetjmp() buffer or a signal-
+ received flag.
+
+ The signal handlers that are installed by this function, should call
+ the gl_handle_signal().
+
+
+ void gl_handle_signal(int signo, GetLine *gl, int ngl);
+
+
+ The signo argument tells this function which signal it is being asked
+ to respond to, and the gl argument should be a pointer to the first
+ element of an array of ngl GetLine objects. If your application only
+ has one of these objects, just pass its pointer as the gl argument and
+ specify ngl as 1.
+
+ Depending on the signal that is being handled, this function does dif-
+ ferent things.
+
+
+ Terminal resize signals (SIGWINCH)
+ If the signal indicates that the terminal was resized, then it arranges
+ for the next call to gl_get_line() to ask the terminal for its new size
+ and redraw the input line accordingly. In order that gl_get_line() be
+ called as soon as possible to do this, gl_handle_signal() also arranges
+ that the next call to gl_pending_io() will return GLP_WRITE. Thus if
+ the application waits for I/O in select() or poll(), then the applica-
+ tion needs to ensure that these functions will be reliably aborted when
+ a signal is caught and handled by the application. More on this below.
+
+
+</pre><h2>Process termination signals.</h2><pre>
+ If the signal that was caught is one of those that by default termi-
+ nates any process that receives it, then gl_handle_signal() does the
+ following steps.
+
+ 1. First it blocks the delivery of all signals that can be
+ blocked (ie. SIGKILL and SIGSTOP can't be blocked)
+
+ 2. Next it calls gl_normal_io() for each of the ngl
+ GetLine objects. Note that this does nothing to any of the
+ GetLine objects that aren't currently in raw mode.
+
+ 3. Next it sets the signal handler of the signal to its default,
+ process-termination disposition.
+
+ 4. Next it re-sends the process the signal that was caught.
+
+ 5. Finally it unblocks delivery of this signal, which
+ results in the process being terminated.
+
+
+</pre><h2>Process suspension signals.</h2><pre>
+ If the default disposition of the signal is to suspend the process, the
+ same steps are executed as for process termination signals, except that
+ when the process is later resumed, gl_handle_signal() continues, and
+ does the following steps.
+
+ 6. It re-blocks delivery of the signal.
+
+ 7. It reinstates the signal handler of the signal to the one
+ that was displaced when its default disposition was substituted.
+
+ 8. For any of the GetLine objects that were in raw mode when
+ gl_handle_signal() was called, gl_handle_signal() then
+ calls gl_raw_io(), to resume entry of the input lines on
+ those terminals.
+
+ 9. Finally, it restores the signal process mask to how it
+ was when gl_handle_signal() was called.
+
+ Note that the process is suspended or terminated using the original
+ signal that was caught, rather than using the uncatchable SIGSTOP and
+ SIGKILL signals. This is important, because when a process is suspended
+ or terminated, the parent of the process may wish to use the status
+ value returned by the wait() system call to figure out which signal was
+ responsible. In particular, most shells use this information to print a
+ corresponding message to the terminal. Users would be rightly confused
+ if when their process received a SIGPIPE signal, the program responded
+ by sending itself a SIGKILL signal, and the shell then printed out the
+ provocative statement, "Killed!".
+
+
+</pre><h2>INTERRUPTING THE EVENT LOOP</h2><pre>
+ If a signal is caught and handled when the application's event loop is
+ waiting in select() or poll(), these functions will be aborted with
+ errno set to EINTR. When this happens the event loop should call
+ gl_pending_io(), before calling select() or poll() again. It should
+ then arrange for select() or poll() to wait for the type of I/O that
+ this reports. This is necessary, because any signal handler which calls
+ gl_handle_signal(), will frequently change the type of I/O that
+ gl_get_line() is waiting for.
+
+ Unfortunately, if a signal arrives between the statements which config-
+ ure the arguments of select() or poll() and the calls to these func-
+ tions, then the signal will not be seen by these functions, which will
+ then not be aborted. If these functions are waiting for keyboard input
+ from the user when the signal is received, and the signal handler
+ arranges to redraw the input line to accomodate a terminal resize or
+ the resumption of the process, then this redisplay will be end up being
+ delayed until the user hits the next key. Apart from puzzling the user,
+ this clearly isn't a serious problem. However there is a way, albeit
+ complicated, to completely avoid this race condition. The following
+ steps illustrate this.
+
+ 1. Block all of the signals that gl_get_line() catches,
+ by passing the signal set returned by gl_list_signals() to
+ sigprocmask().
+
+ 2. Call gl_pending_io() and set up the arguments of
+ select() or poll() accordingly.
+
+ 3. Call sigsetjmp() with a non-zero savesigs argument.
+
+ 4. Initially this sigsetjmp() statement will return zero,
+ indicating that control isn't resuming there after a matching
+ call to siglongjmp().
+
+ 5. Replace all of the handlers of the signals that gl_get_line()
+ is configured to catch, with a signal handler that first records
+ the number of the signal that was caught, in a file-scope variable,
+ then calls siglongjmp() with a non-zero value argument, to
+ return execution to the above sigsetjmp()
+ statement. Registering these signal handlers can conveniently be
+ done using the gl_tty_signals() function.
+
+ 6. Set the file-scope variable that the above signal handler uses to
+ record any signal that is caught to -1, so that we can check
+ whether a signal was caught by seeing if it contains a valid signal
+ number.
+
+ 7. Now unblock the signals that were blocked in step 1. Any signal
+ that was received by the process in between step 1 and now will
+ now be delivered, and trigger our signal handler, as will any
+ signal that is received until we block these signals again.
+
+ 8. Now call select() or poll().
+
+ 9. When select() returns, again block the signals that were
+ unblocked in step 7.
+
+ If a signal is arrived any time during the above steps, our signal han-
+ dler will be triggered and cause control to return to the sigsetjmp()
+ statement, where this time, sigsetjmp() will return non-zero, indicat-
+ ing that a signal was caught. When this happens we simply skip the
+ above block of statements, and continue with the following statements,
+ which are executed regardless of whether or not a signal is caught.
+ Note that when sigsetjmp() returns, regardless of why it returned, the
+ process signal mask is returned to how it was when sigsetjmp() was
+ called. Thus the following statements are always executed with all of
+ our signals blocked.
+
+ 9. Reinstate the signal handlers that were displaced in step 5.
+
+ 10. Check wether a signal was caught, by checking the file-scope
+ variable that the signal handler records signal numbers in.
+
+ 11. If a signal was caught, send this signal to the application
+ again, and unblock just this signal, so that it invokes the
+ signal handler which we just reinstated in step 10.
+
+ 12. Unblock all of the signals that were blocked in step 7.
+
+ Since this is complicated, note that demo3.c includes a working example
+ of how to do this. The method used there however, is more general than
+ the above. What it provides is a wrapper function around select() which
+ encompasses steps 3 to 11. In this wrapper, rather than use
+ gl_list_signals() to figure out the signals to block, and and
+ gl_tty_signals() to assign and revert signal handlers, one of its argu-
+ ments is a sigset_t which specifies which signals to block and assign
+ signal handlers to. This function thus doesn't depend on gl_get_line()
+ and can thus be used in other situations where race-condition-free sig-
+ nal handling is required.
+
+
+</pre><h2>SIGNALS CAUGHT BY GL_GET_LINE</h2><pre>
+ Since the application is expected to handle signals in non-blocking
+ server mode, gl_get_line() doesn't attempt to duplicate this when it is
+ being called. If one of the signals that it is configured to catch is
+ sent to the application while gl_get_line() is being called,
+ gl_get_line() reinstates the caller's signal handlers, then just before
+ returning, re-sends the signal to the process to let the application's
+ signal handler handle it. If the process isn't terminated by this sig-
+ nal, gl_get_line() returns NULL, and a following call to gl_return_sta-
+ tus() returns the enumerated value GLR_SIGNAL.
+
+
+</pre><h2>ABORTING LINE INPUT</h2><pre>
+ Often, rather than letting it terminate the process, applications
+ respond to the SIGINT user-interrupt signal by aborting the current
+ input line. The way to do this in non-blocking server-I/O mode is to
+ not call gl_handle_signal() when this signal is caught, but instead to
+ call the gl_abandon_line().
+
+
+ void gl_abandon_line(GetLine *gl);
+
+
+ This function arranges that when gl_get_line() is next called, it first
+ flushes any pending output to the terminal, then discardes the current
+ input line, outputs a new prompt on the next line, and finally starts
+ accepting input of a new input line from the user.
+
+
+</pre><h2>SIGNAL SAFE FUNCTIONS</h2><pre>
+ Provided that certain rules are followed, the following functions can
+ have been written to be safely callable from signal handlers. Other
+ functions in this library should not be called from signal handlers.
+
+
+ gl_normal_io()
+ gl_raw_io()
+ gl_handle_signal()
+ gl_abandon_line()
+
+
+ In order for this to be true, all signal handlers that call these func-
+ tions must be registered in such a way that only one instance of any
+ one of them can be running at one time. The way to do this is to use
+ the POSIX sigaction() function to register all signal handlers, and
+ when doing this, use the sa_mask member of the corresponding sigaction
+ structure, to indicate that all of the signals who's handlers invoke
+ the above functions, should be blocked when the current signal is being
+ handled. This prevents two signal handlers from operating on a GetLine
+ object at the same time.
+
+ To prevent signal handlers from accessing a GetLine object while
+ gl_get_line() or any of its associated public functions are operating
+ on it, all public functions associated with gl_get_line(), including
+ gl_get_line() itself, temporarily block the delivery of signals when
+ they are accessing GetLine objects. Beware that the only signals that
+ they block are the signals that gl_get_line() is currently configured
+ to catch, so be sure that if you call any of the above functions from
+ signal handlers, that the signals that these handlers are assigned to
+ are configured to be caught by gl_get_line() (see gl_trap_signal()).
+
+
+</pre><h2>USING TIMEOUTS TO POLL</h2><pre>
+ If instead of using select() or poll() to wait for I/O, your applica-
+ tion just needs to get out of gl_get_line() periodically to briefly do
+ something else before returning to accept input from the user, this can
+ be done in non-blocking server mode by using the gl_inactivity_time-
+ out() function (see <a href="gl_get_line.html"><b>gl_get_line</b></a>), to specify that a
+ callback function that returns GLTO_CONTINUE should be called whenever
+ gl_get_line() has been waiting for I/O for more than a specified amount
+ of time.
+
+ When this callback is triggered, gl_get_line() will return NULL, and a
+ following call to gl_return_status() will return GLR_BLOCKED.
+
+ Beware that gl_get_line() won't return until the user hasn't typed a
+ key for the specified interval, so if the interval is long, and the
+ user keeps typing, gl_get_line() may not return for a while. In other
+ words there is no guarantee that it will return in the time specified.
+
+
+</pre><h2>THE SERVER DEMO PROGRAM</h2><pre>
+ The demo3 program that is distributed with the library, provides a
+ working example of how to use non-blocking server I/O mode in a real
+ program. As far as the user is concerned, this program operates
+ identically to the main demo program (called demo), except that whereas
+ the main demo program uses the normal blocking I/O mode, demo3 using
+ non-blocking I/O and an external event loop. The source code can be
+ found in demo3.c, and the comments therein explain the various steps.
+
+
+</pre><h2>FILES</h2><pre>
+ libtecla.a - The tecla library
+ libtecla.h - The tecla header file.
+
+
+</pre><h2>SEE ALSO</h2><pre>
+ <a href="libtecla.html"><b>libtecla</b></a>, <a href="gl_get_line.html"><b>gl_get_line</b></a>, <a href="tecla.html"><b>tecla</b></a>, <a href="ef_expand_file.html"><b>ef_expand_file</b></a>,
+ <a href="cpl_complete_word.html"><b>cpl_complete_word</b></a>, <a href="pca_lookup_file.html"><b>pca_lookup_file</b></a>
+
+
+</pre><h2>AUTHOR</h2><pre>
+ Martin Shepherd (mcs@astro.caltech.edu)
+
+
+
+ <a href="gl_io_mode.html"><b>gl_io_mode</b></a>
+</pre>
+</body>
diff --git a/libtecla-1.4.1/html/index.html b/libtecla-1.6.1/html/index.html
index f75a90f..29889da 100644
--- a/libtecla-1.4.1/html/index.html
+++ b/libtecla-1.6.1/html/index.html
@@ -25,9 +25,9 @@ in threaded programs. The option to enable this is discussed in the
Makefile, and specific discussions of thread safety are presented in
the included man pages.
<P>
-The current version is version 1.4.1. This may be obtained from:
+The current version is version 1.6.1. This may be obtained from:
<P>
- <a href="libtecla-1.4.1.tar.gz">http://www.astro.caltech.edu/~mcs/tecla/libtecla-1.4.1.tar.gz</a>
+ <a href="libtecla-1.6.1.tar.gz">http://www.astro.caltech.edu/~mcs/tecla/libtecla-1.6.1.tar.gz</a>
<P>
For the sake of automated scripts, the following URL always points to
@@ -58,12 +58,14 @@ library can be found <a href="changes.html">here</a>.
The following are html versions of the libtecla man pages:
<UL>
-<LI> <a href="libtecla.html">libtecla(3)</a> - An introduction to the tecla library.
-<LI> <a href="gl_get_line.html">gl_get_line(3)</a> - The interactive line-input function.
-<LI> <a href="cpl_complete_word.html">cpl_complete_word(3)</a> - The word (eg. filename) completion function.
-<LI> <a href="ef_expand_file.html">ef_expand_file(3)</a> - The filename expansion function.
-<LI> <a href="pca_lookup_file.html">pca_lookup_file(3)</a> - A directory-list based filename lookup and completion module.
-<LI> <a href="enhance.html">enhance(3)</a> - A program that adds command-line editing to third party programs.
+<LI> <a href="tecla.html">tecla</a> - Documentation for users of programs which use gl_get_line().
+<LI> <a href="libtecla.html">libtecla</a> - A programmers introduction to the tecla library.
+<LI> <a href="gl_get_line.html">gl_get_line</a> - The interactive line-input function.
+<LI> <a href="gl_io_mode.html">gl_io_mode</a> - Using gl_get_line() in a non-blocking fashion.
+<LI> <a href="cpl_complete_word.html">cpl_complete_word</a> - The word (eg. filename) completion function.
+<LI> <a href="ef_expand_file.html">ef_expand_file</a> - The filename expansion function.
+<LI> <a href="pca_lookup_file.html">pca_lookup_file</a> - A directory-list based filename lookup and completion module.
+<LI> <a href="enhance.html">enhance</a> - A program that adds command-line editing to third party programs.
</UL>
<H2>Portability</H2>
@@ -73,18 +75,20 @@ without any problems on any UNIX or UNIX like system. So far it has
been reported to work on the following systems:
<pre>
- Sun Solaris 2.5,2.6,7,8, with any of gcc, Sun C, or g++.
+ Sun Solaris 2.5,2.6,7,8,9 with any of gcc, Sun C, or g++.
Mandrake Linux 7.1 etc.., gcc
Red Hat Linux 7 etc.., gcc
+ Fedora Core 1, gcc
Suse Linux 6.4, gcc
IBM AIX 4.3.3, gcc
HP-UX 10.20, HP-UX 11, gcc, c89
- SCO UnixWare 7.1.1
FreeBSD, gcc
Alpha OSF1, cc, gcc
Mac OS X
Cygwin (running under Windows)
QNX
+ NetBSD 1.6, 386, gcc
+ SGI IRIX 6.5
</pre>
There haven't been many reports concerning the POSIX reentrant
@@ -93,24 +97,26 @@ systems on which the reentrant version is known to work, shouldn't be
taken as an indication that the reentrant version doesn't work.
<pre>
- Sun Solaris 2.5,2.6,7,8, with any of gcc, Sun C, or g++.
- Mandrake Linux 7.1, gcc
- RedHat Linux 7.0,7.1, gcc
- SuSe Linux 6.4, gcc
+ Sun Solaris 2.5,2.6,7,8,9 with any of gcc, Sun C, or g++.
+ Mandrake Linux, gcc
+ RedHat Linux, gcc
+ Fedora Core, gcc
+ SuSE Linux, gcc
HP-UX 11, gcc
IBM AIX 4.3.3, gcc
Alpha OSF1, cc
+ SGI IRIX 6.5
</pre>
The only system that is known to have issues with the reentrant
version of the library is SCO UnixWare 7.1.1. The problem is in the
system provided signal.h, which breaks when POSIX_C_SOURCE is
-defined. It has been reported that this can be fixed by editing
+defined. It has been reported that this can be "fixed" by editing
signal.h.
<P>
If you compile the library on a system that isn't mentioned above,
please send E-mail to <b>mcs@astro.caltech.edu</b>.
<HR>
-Martin Shepherd (25-May-2002)
+Martin Shepherd (31-Oct-2004)
</BODY>
diff --git a/libtecla-1.6.1/html/libtecla.html b/libtecla-1.6.1/html/libtecla.html
new file mode 100644
index 0000000..2b85d7a
--- /dev/null
+++ b/libtecla-1.6.1/html/libtecla.html
@@ -0,0 +1,138 @@
+<head>
+<title>Manual Page</title>
+</head>
+<body>
+<pre>
+<a href="libtecla.html"><b>libtecla</b></a> <a href="libtecla.html"><b>libtecla</b></a>
+
+
+
+</pre><h2>NAME</h2><pre>
+ libtecla - An interactive command-line input library.
+
+</pre><h2>SYNOPSIS</h2><pre>
+ @CC@ ... -ltecla -lcurses
+
+
+</pre><h2>DESCRIPTION</h2><pre>
+ The tecla library provides programs with interactive command line edit-
+ ing facilities, similar to those of the unix tcsh shell. In addition to
+ simple command-line editing, it supports recall of previously entered
+ command lines, TAB completion of file names or other tokens, and in-
+ line wild-card expansion of filenames. The internal functions which
+ perform file-name completion and wild-card expansion are also available
+ externally for optional use by the calling program.
+
+ The various parts of the library are documented in the following man
+ pages:
+
+ <a href="tecla.html"><b>tecla</b></a> - Use level documentation of the
+ command-line editing facilities
+ provided by gl_get_line().
+ <a href="gl_get_line.html"><b>gl_get_line</b></a> - The interactive line-input module.
+ <a href="gl_io_mode.html"><b>gl_io_mode</b></a> - How to use gl_get_line() in an
+ incremental, non-blocking fashion.
+ <a href="cpl_complete_word.html"><b>cpl_complete_word</b></a> - The word completion module.
+ <a href="ef_expand_file.html"><b>ef_expand_file</b></a> - The filename expansion module.
+ <a href="pca_lookup_file.html"><b>pca_lookup_file</b></a> - A directory-list based filename
+ lookup and completion module.
+
+ In addition there is one optional application distributed with the
+ library:
+
+ <a href="enhance.html"><b>enhance</b></a> - Add command-line editing to third
+ party applications.
+
+
+</pre><h2>THREAD SAFETY</h2><pre>
+ If the library is compiled with -D_POSIX_C_SOURCE=199506L, reentrant
+ versions of as many functions as possible are used. This includes using
+ getpwuid_r() and getpwnam_r() instead of getpwuid() and getpwnam() when
+ looking up the home directories of specific users in the password file
+ (for ~user/ expansion), and readdir_r() instead of readdir() for read-
+ ing directory entries when doing filename completion. The reentrant
+ version of the library is usually called libtecla_r.a instead of libte-
+ cla.a, so if only the latter is available, it probably isn't the cor-
+ rect version to link with threaded programs.
+
+ Reentrant functions for iterating through the password file aren't
+ available, so when the library is compiled to be reentrant, TAB comple-
+ tion of incomplete usernames in ~username/ expressions is disabled.
+ This doesn't disable expansion of complete ~username expressions, which
+ can be done reentrantly, or expansion of the parts of filenames that
+ follow them, so this doesn't remove much functionality.
+
+ The terminfo functions setupterm(), tigetstr(), tigetnum() and tputs()
+ also aren't reentrant, but very few programs will want to interact with
+ multiple terminals, so this shouldn't prevent this library from being
+ used in threaded programs.
+
+
+</pre><h2>LIBRARY VERSION NUMBER</h2><pre>
+ The version number of the library can be queried using the following
+ function.
+
+ void libtecla_version(int *major, int *minor, int *micro);
+
+
+ On return, this function records the three components of the libtecla
+ version number in *major, *minor, *micro. The formal meaning of the
+ three components is as follows.
+
+
+ major - Incrementing this number implies that a change has
+ been made to the library's public interface, which
+ makes it binary incompatible with programs that
+ were linked with previous shared versions of the
+ tecla library.
+
+ minor - This number is incremented by one whenever
+ additional functionality, such as new functions or
+ modules, are added to the library.
+
+ micro - This is incremented whenever modifications to the
+ library are made which make no changes to the
+ public interface, but which fix bugs and/or improve
+ the behind-the-scenes implementation.
+
+
+
+</pre><h2>TRIVIA</h2><pre>
+ In Spanish, a "tecla" is the key of a keyboard. Since this library cen-
+ ters on keyboard input, and given that I wrote much of the library
+ while working in Chile, this seemed like a suitable name.
+
+
+</pre><h2>FILES</h2><pre>
+ libtecla.a - The tecla library.
+ libtecla.h - The tecla header file.
+ ~/.teclarc - The tecla personal customization file.
+
+
+</pre><h2>SEE ALSO</h2><pre>
+ <a href="gl_get_line.html"><b>gl_get_line</b></a>, <a href="tecla.html"><b>tecla</b></a>, <a href="gl_io_mode.html"><b>gl_io_mode</b></a>, <a href="ef_expand_file.html"><b>ef_expand_file</b></a>,
+ <a href="cpl_complete_word.html"><b>cpl_complete_word</b></a>, <a href="pca_lookup_file.html"><b>pca_lookup_file</b></a>, <a href="enhance.html"><b>enhance</b></a>
+
+
+</pre><h2>AUTHOR</h2><pre>
+ Martin Shepherd (mcs@astro.caltech.edu)
+
+
+</pre><h2>ACKNOWLEDGMENTS</h2><pre>
+ Markus Gyger - Lots of assistance, including help with
+ shared libraries, configuration information,
+ particularly for Solaris; modifications to
+ support C++ compilers, improvements for ksh
+ users, faster cursor motion, output
+ buffering, and changes to make gl_get_line()
+ 8-bit clean.
+ Mike MacFaden - Suggestions, feedback and testing that led
+ to many of the major new functions that were
+ added in version 1.4.0.
+ Tim Eliseo - Many vi-mode bindings and fixes.
+
+
+
+ <a href="libtecla.html"><b>libtecla</b></a>
+</pre>
+</body>
diff --git a/libtecla-1.6.1/html/pca_lookup_file.html b/libtecla-1.6.1/html/pca_lookup_file.html
new file mode 100644
index 0000000..d5e1e7b
--- /dev/null
+++ b/libtecla-1.6.1/html/pca_lookup_file.html
@@ -0,0 +1,312 @@
+<head>
+<title>Manual Page</title>
+</head>
+<body>
+<pre>
+<a href="pca_lookup_file.html"><b>pca_lookup_file</b></a> <a href="pca_lookup_file.html"><b>pca_lookup_file</b></a>
+
+
+
+</pre><h2>NAME</h2><pre>
+ pca_lookup_file, del_PathCache, del_PcaPathConf, new_PathCache,
+ new_PcaPathConf, pca_last_error, pca_path_completions, pca_scan_path,
+ pca_set_check_fn, ppc_file_start, ppc_literal_escapes - lookup a file
+ in a list of directories
+
+</pre><h2>SYNOPSIS</h2><pre>
+ #include &lt;libtecla.h&gt;
+
+ PathCache *new_PathCache(void);
+
+ PathCache *del_PathCache(PathCache *pc);
+
+ int pca_scan_path(PathCache *pc, const char *path);
+
+ void pca_set_check_fn(PathCache *pc, CplCheckFn *check_fn,
+ void *data);
+
+ char *pca_lookup_file(PathCache *pc, const char *name,
+ int name_len, int literal);
+
+ const char *pca_last_error(PathCache *pc);
+
+ CPL_MATCH_FN(pca_path_completions);
+
+
+
+</pre><h2>DESCRIPTION</h2><pre>
+ The PathCache object is part of the tecla library (see the libte-
+ cla(@LIBR_MANEXT@) man page).
+
+ PathCache objects allow an application to search for files in any colon
+ separated list of directories, such as the unix execution PATH environ-
+ ment variable. Files in absolute directories are cached in a PathCache
+ object, whereas relative directories are scanned as needed. Using a
+ PathCache object, you can look up the full pathname of a simple file-
+ name, or you can obtain a list of the possible completions of a given
+ filename prefix. By default all files in the list of directories are
+ targets for lookup and completion, but a versatile mechanism is pro-
+ vided for only selecting specific types of files. The obvious applica-
+ tion of this facility is to provide Tab-completion and lookup of exe-
+ cutable commands in the unix PATH, so an optional callback which
+ rejects all but executable files, is provided.
+
+
+</pre><h2>AN EXAMPLE</h2><pre>
+ Under UNIX, the following example program looks up and displays the
+ full pathnames of each of the command names on the command line.
+
+ #include &lt;stdio.h&gt;
+ #include &lt;stdlib.h&gt;
+ #include &lt;libtecla.h&gt;
+
+ int main(int argc, char *argv[])
+ {
+ int i;
+ /*
+ * Create a cache for executable files.
+ */
+ PathCache *pc = new_PathCache();
+ if(!pc)
+ exit(1);
+ /*
+ * Scan the user's PATH for executables.
+ */
+ if(pca_scan_path(pc, getenv("PATH"))) {
+ fprintf(stderr, "%s\n", pca_last_error(pc));
+ exit(1);
+ }
+ /*
+ * Arrange to only report executable files.
+ */
+ pca_set_check_fn(pc, cpl_check_exe, NULL);
+ /*
+ * Lookup and display the full pathname of each of the
+ * commands listed on the command line.
+ */
+ for(i=1; i&lt;argc; i++) {
+ char *cmd = pca_lookup_file(pc, argv[i], -1, 0);
+ printf("The full pathname of '%s' is %s\n", argv[i],
+ cmd ? cmd : "unknown");
+ }
+ pc = del_PathCache(pc); /* Clean up */
+ return 0;
+ }
+
+ The following is an example of what this does on my laptop under linux:
+
+ $ ./example less more blob
+ The full pathname of 'less' is /usr/bin/less
+ The full pathname of 'more' is /bin/more
+ The full pathname of 'blob' is unknown
+ $
+
+
+</pre><h2>FUNCTION DESCRIPTIONS</h2><pre>
+ In order to use the facilities of this module, you must first allocate
+ a PathCache object by calling the new_PathCache() constructor function.
+
+ PathCache *new_PathCache(void)
+
+ This function creates the resources needed to cache and lookup files in
+ a list of directories. It returns NULL on error.
+
+
+</pre><h2>POPULATING THE CACHE</h2><pre>
+ Once you have created a cache, it needs to be populated with files. To
+ do this, call the pca_scan_path() function.
+
+ int pca_scan_path(PathCache *pc, const char *path);
+
+ Whenever this function is called, it discards the current contents of
+ the cache, then scans the list of directories specified in its path
+ argument for files. The path argument must be a string containing a
+ colon-separated list of directories, such as
+ "/usr/bin:/home/mcs/bin:.". This can include directories specified by
+ absolute pathnames such as "/usr/bin", as well as sub-directories spec-
+ ified by relative pathnames such as "." or "bin". Files in the absolute
+ directories are immediately cached in the specified PathCache object,
+ whereas sub-directories, whose identities obviously change whenever the
+ current working directory is changed, are marked to be scanned on the
+ fly whenever a file is looked up.
+
+ On success this function return 0. On error it returns 1, and a
+ description of the error can be obtained by calling pca_last_error(pc).
+
+
+</pre><h2>LOOKING UP FILES</h2><pre>
+ Once the cache has been populated with files, you can look up the full
+ pathname of a file, simply by specifying its filename to
+ pca_lookup_file().
+
+ char *pca_lookup_file(PathCache *pc, const char *name,
+ int name_len, int literal);
+
+ To make it possible to pass this function a filename which is actually
+ part of a longer string, the name_len argument can be used to specify
+ the length of the filename at the start of the name[] argument. If you
+ pass -1 for this length, the length of the string will be determined
+ with strlen(). If the name[] string might contain backslashes that
+ escape the special meanings of spaces and tabs within the filename,
+ give the literal argument, the value 0. Otherwise, if backslashes
+ should be treated as normal characters, pass 1 for the value of the
+ literal argument.
+
+
+</pre><h2>FILENAME COMPLETION</h2><pre>
+ Looking up the potential completions of a filename-prefix in the file-
+ name cache, is achieved by passing the provided pca_path_completions()
+ callback function to the cpl_complete_word() function (see the cpl_com-
+ plete_word(@FUNC_MANEXT@) man page).
+
+ CPL_MATCH_FN(pca_path_completions);
+
+ This callback requires that its data argument be a pointer to a PcaP-
+ athConf object. Configuration objects of this type are allocated by
+ calling new_PcaPathConf().
+
+ PcaPathConf *new_PcaPathConf(PathCache *pc);
+
+ This function returns an object initialized with default configuration
+ parameters, which determine how the cpl_path_completions() callback
+ function behaves. The functions which allow you to individually change
+ these parameters are discussed below.
+
+ By default, the pca_path_completions() callback function searches back-
+ wards for the start of the filename being completed, looking for the
+ first un-escaped space or the start of the input line. If you wish to
+ specify a different location, call ppc_file_start() with the index at
+ which the filename starts in the input line. Passing start_index=-1 re-
+ enables the default behavior.
+
+ void ppc_file_start(PcaPathConf *ppc, int start_index);
+
+ By default, when pca_path_completions() looks at a filename in the
+ input line, each lone backslash in the input line is interpreted as
+ being a special character which removes any special significance of the
+ character which follows it, such as a space which should be taken as
+ part of the filename rather than delimiting the start of the filename.
+ These backslashes are thus ignored while looking for completions, and
+ subsequently added before spaces, tabs and literal backslashes in the
+ list of completions. To have unescaped backslashes treated as normal
+ characters, call ppc_literal_escapes() with a non-zero value in its
+ literal argument.
+
+ void ppc_literal_escapes(PcaPathConf *ppc, int literal);
+
+ When you have finished with a PcaPathConf variable, you can pass it to
+ the del_PcaPathConf() destructor function to reclaim its memory.
+
+ PcaPathConf *del_PcaPathConf(PcaPathConf *ppc);
+
+
+
+</pre><h2>BEING SELECTIVE</h2><pre>
+ If you are only interested in certain types or files, such as, for
+ example, executable files, or files whose names end in a particular
+ suffix, you can arrange for the file completion and lookup functions to
+ be selective in the filenames that they return. This is done by regis-
+ tering a callback function with your PathCache object. Thereafter,
+ whenever a filename is found which either matches a filename being
+ looked up, or matches a prefix which is being completed, your callback
+ function will be called with the full pathname of the file, plus any
+ application-specific data that you provide, and if the callback returns
+ 1 the filename will be reported as a match, and if it returns 0, it
+ will be ignored. Suitable callback functions and their prototypes
+ should be declared with the following macro. The CplCheckFn typedef is
+ also provided in case you wish to declare pointers to such functions.
+
+ #define CPL_CHECK_FN(fn) int (fn)(void *data, \
+ const char *pathname)
+ typedef CPL_CHECK_FN(CplCheckFn);
+
+ Registering one of these functions involves calling the
+ pca_set_check_fn() function. In addition to the callback function,
+ passed via the check_fn argument, you can pass a pointer to anything
+ via the data argument. This pointer will be passed on to your callback
+ function, via its own data argument, whenever it is called, so this
+ provides a way to pass appplication specific data to your callback.
+
+ void pca_set_check_fn(PathCache *pc, CplCheckFn *check_fn,
+ void *data);
+
+ Note that these callbacks are passed the full pathname of each matching
+ file, so the decision about whether a file is of interest can be based
+ on any property of the file, not just its filename. As an example, the
+ provided cpl_check_exe() callback function looks at the executable per-
+ missions of the file and the permissions of its parent directories, and
+ only returns 1 if the user has execute permission to the file. This
+ callback function can thus be used to lookup or complete command names
+ found in the directories listed in the user's PATH environment vari-
+ able. The example program given earlier in this man page provides a
+ demonstration of this.
+
+ Beware that if somebody tries to complete an empty string, your call-
+ back will get called once for every file in the cache, which could num-
+ ber in the thousands. If your callback does anything time consuming,
+ this could result in an unacceptable delay for the user, so callbacks
+ should be kept short.
+
+ To improve performance, whenever one of these callbacks is called, the
+ choice that it makes is cached, and the next time the corresponding
+ file is looked up, instead of calling the callback again, the cached
+ record of whether it was accepted or rejected is used. Thus if somebody
+ tries to complete an empty string, and hits tab a second time when
+ nothing appears to happen, there will only be one long delay, since the
+ second pass will operate entirely from the cached dispositions of the
+ files. These cached dipositions are discarded whenever pca_scan_path()
+ is called, and whenever pca_set_check_fn() is called with changed call-
+ back function or data arguments.
+
+
+</pre><h2>ERROR HANDLING</h2><pre>
+ If pca_scan_path() reports that an error occurred by returning 1, you
+ can obtain a terse description of the error by calling
+ pca_last_error(pc). This returns an internal string containing an error
+ message.
+
+ const char *pca_last_error(PathCache *pc);
+
+
+
+</pre><h2>CLEANING UP</h2><pre>
+ Once you have finished using a PathCache object, you can reclaim its
+ resources by passing it to the del_PathCache() destructor function.
+ This takes a pointer to one of these objects, and always returns NULL.
+
+ PathCache *del_PathCache(PathCache *pc);
+
+
+</pre><h2>THREAD SAFETY</h2><pre>
+ In multi-threaded programs, you should use the libtecla_r.a version of
+ the library. This uses POSIX reentrant functions where available (hence
+ the _r suffix), and disables features that rely on non-reentrant system
+ functions. In the case of this module, the only disabled feature is
+ username completion in ~username/ expressions, in cpl_path_comple-
+ tions().
+
+ Using the libtecla_r.a version of the library, it is safe to use the
+ facilities of this module in multiple threads, provided that each
+ thread uses a separately allocated PathCache object. In other words, if
+ two threads want to do path searching, they should each call new_Path-
+ Cache() to allocate their own caches.
+
+
+</pre><h2>FILES</h2><pre>
+ libtecla.a - The tecla library
+ libtecla.h - The tecla header file.
+
+
+</pre><h2>SEE ALSO</h2><pre>
+ <a href="libtecla.html"><b>libtecla</b></a>, <a href="gl_get_line.html"><b>gl_get_line</b></a>, <a href="ef_expand_file.html"><b>ef_expand_file</b></a>,
+ <a href="cpl_complete_word.html"><b>cpl_complete_word</b></a>
+
+
+</pre><h2>AUTHOR</h2><pre>
+ Martin Shepherd (mcs@astro.caltech.edu)
+
+
+
+ <a href="pca_lookup_file.html"><b>pca_lookup_file</b></a>
+</pre>
+</body>
diff --git a/libtecla-1.4.1/html/release.html b/libtecla-1.6.1/html/release.html
index e0d219c..b048f4f 100644
--- a/libtecla-1.4.1/html/release.html
+++ b/libtecla-1.6.1/html/release.html
@@ -1,7 +1,237 @@
-<HEAD><TITLE>The tecla library release notes</TITLE></HEAD>
-<BODY bgcolor=add8e6><PRE>
+<html><head><title>The tecla library release notes</title></head>
+<body bgcolor="#add8e6"><pre>
This file lists major changes which accompany each new release.
+Version 1.6.1:
+
+ This is primarily a minor bug-fix release.
+
+ One added feature is the ability to call gl_normal_io() from
+ callbacks registered by gl_watch_fd() and
+ gl_inactivity_timeout(). This allows these callbacks to cleanly
+ suspend line editing before either reading from the terminal, or
+ writing to the terminal; and then subsequently causes the input line
+ to be automatically redisplayed, and line-editing to be resumed by
+ gl_get_line(), as soon as the callback returns.
+
+ Another minor change is that if the terminal type specified in the
+ TERM environment variable is set to "dumb", gl_get_line() now treats
+ the terminal as though it were a non-interactive stream, rather than
+ treating it as a VT100-compatible terminal. This means that it
+ doesn't either prompt for input, or perform any command-line
+ editing, even when it really is interacting with a terminal. This is
+ aimed at the rare situation where a third-pary program that connects
+ to libtecla through an embedded pseudo-terminal, needs to be forced
+ to behave as though it weren't talking to a terminal, in order that
+ it be useable in non-interactive scripts.
+
+ Note that in the previous release, the optional configuration
+ function, gl_tty_signals(), was incorrectly swapping the suspend and
+ terminal signal handlers before installing them.
+
+ A configuration problem that prevented select() from being used
+ under MacOS X, has been fixed.
+
+ Although not documented in the man page, it was meant to be possible
+ to take the input line that one call to gl_get_line() returned, and
+ ask the next call to gl_get_line() to present it back to the user
+ for re-editing, simply by passing the pointer returned by one call
+ to gl_get_line() as the start_line argument of the next call to
+ gl_get_line(). This feature unfortunately stopped working in 1.6.0,
+ so this release restores it, and officially documents it in the man
+ page documentation of gl_get_line().
+
+ In the previous version of the library, calling gl_terminal_size()
+ on a system without SIGWINCH support, would crash the
+ application. This has been fixed.
+
+ Libtecla now apparently compiles cleanly under IRIX.
+
+Version 1.6.0:
+
+ This release is primarily a bug-fix release. However there are also
+ four new functions, so the minor version number has been
+ incremented to reflect this.
+
+ Two of the new functions are gl_automatic_history() and
+ gl_append_history(). The former of these functions allows the
+ application to tell gl_get_line() not to automatically archive
+ entered lines in the history list. The second of these functions
+ allows the application to explicitly append a line to the history
+ list. Thus together, these two functions allow the calling
+ application to take over control of what is placed in the history
+ list.
+
+ The third new function is gl_query_char(), which prompts the user
+ for a single character reply, which the user can then type without
+ having to hit return to enter it. Unless echoing is disabled, the
+ character that is entered is then displayed after the prompt,
+ and a newline is started.
+
+ Finally, the 4th new function is gl_read_char(), which also reads
+ a single character from the user, but doesn't prompt the user, write
+ anything to the terminal, or disturb any partially entered input
+ line. It is thus safe to call this function not only from between
+ calls to gl_get_line(), but also from application callback
+ functions, even if gl_normal_io() hasn't been called.
+
+ When using the history-search-backwards or history-search-forwards
+ actions, if the search prefix that the user typed, contains any of
+ the *,? or [ globbing characters, it is now treated as a glob
+ pattern to be matched against historical lines, instead of a simple
+ prefix.
+
+ I have added a --without-file-system option to the configure
+ script. This is intended for use in embedded systems that either
+ don't have filesystems, or where the file-system code in libtecla is
+ seen as unwanted bloat. See the INSTALL document for details.
+
+ Similarly, I also added a --without-file-actions option to the
+ configure script. This allows the application author/installer to
+ prevent users of gl_get_line() from accessing the filesystem with
+ the builtin actions of gl_get_line(). It does this by removing a
+ number of action functions, such as expand-filename, and list-glob,
+ and by changing the default behavior of other actions, such as
+ complete-word and list-or-eof, to show no completions.
+
+ Now to the bugs that have been fixed. Version 1.5.0 had a lot of big
+ internal changes, so there are a number of bugs that needed to be
+ fixed. There was a bug which caused a crash if gl_load_history()
+ was called multiple times. There was another bug which caused a
+ prompt not to be displayed on the next line after switching from
+ reading input from a file to reading from the terminal. Also, in
+ tecla configuration files, backslash escaped characters within
+ key-binding key-sequences weren't being escaped. Thus ^\\ got
+ interpretted as a control-\ followed by a \ character instead of as
+ a control-\. There was a bug in the history recall mechanism which
+ caused the search prefix to be forgotten in certain complicated
+ usage scenarios. There was a minor memory leak in the
+ gl_configure_getline() function. Finally, if gl_get_line() was
+ aborted by a signal, or any other abnormal event, the value of errno
+ which originally indicated what had happened, got zeroed by the
+ code that restored the terminal to a usable state. Thus the
+ application couldn't figure out what had caused the error, apart
+ from by looking at gl_return_status(). All of these bugs have been
+ fixed.
+
+ In the Makefile, there were a number of places where install-sh was
+ invoked without a path prefix. This has now been remedied.
+
+ A fully functional workaround for a bug in Solaris' terminal I/O
+ code has also been implemented. This bug, which only manifested
+ itself in libtecla's uncommonly used non-blocking server I/O mode,
+ caused characters entered while in normal I/O mode, between calls to
+ gl_get_line() to be invisible to the next call to gl_get_line(),
+ until the user typed at least one more key after raw terminal mode
+ was restored.
+
+ The Gnu autoconf config.guess and config.sub scripts have been
+ updated to their latest versions. Apparently the old versions that I
+ was previously using were too old to know about certain BSD ports.
+
+Version 1.5.0:
+
+ This release includes several major new features for those using
+ gl_get_line(), shared library support in Darwin, better cross
+ compilation support, and various minor bug fixes.
+
+ The biggest new feature is the option of a non-blocking I/O mode, in
+ which gl_get_line() can safely be called from an application's
+ external event-loop to incrementally read input lines from the user.
+ This feature is documented in the gl_io_mode(3) man page.
+
+ In addition, there is now support for the definition of additional
+ word-completion action functions, which can then be bound to
+ different keys. See the documentation of the gl_completion_action()
+ function in the gl_get_line(3) man page.
+
+ Externally defined action functions can also be defined, although
+ presently they don't have write access to the input line, so they
+ are restricted to operations that display information text to the
+ terminal, or modify the environment of the calling application in
+ some way. See the documentation of the gl_register_action() function
+ in the gl_get_line(3) man page.
+
+ Some of the non-blocking I/O support functions can also be used for
+ improved signal handling in the normal blocking mode. In particular,
+ the gl_list_signals() and gl_catch_blocked() functions make it
+ easier to write reliable signal handling around gl_get_line(). The
+ new "RELIABLE SIGNAL HANDLING" section of the gl_get_line(3) man
+ page is intended as an introduction to this subject.
+
+ Programs can now clear the terminal between calls to gl_get_line(),
+ by calling the new gl_erase_terminal() function.
+
+ The gl_display_text() function, now used in the demos to display
+ introductory banners, is provided for formatting text according to
+ the width of the terminal.
+
+ It is now possible to install inactivity timeout callbacks in
+ gl_get_line(), using the new gl_inactivity_timeout() function.
+
+ The new gl_set_term_size() function allows the application to
+ explicitly set the terminal size, for cases, such as when one is
+ using a terminal at the end of a serial lineq, where the terminal
+ driver doesn't send the process a SIGWINCH when the terminal size
+ changes.
+
+ The new gl_bind_keyseq() function provides a convenient
+ alternative to gl_configure_getline(), for binding or unbinding
+ one key-sequence at a time.
+
+ gl_get_line()s signal handling, file-descriptor event-handling,
+ inactivity-timeout handling and server-mode non-blocking I/O
+ features now not only work when input is coming from a terminal, but
+ now also work when input is coming from non-interactive streams,
+ such as files and pipes.
+
+ The history implementation has been re-written to make it more
+ efficient and easier to modify. The biggest user-level change is
+ that when recalling history lines using a search prefix, the same
+ line is no longer returned more than once in a row. Previously this
+ duplicate elimination only worked when one was recalling a line
+ without specifying a search prefix, and this was naively performed
+ by preventing neighboring duplicates from existing in the history
+ list, rather than by skipping duplicates at search time.
+
+ In previous versions of the library, when gl_get_line() and its
+ associated public functions detected invalid arguments, or couldn't
+ allocate memory, etc, error messages were written to stderr. This
+ isn't appropriate for library functions, so instead of writing such
+ messages to stderr, these messages are now recorded in buffers
+ within the affected GetLine object. The latest error message can
+ then subsequently be queried by calling gl_error_message(). The use
+ of errno has also been expanded, and a new function called
+ gl_return_status() has been provided to expand on the cause of the
+ last return from gl_get_line().
+
+ User level usage and configuration information has now been split
+ out of the gl_get_line(3) man page into a separate tecla(7) man
+ page. The enhance(3) man page has also been renamed to enhance(1).
+
+ When expanding "~/", gl_get_line() now checks for, and returns the
+ value of the HOME environment variable, if it exists, in preference
+ to looking up the directory of the current user in the password
+ file.
+
+ When the terminal was resized to a narrower width, previous versions
+ of gl_get_line() would redraw the line higher up the terminal. This
+ bug has been fixed. A bug in history recall has also been fixed, in
+ which an error message was being generated if one attempted to
+ recall a line while the cursor was at the end of the longest
+ possible input line. A more serious bug, in which callbacks
+ registered by gl_watch_fd() weren't being called for write-events,
+ has also been fixed. Finally, a few minor fixes have been made to
+ improve support under QNX and Mac OS X.
+
+ Beware that in this release, much of the underlying code has
+ undergone some radical re-work, so although backwards compatibility
+ of all documented features has been preserved, there may be some
+ lingering bugs that could break existing programs. So, if you plan
+ to use this version in production code, please test it as far as
+ possible within your application before releasing it to your
+ clients, and as always, please report any unexpected behavior.
+
Version 1.4.1:
This is a maintenance release. It includes minor changes to support
@@ -357,4 +587,4 @@ Version 1.2:
Version 1.1j
This was the initial public release on freshmeat.org.
-</PRE></BODY>
+</pre></body></html>
diff --git a/libtecla-1.6.1/html/tecla.html b/libtecla-1.6.1/html/tecla.html
new file mode 100644
index 0000000..6f270c1
--- /dev/null
+++ b/libtecla-1.6.1/html/tecla.html
@@ -0,0 +1,1120 @@
+<head>
+<title>Manual Page</title>
+</head>
+<body>
+<pre>
+<a href="tecla.html"><b>tecla</b></a> <a href="tecla.html"><b>tecla</b></a>
+
+
+
+</pre><h2>NAME</h2><pre>
+ tecla, teclarc - The user interface provided by the Tecla library.
+
+</pre><h2>DESCRIPTION</h2><pre>
+ This man page describes the command-line editing features that are
+ available to users of programs that read keyboard input via the Tecla
+ library. Users of the tcsh shell will find the default key-bindings
+ very familiar. Users of the bash shell will also find it quite famil-
+ iar, but with a few minor differences, most notably in how forward and
+ backward searches through the list of historical commands are per-
+ formed. There are two major editing modes, one with emacs-like key-
+ bindings and another with vi-like key-bindings. By default emacs mode
+ is enabled, but vi mode can alternatively be selected via the user's
+ configuration file. This file can also be used to change the bindings
+ of individual keys to suit the user's preferences. By default, tab com-
+ pletion is provided. If the application hasn't reconfigured this to
+ complete other types of symbols, then tab completion completes file-
+ names.
+
+
+</pre><h2>KEY SEQUENCE NOTATION</h2><pre>
+ In the rest of this man page, and also in all Tecla configuration
+ files, key-sequences are expressed as follows.
+
+
+ ^A or C-a
+ This is a control-A, entered by pressing the control key at
+ the same time as the A key.
+
+ \E or M-
+ In key-sequences, both of these notations can be entered
+ either by pressing the escape key, then the following key, or by
+ pressing the Meta key at the same time as the following key. Thus
+ the key sequence M-p can be typed in two ways, by pressing
+ the escape key, followed by pressing p, or by pressing the
+ Meta key at the same time as p.
+
+ up
+ This refers to the up-arrow key.
+
+ down
+ This refers to the down-arrow key.
+
+ left
+ This refers to the left-arrow key.
+
+ right
+ This refers to the right-arrow key.
+
+ a
+ This is just a normal A key.
+
+
+
+</pre><h2>THE TECLA CONFIGURATION FILE</h2><pre>
+ By default, Tecla looks for a file called .teclarc in your home direc-
+ tory (ie. ~/.teclarc). If it finds this file, it reads it, interpret-
+ ing each line as defining a new key binding or an editing configuration
+ option. Since the emacs keybindings are installed by default, if you
+ want to use the non-default vi editing mode, the most important item to
+ go in this file is the following line:
+
+ edit-mode vi
+
+ This will re-configure the default bindings for vi-mode. The complete
+ set of arguments that this command accepts are:
+
+ vi - Install key-bindings like those of the vi
+ editor.
+ emacs - Install key-bindings like those of the emacs
+ editor. This is the default.
+ none - Use just the native line editing facilities
+ provided by the terminal driver.
+
+ To prevent the terminal bell from being rung, such as when an unrecog-
+ nized control-sequence is typed, place the following line in the con-
+ figuration file:
+
+ nobeep
+
+ An example of a key binding line in the configuration file is the fol-
+ lowing.
+
+ bind M-[2~ insert-mode
+
+ On many keyboards, the above key sequence is generated when one presses
+ the insert key, so with this keybinding, one can toggle between the
+ emacs-mode insert and overwrite modes by hitting one key. One could
+ also do it by typing out the above sequence of characters one by one.
+ As explained above, the M- part of this sequence can be typed either by
+ pressing the escape key before the following key, or by pressing the
+ Meta key at the same time as the following key. Thus if you had set the
+ above key binding, and the insert key on your keyboard didn't generate
+ the above key sequence, you could still type it in either of the fol-
+ lowing 2 ways.
+
+ 1. Hit the escape key momentarily, then press '[', then '2', then
+ finally '~'.
+
+ 2. Press the meta key at the same time as pressing the '[' key,
+ then press '2', then '~'.
+
+ If you set a keybinding for a key-sequence that is already bound to a
+ function, the new binding overrides the old one. If in the new binding
+ you omit the name of the new function to bind to the key-sequence, the
+ original binding becomes undefined.
+
+ Starting with versions of libtecla later than 1.3.3 it is now possible
+ to bind keysequences that begin with a printable character. Previously
+ key-sequences were required to start with a control or meta character.
+
+ Note that the special keywords "up", "down", "left" and "right" refer
+ to the arrow keys, and are thus not treated as keysequences. So, for
+ example, to rebind the up and down arrow keys to use the history search
+ mechanism instead of the simple history recall method, you could place
+ the following in your configuration file:
+
+ bind up history-search-backwards
+ bind down history-search-backwards
+
+ To unbind an existing binding, you can do this with the bind command by
+ omitting to name any action to rebind the key sequence to. For exam-
+ ple, by not specifying an action function, the following command
+ unbinds the default beginning-of-line action from the ^A key sequence:
+
+ bind ^A
+
+ If you create a ~/.teclarc configuration file, but it appears to have
+ no effect on the program, check the documentation of the program to see
+ if the author chose a different name for this file.
+
+
+</pre><h2>FILENAME AND TILDE COMPLETION</h2><pre>
+ With the default key bindings, pressing the TAB key (aka. ^I) results
+ in Tecla attempting to complete the incomplete filename that precedes
+ the cursor. Tecla searches backwards from the cursor, looking for the
+ start of the filename, stopping when it hits either a space or the
+ start of the line. If more than one file has the specified prefix, then
+ Tecla completes the filename up to the point at which the ambiguous
+ matches start to differ, then lists the possible matches.
+
+ In addition to literally written filenames, Tecla can complete files
+ that start with ~/ and ~user/ expressions and that contain $envvar
+ expressions. In particular, if you hit TAB within an incomplete ~user,
+ expression, Tecla will attempt to complete the username, listing any
+ ambiguous matches.
+
+ The completion binding is implemented using the cpl_word_completions()
+ function, which is also available separately to users of this library.
+ See the cpl_word_completions(@LIBR_MANEXT@) man page for more details.
+
+
+</pre><h2>FILENAME EXPANSION</h2><pre>
+ With the default key bindings, pressing ^X* causes Tecla to expand the
+ filename that precedes the cursor, replacing ~/ and ~user/ expressions
+ with the corresponding home directories, and replacing $envvar expres-
+ sions with the value of the specified environment variable, then if
+ there are any wildcards, replacing the so far expanded filename with a
+ space-separated list of the files which match the wild cards.
+
+ The expansion binding is implemented using the ef_expand_file() func-
+ tion. See the <a href="ef_expand_file.html"><b>ef_expand_file</b></a> man page for more details.
+
+
+</pre><h2>RECALLING PREVIOUSLY TYPED LINES</h2><pre>
+ Every time that a new line is entered by the user, it is appended to a
+ list of historical input lines maintained within the GetLine resource
+ object. You can traverse up and down this list using the up and down
+ arrow keys. Alternatively, you can do the same with the ^P, and ^N
+ keys, and in vi command mode you can alternatively use the k and j
+ characters. Thus pressing up-arrow once, replaces the current input
+ line with the previously entered line. Pressing up-arrow again,
+ replaces this with the line that was entered before it, etc.. Having
+ gone back one or more lines into the history list, one can return to
+ newer lines by pressing down-arrow one or more times. If you do this
+ sufficient times, you will return to the original line that you were
+ entering when you first hit up-arrow.
+
+ Note that in vi mode, all of the history recall functions switch the
+ library into command mode.
+
+ In emacs mode the M-p and M-n keys work just like the ^P and ^N keys,
+ except that they skip all but those historical lines which share the
+ prefix that precedes the cursor. In vi command mode the upper case K
+ and J characters do the same thing, except that the string that they
+ search for includes the character under the cursor as well as what pre-
+ cedes it.
+
+ Thus for example, suppose that you were in emacs mode, and you had just
+ entered the following list of commands in the order shown:
+
+ ls ~/tecla/
+ cd ~/tecla
+ ls -l getline.c
+ emacs ~/tecla/getline.c
+
+ If you next typed:
+
+ ls
+
+ and then hit M-p, then rather than returning the previously typed emacs
+ line, which doesn't start with "ls", Tecla would recall the "ls -l get-
+ line.c" line. Pressing M-p again would recall the "ls ~/tecla/" line.
+
+ Note that if the string that you are searching for, contains any of the
+ special characters, *, ?, or '[', then it is interpretted as a pattern
+ to be matched. Thus, cotinuing with the above example, after typing in
+ the list of commands shown, if you then typed:
+
+ *tecla*
+
+ and hit M-p, then the "emacs ~/tecla/getline.c" line would be recalled
+ first, since it contains the word tecla somewhere in the line, Simi-
+ larly, hitting M-p again, would recall the "ls ~/tecla/" line, and hit-
+ ting it once more would recall the "ls ~/tecla/" line. The pattern syn-
+ tax is the same as that described for filename expansion, in the
+ ef_expand_file(@LIBR_MANEXT@ man page.
+
+
+</pre><h2>HISTORY FILES</h2><pre>
+ Authors of programs that use the Tecla library have the option of sav-
+ ing historical command-lines in a file before exiting, and subsequently
+ reading them back in from this file when the program is next started.
+ There is no standard name for this file, since it makes sense for each
+ application to use its own history file, so that commands from differ-
+ ent applications don't get mixed up.
+
+
+</pre><h2>INTERNATIONAL CHARACTER SETS</h2><pre>
+ Since libtecla version 1.4.0, Tecla has been 8-bit clean. This means
+ that all 8-bit characters that are printable in the user's current
+ locale are now displayed verbatim and included in the returned input
+ line. Assuming that the calling program correctly contains a call like
+ the following,
+
+ setlocale(LC_CTYPE, "");
+
+ then the current locale is determined by the first of the environment
+ variables LC_CTYPE, LC_ALL, and LANG, that is found to contain a valid
+ locale name. If none of these variables are defined, or the program
+ neglects to call setlocale, then the default C locale is used, which is
+ US 7-bit ASCII. On most unix-like platforms, you can get a list of
+ valid locales by typing the command:
+
+ locale -a
+
+ at the shell prompt.
+
+
+ Meta keys and locales
+ Beware that in most locales other than the default C locale, meta char-
+ acters become printable, and they are then no longer considered to
+ match M-c style key bindings. This allows international characters to
+ be entered with the compose key without unexpectedly triggering meta
+ key bindings. You can still invoke meta bindings, since there are actu-
+ ally two ways to do this. For example the binding M-c can also be
+ invoked by pressing the escape key momentarily, then pressing the c
+ key, and this will work regardless of locale. Moreover, many modern
+ terminal emulators, such as gnome's gnome-terminal's and KDE's konsole
+ terminals, already generate escape pairs like this when you use the
+ meta key, rather than a real meta character, and other emulators usu-
+ ally have a way to request this behavior, so you can continue to use
+ the meta key on most systems.
+
+ For example, although xterm terminal emulators generate real 8-bit meta
+ characters by default when you use the meta key, they can be configured
+ to output the equivalent escape pair by setting their EightBitInput X
+ resource to False. You can either do this by placing a line like the
+ following in your ~/.Xdefaults file,
+
+ XTerm*EightBitInput: False
+
+ or by starting an xterm with an -xrm '*EightBitInput: False' command-
+ line argument. In recent versions of xterm you can toggle this feature
+ on and off with the "Meta Sends Escape" option in the menu that is dis-
+ played when you press the left mouse button and the control key within
+ an xterm window. In CDE, dtterms can be similarly coerced to generate
+ escape pairs in place of meta characters, by setting the Dtterm*KshMode
+ resource to True.
+
+
+ Entering international characters
+ If you don't have a keyboard that generates all of the international
+ characters that you need, there is usually a compose key that will
+ allow you to enter special characters, or a way to create one. For
+ example, under X windows on unix-like systems, if your keyboard doesn't
+ have a compose key, you can designate a redundant key to serve this
+ purpose with the xmodmap command. For example, on many PC keyboards
+ there is a microsoft-windows key, which is otherwise useless under
+ Linux. On my laptop the xev program reports that pressing this key gen-
+ erates keycode 115, so to turn this key into a compose key, I do the
+ following:
+
+ xmodmap -e 'keycode 115 = Multi_key'
+
+ I can then enter an i with a umlaut over it by typing this key, fol-
+ lowed by ", followed by i.
+
+
+</pre><h2>THE AVAILABLE KEY BINDING FUNCTIONS</h2><pre>
+ The following is a list of the editing functions provided by the Tecla
+ library. The names in the leftmost column of the list can be used in
+ configuration files to specify which function a given key or combina-
+ tion of keys should invoke. They are also used in the next two sections
+ to list the default key-bindings in emacs and vi modes.
+
+ user-interrupt - Send a SIGINT signal to the
+ parent process.
+ abort - Send a SIGABRT signal to the
+ parent process.
+ suspend - Suspend the parent process.
+ stop-output - Pause terminal output.
+ start-output - Resume paused terminal output.
+ literal-next - Arrange for the next character
+ to be treated as a normal
+ character. This allows control
+ characters to be entered.
+ cursor-right - Move the cursor one character
+ right.
+ cursor-left - Move the cursor one character
+ left.
+ insert-mode - Toggle between insert mode and
+ overwrite mode.
+ beginning-of-line - Move the cursor to the
+ beginning of the line.
+ end-of-line - Move the cursor to the end of
+ the line.
+ delete-line - Delete the contents of the
+ current line.
+ kill-line - Delete everything that follows
+ the cursor.
+ backward-kill-line - Delete all characters between
+ the cursor and the start of the
+ line.
+ forward-word - Move to the end of the word
+ which follows the cursor.
+ forward-to-word - Move the cursor to the start of
+ the word that follows the
+ cursor.
+ backward-word - Move to the start of the word
+ which precedes the cursor.
+ goto-column - Move the cursor to the
+ 1-relative column in the line
+ specified by any preceding
+ digit-argument sequences (see
+ ENTERING REPEAT COUNTS below).
+ find-parenthesis - If the cursor is currently
+ over a parenthesis character,
+ move it to the matching
+ parenthesis character. If not
+ over a parenthesis character
+ move right to the next close
+ parenthesis.
+ forward-delete-char - Delete the character under the
+ cursor.
+ backward-delete-char - Delete the character which
+ precedes the cursor.
+ list-or-eof - This is intended for binding
+ to ^D. When invoked when the
+ cursor is within the line it
+ displays all possible
+ completions then redisplays
+ the line unchanged. When
+ invoked on an empty line, it
+ signals end-of-input (EOF) to
+ the caller of gl_get_line().
+ del-char-or-list-or-eof - This is intended for binding
+ to ^D. When invoked when the
+ cursor is within the line it
+ invokes forward-delete-char.
+ When invoked at the end of the
+ line it displays all possible
+ completions then redisplays
+ the line unchanged. When
+ invoked on an empty line, it
+ signals end-of-input (EOF) to
+ the caller of gl_get_line().
+ forward-delete-word - Delete the word which follows
+ the cursor.
+ backward-delete-word - Delete the word which precedes
+ the cursor.
+ upcase-word - Convert all of the characters
+ of the word which follows the
+ cursor, to upper case.
+ downcase-word - Convert all of the characters
+ of the word which follows the
+ cursor, to lower case.
+ capitalize-word - Capitalize the word which
+ follows the cursor.
+ change-case - If the next character is upper
+ case, toggle it to lower case
+ and vice versa.
+ redisplay - Redisplay the line.
+ clear-screen - Clear the terminal, then
+ redisplay the current line.
+ transpose-chars - Swap the character under the
+ cursor with the character just
+ before the cursor.
+ set-mark - Set a mark at the position of
+ the cursor.
+ exchange-point-and-mark - Move the cursor to the last
+ mark that was set, and move
+ the mark to where the cursor
+ used to be.
+ kill-region - Delete the characters that lie
+ between the last mark that was
+ set, and the cursor.
+ copy-region-as-kill - Copy the text between the mark
+ and the cursor to the cut
+ buffer, without deleting the
+ original text.
+ yank - Insert the text that was last
+ deleted, just before the
+ current position of the cursor.
+ append-yank - Paste the current contents of
+ the cut buffer, after the
+ cursor.
+ up-history - Recall the next oldest line
+ that was entered. Note that
+ in vi mode you are left in
+ command mode.
+ down-history - Recall the next most recent
+ line that was entered. If no
+ history recall session is
+ currently active, the next
+ line from a previous recall
+ session is recalled. Note that
+ in vi mode you are left in
+ command mode.
+ history-search-backward - Recall the next oldest line
+ who's prefix matches the string
+ which currently precedes the
+ cursor (in vi command-mode the
+ character under the cursor is
+ also included in the search
+ string). Note that in vi mode
+ you are left in command mode.
+ history-search-forward - Recall the next newest line
+ who's prefix matches the string
+ which currently precedes the
+ cursor (in vi command-mode the
+ character under the cursor is
+ also included in the search
+ string). Note that in vi mode
+ you are left in command mode.
+ history-re-search-backward -Recall the next oldest line
+ who's prefix matches that
+ established by the last
+ invocation of either
+ history-search-forward or
+ history-search-backward.
+ history-re-search-forward - Recall the next newest line
+ who's prefix matches that
+ established by the last
+ invocation of either
+ history-search-forward or
+ history-search-backward.
+ complete-word - Attempt to complete the
+ incomplete word which
+ precedes the cursor. Unless
+ the host program has customized
+ word completion, filename
+ completion is attempted. In vi
+ commmand mode the character
+ under the cursor is also
+ included in the word being
+ completed, and you are left in
+ vi insert mode.
+ expand-filename - Within the command line, expand
+ wild cards, tilde expressions
+ and dollar expressions in the
+ filename which immediately
+ precedes the cursor. In vi
+ commmand mode the character
+ under the cursor is also
+ included in the filename being
+ expanded, and you are left in
+ vi insert mode.
+ list-glob - List any filenames which match
+ the wild-card, tilde and dollar
+ expressions in the filename
+ which immediately precedes the
+ cursor, then redraw the input
+ line unchanged.
+ list-history - Display the contents of the
+ history list for the current
+ history group. If a repeat
+ count of &gt; 1 is specified,
+ only that many of the most
+ recent lines are displayed.
+ See the "ENTERING REPEAT
+ COUNTS" section.
+ read-from-file - Temporarily switch to reading
+ input from the file who's
+ name precedes the cursor.
+ read-init-files - Re-read teclarc configuration
+ files.
+ beginning-of-history - Move to the oldest line in the
+ history list. Note that in vi
+ mode you are left in command
+ mode.
+ end-of-history - Move to the newest line in the
+ history list (ie. the current
+ line). Note that in vi mode
+ this leaves you in command
+ mode.
+ digit-argument - Enter a repeat count for the
+ next key-binding function.
+ For details, see the ENTERING
+ REPEAT COUNTS section.
+ newline - Terminate and return the
+ current contents of the
+ line, after appending a
+ newline character. The newline
+ character is normally '\n',
+ but will be the first
+ character of the key-sequence
+ that invoked the newline
+ action, if this happens to be
+ a printable character. If the
+ action was invoked by the
+ '\n' newline character or the
+ '\r' carriage return
+ character, the line is
+ appended to the history
+ buffer.
+ repeat-history - Return the line that is being
+ edited, then arrange for the
+ next most recent entry in the
+ history buffer to be recalled
+ when Tecla is next called.
+ Repeatedly invoking this
+ action causes successive
+ historical input lines to be
+ re-executed. Note that this
+ action is equivalent to the
+ 'Operate' action in ksh.
+ ring-bell - Ring the terminal bell, unless
+ the bell has been silenced via
+ the nobeep configuration
+ option (see the THE TECLA
+ CONFIGURATION FILE section).
+ forward-copy-char - Copy the next character into
+ the cut buffer (NB. use repeat
+ counts to copy more than one).
+ backward-copy-char - Copy the previous character
+ into the cut buffer.
+ forward-copy-word - Copy the next word into the cut
+ buffer.
+ backward-copy-word - Copy the previous word into the
+ cut buffer.
+ forward-find-char - Move the cursor to the next
+ occurrence of the next
+ character that you type.
+ backward-find-char - Move the cursor to the last
+ occurrence of the next
+ character that you type.
+ forward-to-char - Move the cursor to the
+ character just before the next
+ occurrence of the next
+ character that the user types.
+ backward-to-char - Move the cursor to the
+ character just after the last
+ occurrence before the cursor
+ of the next character that the
+ user types.
+ repeat-find-char - Repeat the last
+ backward-find-char,
+ forward-find-char,
+ backward-to-char or
+ forward-to-char.
+ invert-refind-char - Repeat the last
+ backward-find-char,
+ forward-find-char,
+ backward-to-char, or
+ forward-to-char in the
+ opposite direction.
+ delete-to-column - Delete the characters from the
+ cursor up to the column that
+ is specified by the repeat
+ count.
+ delete-to-parenthesis - Delete the characters from the
+ cursor up to and including
+ the matching parenthesis, or
+ next close parenthesis.
+ forward-delete-find - Delete the characters from the
+ cursor up to and including the
+ following occurence of the
+ next character typed.
+ backward-delete-find - Delete the characters from the
+ cursor up to and including the
+ preceding occurence of the
+ next character typed.
+ forward-delete-to - Delete the characters from the
+ cursor up to, but not
+ including, the following
+ occurence of the next
+ character typed.
+ backward-delete-to - Delete the characters from the
+ cursor up to, but not
+ including, the preceding
+ occurence of the next
+ character typed.
+ delete-refind - Repeat the last *-delete-find
+ or *-delete-to action.
+ delete-invert-refind - Repeat the last *-delete-find
+ or *-delete-to action, in the
+ opposite direction.
+ copy-to-column - Copy the characters from the
+ cursor up to the column that
+ is specified by the repeat
+ count, into the cut buffer.
+ copy-to-parenthesis - Copy the characters from the
+ cursor up to and including
+ the matching parenthesis, or
+ next close parenthesis, into
+ the cut buffer.
+ forward-copy-find - Copy the characters from the
+ cursor up to and including the
+ following occurence of the
+ next character typed, into the
+ cut buffer.
+ backward-copy-find - Copy the characters from the
+ cursor up to and including the
+ preceding occurence of the
+ next character typed, into the
+ cut buffer.
+ forward-copy-to - Copy the characters from the
+ cursor up to, but not
+ including, the following
+ occurence of the next
+ character typed, into the cut
+ buffer.
+ backward-copy-to - Copy the characters from the
+ cursor up to, but not
+ including, the preceding
+ occurence of the next
+ character typed, into the cut
+ buffer.
+ copy-refind - Repeat the last *-copy-find
+ or *-copy-to action.
+ copy-invert-refind - Repeat the last *-copy-find
+ or *-copy-to action, in the
+ opposite direction.
+ vi-mode - Switch to vi mode from emacs
+ mode.
+ emacs-mode - Switch to emacs mode from vi
+ mode.
+ vi-insert - From vi command mode, switch to
+ insert mode.
+ vi-overwrite - From vi command mode, switch to
+ overwrite mode.
+ vi-insert-at-bol - From vi command mode, move the
+ cursor to the start of the line
+ and switch to insert mode.
+ vi-append-at-eol - From vi command mode, move the
+ cursor to the end of the line
+ and switch to append mode.
+ vi-append - From vi command mode, move the
+ cursor one position right, and
+ switch to insert mode.
+ vi-replace-char - From vi command mode, replace
+ the character under the cursor
+ with the the next character
+ entered.
+ vi-forward-change-char - From vi command mode, delete
+ the next character then enter
+ insert mode.
+ vi-backward-change-char - From vi command mode, delete
+ the preceding character then
+ enter insert mode.
+ vi-forward-change-word - From vi command mode, delete
+ the next word then enter
+ insert mode.
+ vi-backward-change-word - From vi command mode, delete
+ the preceding word then
+ enter insert mode.
+ vi-change-rest-of-line - From vi command mode, delete
+ from the cursor to the end of
+ the line, then enter insert
+ mode.
+ vi-change-line - From vi command mode, delete
+ the current line, then enter
+ insert mode.
+ vi-change-to-bol - From vi command mode, delete
+ all characters between the
+ cursor and the beginning of
+ the line, then enter insert
+ mode.
+ vi-change-to-column - From vi command mode, delete
+ the characters from the cursor
+ up to the column that is
+ specified by the repeat count,
+ then enter insert mode.
+ vi-change-to-parenthesis - Delete the characters from the
+ cursor up to and including
+ the matching parenthesis, or
+ next close parenthesis, then
+ enter vi insert mode.
+ vi-forward-change-find - From vi command mode, delete
+ the characters from the
+ cursor up to and including the
+ following occurence of the
+ next character typed, then
+ enter insert mode.
+ vi-backward-change-find - From vi command mode, delete
+ the characters from the
+ cursor up to and including the
+ preceding occurence of the
+ next character typed, then
+ enter insert mode.
+ vi-forward-change-to - From vi command mode, delete
+ the characters from the
+ cursor up to, but not
+ including, the following
+ occurence of the next
+ character typed, then enter
+ insert mode.
+ vi-backward-change-to - From vi command mode, delete
+ the characters from the
+ cursor up to, but not
+ including, the preceding
+ occurence of the next
+ character typed, then enter
+ insert mode.
+ vi-change-refind - Repeat the last
+ vi-*-change-find or
+ vi-*-change-to action.
+ vi-change-invert-refind - Repeat the last
+ vi-*-change-find or
+ vi-*-change-to action, in the
+ opposite direction.
+ vi-undo - In vi mode, undo the last
+ editing operation.
+ vi-repeat-change - In vi command mode, repeat the
+ last command that modified the
+ line.
+
+
+</pre><h2>DEFAULT KEY BINDINGS IN EMACS MODE</h2><pre>
+ The following default key bindings, which can be overriden by the Tecla
+ configuration file, are designed to mimic most of the bindings of the
+ unix tcsh shell, when it is in emacs editing mode.
+
+ This is the default editing mode of the Tecla library.
+
+ Under UNIX the terminal driver sets a number of special keys for cer-
+ tain functions. The tecla library attempts to use the same keybindings
+ to maintain consistency. The key sequences shown for the following 6
+ bindings are thus just examples of what they will probably be set to.
+ If you have used the stty command to change these keys, then the
+ default bindings should match.
+
+ ^C -&gt; user-interrupt
+ ^\ -&gt; abort
+ ^Z -&gt; suspend
+ ^Q -&gt; start-output
+ ^S -&gt; stop-output
+ ^V -&gt; literal-next
+
+ The cursor keys are refered to by name, as follows. This is necessary
+ because different types of terminals generate different key sequences
+ when their cursor keys are pressed.
+
+ right -&gt; cursor-right
+ left -&gt; cursor-left
+ up -&gt; up-history
+ down -&gt; down-history
+
+ The remaining bindings don't depend on the terminal setttings.
+
+ ^F -&gt; cursor-right
+ ^B -&gt; cursor-left
+ M-i -&gt; insert-mode
+ ^A -&gt; beginning-of-line
+ ^E -&gt; end-of-line
+ ^U -&gt; delete-line
+ ^K -&gt; kill-line
+ M-f -&gt; forward-word
+ M-b -&gt; backward-word
+ ^D -&gt; del-char-or-list-or-eof
+ ^H -&gt; backward-delete-char
+ ^? -&gt; backward-delete-char
+ M-d -&gt; forward-delete-word
+ M-^H -&gt; backward-delete-word
+ M-^? -&gt; backward-delete-word
+ M-u -&gt; upcase-word
+ M-l -&gt; downcase-word
+ M-c -&gt; capitalize-word
+ ^R -&gt; redisplay
+ ^L -&gt; clear-screen
+ ^T -&gt; transpose-chars
+ ^@ -&gt; set-mark
+ ^X^X -&gt; exchange-point-and-mark
+ ^W -&gt; kill-region
+ M-w -&gt; copy-region-as-kill
+ ^Y -&gt; yank
+ ^P -&gt; up-history
+ ^N -&gt; down-history
+ M-p -&gt; history-search-backward
+ M-n -&gt; history-search-forward
+ ^I -&gt; complete-word
+ ^X* -&gt; expand-filename
+ ^X^F -&gt; read-from-file
+ ^X^R -&gt; read-init-files
+ ^Xg -&gt; list-glob
+ ^Xh -&gt; list-history
+ M-&lt; -&gt; beginning-of-history
+ M-&gt; -&gt; end-of-history
+ \n -&gt; newline
+ \r -&gt; newline
+ M-o -&gt; repeat-history
+ M-^V -&gt; vi-mode
+
+ M-0, M-1, ... M-9 -&gt; digit-argument (see below)
+
+ Note that ^I is what the TAB key generates, and that ^@ can be gener-
+ ated not only by pressing the control key and the @ key simultaneously,
+ but also by pressing the control key and the space bar at the same
+ time.
+
+
+</pre><h2>DEFAULT KEY BINDINGS IN VI MODE</h2><pre>
+ The following default key bindings are designed to mimic the vi style
+ of editing as closely as possible. This means that very few editing
+ functions are provided in the initial character input mode, editing
+ functions instead being provided by the vi command mode. Vi command
+ mode is entered whenever the escape character is pressed, or whenever a
+ key-sequence that starts with a meta character is entered. In addition
+ to mimicing vi, libtecla provides bindings for tab completion, wild-
+ card expansion of file names, and historical line recall.
+
+ To learn how to tell the Tecla library to use vi mode instead of the
+ default emacs editing mode, see the earlier section entitled THE TECLA
+ CONFIGURATION FILE.
+
+ Under UNIX the terminal driver sets a number of special keys for cer-
+ tain functions. The Tecla library attempts to use the same keybindings
+ to maintain consistency, binding them both in input mode and in command
+ mode. The key sequences shown for the following 6 bindings are thus
+ just examples of what they will probably be set to. If you have used
+ the stty command to change these keys, then the default bindings should
+ match.
+
+ ^C -&gt; user-interrupt
+ ^\ -&gt; abort
+ ^Z -&gt; suspend
+ ^Q -&gt; start-output
+ ^S -&gt; stop-output
+ ^V -&gt; literal-next
+ M-^C -&gt; user-interrupt
+ M-^\ -&gt; abort
+ M-^Z -&gt; suspend
+ M-^Q -&gt; start-output
+ M-^S -&gt; stop-output
+
+ Note that above, most of the bindings are defined twice, once as a raw
+ control code like ^C and then a second time as a meta character like
+ M-^C. The former is the binding for vi input mode, whereas the latter
+ is the binding for vi command mode. Once in command mode all key-
+ sequences that the user types that they don't explicitly start with an
+ escape or a meta key, have their first key secretly converted to a meta
+ character before the key sequence is looked up in the key binding ta-
+ ble. Thus, once in command mode, when you type the letter i, for exam-
+ ple, the Tecla library actually looks up the binding for M-i.
+
+ The cursor keys are refered to by name, as follows. This is necessary
+ because different types of terminals generate different key sequences
+ when their cursor keys are pressed.
+
+ right -&gt; cursor-right
+ left -&gt; cursor-left
+ up -&gt; up-history
+ down -&gt; down-history
+
+ The cursor keys normally generate a keysequence that start with an
+ escape character, so beware that using the arrow keys will put you into
+ command mode (if you aren't already in command mode).
+
+ The following are the terminal-independent key bindings for vi input
+ mode.
+
+ ^D -&gt; list-or-eof
+ ^G -&gt; list-glob
+ ^H -&gt; backward-delete-char
+ ^I -&gt; complete-word
+ \r -&gt; newline
+ \n -&gt; newline
+ ^L -&gt; clear-screen
+ ^N -&gt; down-history
+ ^P -&gt; up-history
+ ^R -&gt; redisplay
+ ^U -&gt; backward-kill-line
+ ^W -&gt; backward-delete-word
+ ^X* -&gt; expand-filename
+ ^X^F -&gt; read-from-file
+ ^X^R -&gt; read-init-files
+ ^? -&gt; backward-delete-char
+
+ The following are the key bindings that are defined in vi command mode,
+ this being specified by them all starting with a meta character. As
+ mentioned above, once in command mode the initial meta character is
+ optional. For example, you might enter command mode by typing Esc, and
+ then press h twice to move the cursor two positions to the left. Both h
+ characters get quietly converted to M-h before being compared to the
+ key-binding table, the first one because Escape followed by a character
+ is always converted to the equivalent meta character, and the second
+ because command mode was already active.
+
+ M-\ -&gt; cursor-right (Meta-space)
+ M-$ -&gt; end-of-line
+ M-* -&gt; expand-filename
+ M-+ -&gt; down-history
+ M-- -&gt; up-history
+ M-&lt; -&gt; beginning-of-history
+ M-&gt; -&gt; end-of-history
+ M-^ -&gt; beginning-of-line
+ M-; -&gt; repeat-find-char
+ M-, -&gt; invert-refind-char
+ M-| -&gt; goto-column
+ M-~ -&gt; change-case
+ M-. -&gt; vi-repeat-change
+ M-% -&gt; find-parenthesis
+ M-a -&gt; vi-append
+ M-A -&gt; vi-append-at-eol
+ M-b -&gt; backward-word
+ M-B -&gt; backward-word
+ M-C -&gt; vi-change-rest-of-line
+ M-cb -&gt; vi-backward-change-word
+ M-cB -&gt; vi-backward-change-word
+ M-cc -&gt; vi-change-line
+ M-ce -&gt; vi-forward-change-word
+ M-cE -&gt; vi-forward-change-word
+ M-cw -&gt; vi-forward-change-word
+ M-cW -&gt; vi-forward-change-word
+ M-cF -&gt; vi-backward-change-find
+ M-cf -&gt; vi-forward-change-find
+ M-cT -&gt; vi-backward-change-to
+ M-ct -&gt; vi-forward-change-to
+ M-c; -&gt; vi-change-refind
+ M-c, -&gt; vi-change-invert-refind
+ M-ch -&gt; vi-backward-change-char
+ M-c^H -&gt; vi-backward-change-char
+ M-c^? -&gt; vi-backward-change-char
+ M-cl -&gt; vi-forward-change-char
+ M-c\ -&gt; vi-forward-change-char (Meta-c-space)
+ M-c^ -&gt; vi-change-to-bol
+ M-c0 -&gt; vi-change-to-bol
+ M-c$ -&gt; vi-change-rest-of-line
+ M-c| -&gt; vi-change-to-column
+ M-c% -&gt; vi-change-to-parenthesis
+ M-dh -&gt; backward-delete-char
+ M-d^H -&gt; backward-delete-char
+ M-d^? -&gt; backward-delete-char
+ M-dl -&gt; forward-delete-char
+ M-d -&gt; forward-delete-char (Meta-d-space)
+ M-dd -&gt; delete-line
+ M-db -&gt; backward-delete-word
+ M-dB -&gt; backward-delete-word
+ M-de -&gt; forward-delete-word
+ M-dE -&gt; forward-delete-word
+ M-dw -&gt; forward-delete-word
+ M-dW -&gt; forward-delete-word
+ M-dF -&gt; backward-delete-find
+ M-df -&gt; forward-delete-find
+ M-dT -&gt; backward-delete-to
+ M-dt -&gt; forward-delete-to
+ M-d; -&gt; delete-refind
+ M-d, -&gt; delete-invert-refind
+ M-d^ -&gt; backward-kill-line
+ M-d0 -&gt; backward-kill-line
+ M-d$ -&gt; kill-line
+ M-D -&gt; kill-line
+ M-d| -&gt; delete-to-column
+ M-d% -&gt; delete-to-parenthesis
+ M-e -&gt; forward-word
+ M-E -&gt; forward-word
+ M-f -&gt; forward-find-char
+ M-F -&gt; backward-find-char
+ M-- -&gt; up-history
+ M-h -&gt; cursor-left
+ M-H -&gt; beginning-of-history
+ M-i -&gt; vi-insert
+ M-I -&gt; vi-insert-at-bol
+ M-j -&gt; down-history
+ M-J -&gt; history-search-forward
+ M-k -&gt; up-history
+ M-K -&gt; history-search-backward
+ M-l -&gt; cursor-right
+ M-L -&gt; end-of-history
+ M-n -&gt; history-re-search-forward
+ M-N -&gt; history-re-search-backward
+ M-p -&gt; append-yank
+ M-P -&gt; yank
+ M-r -&gt; vi-replace-char
+ M-R -&gt; vi-overwrite
+ M-s -&gt; vi-forward-change-char
+ M-S -&gt; vi-change-line
+ M-t -&gt; forward-to-char
+ M-T -&gt; backward-to-char
+ M-u -&gt; vi-undo
+ M-w -&gt; forward-to-word
+ M-W -&gt; forward-to-word
+ M-x -&gt; forward-delete-char
+ M-X -&gt; backward-delete-char
+ M-yh -&gt; backward-copy-char
+ M-y^H -&gt; backward-copy-char
+ M-y^? -&gt; backward-copy-char
+ M-yl -&gt; forward-copy-char
+ M-y\ -&gt; forward-copy-char (Meta-y-space)
+ M-ye -&gt; forward-copy-word
+ M-yE -&gt; forward-copy-word
+ M-yw -&gt; forward-copy-word
+ M-yW -&gt; forward-copy-word
+ M-yb -&gt; backward-copy-word
+ M-yB -&gt; backward-copy-word
+ M-yf -&gt; forward-copy-find
+ M-yF -&gt; backward-copy-find
+ M-yt -&gt; forward-copy-to
+ M-yT -&gt; backward-copy-to
+ M-y; -&gt; copy-refind
+ M-y, -&gt; copy-invert-refind
+ M-y^ -&gt; copy-to-bol
+ M-y0 -&gt; copy-to-bol
+ M-y$ -&gt; copy-rest-of-line
+ M-yy -&gt; copy-line
+ M-Y -&gt; copy-line
+ M-y| -&gt; copy-to-column
+ M-y% -&gt; copy-to-parenthesis
+ M-^E -&gt; emacs-mode
+ M-^H -&gt; cursor-left
+ M-^? -&gt; cursor-left
+ M-^L -&gt; clear-screen
+ M-^N -&gt; down-history
+ M-^P -&gt; up-history
+ M-^R -&gt; redisplay
+ M-^D -&gt; list-or-eof
+ M-^I -&gt; complete-word
+ M-\r -&gt; newline
+ M-\n -&gt; newline
+ M-^X^R -&gt; read-init-files
+ M-^Xh -&gt; list-history
+
+ M-0, M-1, ... M-9 -&gt; digit-argument (see below)
+
+ Note that ^I is what the TAB key generates.
+
+
+</pre><h2>ENTERING REPEAT COUNTS</h2><pre>
+ Many of the key binding functions described previously, take an
+ optional count, typed in before the target keysequence. This is inter-
+ preted as a repeat count by most bindings. A notable exception is the
+ goto-column binding, which interprets the count as a column number.
+
+ By default you can specify this count argument by pressing the meta key
+ while typing in the numeric count. This relies on the digit-argument
+ action being bound to Meta-0, Meta-1 etc. Once any one of these bind-
+ ings has been activated, you can optionally take your finger off the
+ meta key to type in the rest of the number, since every numeric digit
+ thereafter is treated as part of the number, unless it is preceded by
+ the literal-next binding. As soon as a non-digit, or literal digit key
+ is pressed the repeat count is terminated and either causes the just
+ typed character to be added to the line that many times, or causes the
+ next key-binding function to be given that argument.
+
+ For example, in emacs mode, typing:
+
+ M-12a
+
+ causes the letter 'a' to be added to the line 12 times, whereas
+
+ M-4M-c
+
+ Capitalizes the next 4 words.
+
+ In vi command mode the Meta modifier is automatically added to all
+ characters typed in, so to enter a count in vi command-mode, just
+ involves typing in the number, just as it does in the vi editor itself.
+ So for example, in vi command mode, typing:
+
+ 4w2x
+
+ moves the cursor four words to the right, then deletes two characters.
+
+ You can also bind digit-argument to other key sequences. If these end
+ in a numeric digit, that digit gets appended to the current repeat
+ count. If it doesn't end in a numeric digit, a new repeat count is
+ started with a value of zero, and can be completed by typing in the
+ number, after letting go of the key which triggered the digit-argument
+ action.
+
+
+</pre><h2>FILES</h2><pre>
+ libtecla.a - The Tecla library
+ libtecla.h - The Tecla header file.
+ ~/.teclarc - The personal Tecla customization file.
+
+
+</pre><h2>SEE ALSO</h2><pre>
+ <a href="libtecla.html"><b>libtecla</b></a>, <a href="gl_get_line.html"><b>gl_get_line</b></a>, <a href="gl_io_mode.html"><b>gl_io_mode</b></a>, <a href="ef_expand_file.html"><b>ef_expand_file</b></a>,
+ <a href="cpl_complete_word.html"><b>cpl_complete_word</b></a>, <a href="pca_lookup_file.html"><b>pca_lookup_file</b></a>
+
+
+</pre><h2>AUTHOR</h2><pre>
+ Martin Shepherd (mcs@astro.caltech.edu)
+
+
+
+ <a href="tecla.html"><b>tecla</b></a>
+</pre>
+</body>
diff --git a/libtecla-1.4.1/install-sh b/libtecla-1.6.1/install-sh
index e9de238..e9de238 100755
--- a/libtecla-1.4.1/install-sh
+++ b/libtecla-1.6.1/install-sh
diff --git a/libtecla-1.6.1/ioutil.c b/libtecla-1.6.1/ioutil.c
new file mode 100644
index 0000000..daf02c9
--- /dev/null
+++ b/libtecla-1.6.1/ioutil.c
@@ -0,0 +1,330 @@
+/*
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
+ *
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, and/or sell copies of the Software, and to permit persons
+ * to whom the Software is furnished to do so, provided that the above
+ * copyright notice(s) and this permission notice appear in all copies of
+ * the Software and that both the above copyright notice(s) and this
+ * permission notice appear in supporting documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+ * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
+ * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder
+ * shall not be used in advertising or otherwise to promote the sale, use
+ * or other dealings in this Software without prior written authorization
+ * of the copyright holder.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "ioutil.h"
+
+static int _io_pad_line(GlWriteFn *write_fn, void *data, int c, int n);
+
+/*.......................................................................
+ * Display a left-justified string over multiple terminal lines,
+ * taking account of the specified width of the terminal. Optional
+ * indentation and an option prefix string can be specified to be
+ * displayed at the start of each new terminal line used, and if
+ * needed, a single paragraph can be broken across multiple calls.
+ * Note that literal newlines in the input string can be used to force
+ * a newline at any point, and that in order to allow individual
+ * paragraphs to be written using multiple calls to this function,
+ * unless an explicit newline character is specified at the end of the
+ * string, a newline will not be started at the end of the last word
+ * in the string. Note that when a new line is started between two
+ * words that are separated by spaces, those spaces are not output,
+ * whereas when a new line is started because a newline character was
+ * found in the string, only the spaces before the newline character
+ * are discarded.
+ *
+ * Input:
+ * write_fn GlWriteFn * The callback function to use to write the
+ * output.
+ * data void * A pointer to arbitrary data to be passed to
+ * write_fn() whenever it is called.
+ * fp FILE * The stdio stream to write to.
+ * indentation int The number of fill characters to use to
+ * indent the start of each new terminal line.
+ * prefix const char * An optional prefix string to write after the
+ * indentation margin at the start of each new
+ * terminal line. You can specify NULL if no
+ * prefix is required.
+ * suffix const char * An optional suffix string to draw at the end
+ * of the terminal line. The line will be padded
+ * where necessary to ensure that the suffix ends
+ * in the last column of the terminal line. If
+ * no suffix is desired, specify NULL.
+ * fill_char int The padding character to use when indenting
+ * and filling up to the suffix.
+ * term_width int The width of the terminal being written to.
+ * start int The number of characters already written to
+ * the start of the current terminal line. This
+ * is primarily used to allow individual
+ * paragraphs to be written over multiple calls
+ * to this function, but can also be used to
+ * allow you to start the first line of a
+ * paragraph with a different prefix or
+ * indentation than those specified above.
+ * string const char * The string to be written.
+ * Output:
+ * return int On error -1 is returned. Otherwise the
+ * return value is the terminal column index at
+ * which the cursor was left after writing the
+ * final word in the string. Successful return
+ * values can thus be passed verbatim to the
+ * 'start' arguments of subsequent calls to
+ * _io_display_text() to allow the printing of a
+ * paragraph to be broken across multiple calls
+ * to _io_display_text().
+ */
+int _io_display_text(GlWriteFn *write_fn, void *data, int indentation,
+ const char *prefix, const char *suffix, int fill_char,
+ int term_width, int start, const char *string)
+{
+ int ndone; /* The number of characters written from string[] */
+ int nnew; /* The number of characters to be displayed next */
+ int was_space; /* True if the previous character was a space or tab */
+ int last = start; /* The column number of the last character written */
+ int prefix_len; /* The length of the optional line prefix string */
+ int suffix_len; /* The length of the optional line prefix string */
+ int margin_width; /* The total number of columns used by the indentation */
+ /* margin and the prefix string. */
+ int i;
+/*
+ * Check the arguments?
+ */
+ if(!string || !write_fn) {
+ errno = EINVAL;
+ return -1;
+ };
+/*
+ * Enforce sensible values on the arguments.
+ */
+ if(term_width < 0)
+ term_width = 0;
+ if(indentation > term_width)
+ indentation = term_width;
+ else if(indentation < 0)
+ indentation = 0;
+ if(start > term_width)
+ start = term_width;
+ else if(start < 0)
+ start = 0;
+/*
+ * Get the length of the prefix string.
+ */
+ prefix_len = prefix ? strlen(prefix) : 0;
+/*
+ * Get the length of the suffix string.
+ */
+ suffix_len = suffix ? strlen(suffix) : 0;
+/*
+ * How many characters are devoted to indenting and prefixing each line?
+ */
+ margin_width = indentation + prefix_len;
+/*
+ * Write as many terminal lines as are needed to display the whole string.
+ */
+ for(ndone=0; string[ndone]; start=0) {
+ last = start;
+/*
+ * Write spaces from the current position in the terminal line to the
+ * width of the requested indentation margin.
+ */
+ if(indentation > 0 && last < indentation) {
+ if(_io_pad_line(write_fn, data, fill_char, indentation - last))
+ return -1;
+ last = indentation;
+ };
+/*
+ * If a prefix string has been specified, display it unless we have
+ * passed where it should end in the terminal output line.
+ */
+ if(prefix_len > 0 && last < margin_width) {
+ int pstart = last - indentation;
+ int plen = prefix_len - pstart;
+ if(write_fn(data, prefix+pstart, plen) != plen)
+ return -1;
+ last = margin_width;
+ };
+/*
+ * Locate the end of the last complete word in the string before
+ * (term_width - start) characters have been seen. To handle the case
+ * where a single word is wider than the available space after the
+ * indentation and prefix margins, always make sure that at least one
+ * word is printed after the margin, regardless of whether it won't
+ * fit on the line. The two exceptions to this rule are if an embedded
+ * newline is found in the string or the end of the string is reached
+ * before any word has been seen.
+ */
+ nnew = 0;
+ was_space = 0;
+ for(i=ndone; string[i] && (last+i-ndone < term_width - suffix_len ||
+ (nnew==0 && last==margin_width)); i++) {
+ if(string[i] == '\n') {
+ if(!was_space)
+ nnew = i-ndone;
+ break;
+ } else if(isspace((int) string[i])) {
+ if(!was_space) {
+ nnew = i-ndone+1;
+ was_space = 1;
+ };
+ } else {
+ was_space = 0;
+ };
+ };
+/*
+ * Does the end of the string delimit the last word that will fit on the
+ * output line?
+ */
+ if(nnew==0 && string[i] == '\0')
+ nnew = i-ndone;
+/*
+ * Write the new line.
+ */
+ if(write_fn(data, string+ndone, nnew) != nnew)
+ return -1;
+ ndone += nnew;
+ last += nnew;
+/*
+ * Start a newline unless we have reached the end of the input string.
+ * In the latter case, in order to give the caller the chance to
+ * concatenate multiple calls to _io_display_text(), omit the newline,
+ * leaving it up to the caller to write this.
+ */
+ if(string[ndone] != '\0') {
+/*
+ * If a suffix has been provided, pad out the end of the line with spaces
+ * such that the suffix will end in the right-most terminal column.
+ */
+ if(suffix_len > 0) {
+ int npad = term_width - suffix_len - last;
+ if(npad > 0 && _io_pad_line(write_fn, data, fill_char, npad))
+ return -1;
+ last += npad;
+ if(write_fn(data, suffix, suffix_len) != suffix_len)
+ return -1;
+ last += suffix_len;
+ };
+/*
+ * Start a new line.
+ */
+ if(write_fn(data, "\n", 1) != 1)
+ return -1;
+/*
+ * Skip any spaces and tabs that follow the last word that was written.
+ */
+ while(string[ndone] && isspace((int)string[ndone]) &&
+ string[ndone] != '\n')
+ ndone++;
+/*
+ * If the terminating character was a literal newline character,
+ * skip it in the input string, since we just wrote it.
+ */
+ if(string[ndone] == '\n')
+ ndone++;
+ last = 0;
+ };
+ };
+/*
+ * Return the column number of the last character printed.
+ */
+ return last;
+}
+
+/*.......................................................................
+ * Write a given number of spaces to the specified stdio output string.
+ *
+ * Input:
+ * write_fn GlWriteFn * The callback function to use to write the
+ * output.
+ * data void * A pointer to arbitrary data to be passed to
+ * write_fn() whenever it is called.
+ * c int The padding character.
+ * n int The number of spaces to be written.
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+static int _io_pad_line(GlWriteFn *write_fn, void *data, int c, int n)
+{
+ enum {FILL_SIZE=20};
+ char fill[FILL_SIZE+1];
+/*
+ * Fill the buffer with the specified padding character.
+ */
+ memset(fill, c, FILL_SIZE);
+ fill[FILL_SIZE] = '\0';
+/*
+ * Write the spaces using the above literal string of spaces as
+ * many times as needed to output the requested number of spaces.
+ */
+ while(n > 0) {
+ int nnew = n <= FILL_SIZE ? n : FILL_SIZE;
+ if(write_fn(data, fill, nnew) != nnew)
+ return 1;
+ n -= nnew;
+ };
+ return 0;
+}
+
+/*.......................................................................
+ * The following is an output callback function which uses fwrite()
+ * to write to the stdio stream specified via its callback data argument.
+ *
+ * Input:
+ * data void * The stdio stream to write to, specified via a
+ * (FILE *) pointer cast to (void *).
+ * s const char * The string to be written.
+ * n int The length of the prefix of s[] to attempt to
+ * write.
+ * Output:
+ * return int The number of characters written from s[]. This
+ * should normally be a number in the range 0 to n.
+ * To signal that an I/O error occurred, return -1.
+ */
+GL_WRITE_FN(_io_write_stdio)
+{
+ int ndone; /* The total number of characters written */
+ int nnew; /* The number of characters written in the latest write */
+/*
+ * The callback data is the stdio stream to write to.
+ */
+ FILE *fp = (FILE *) data;
+/*
+ * Because of signals we may need to do more than one write to output
+ * the whole string.
+ */
+ for(ndone=0; ndone<n; ndone += nnew) {
+ int nmore = n - ndone;
+ nnew = fwrite(s, sizeof(char), nmore, fp);
+ if(nnew < nmore) {
+ if(errno == EINTR)
+ clearerr(fp);
+ else
+ return ferror(fp) ? -1 : ndone + nnew;
+ };
+ };
+ return ndone;
+}
+
diff --git a/libtecla-1.6.1/ioutil.h b/libtecla-1.6.1/ioutil.h
new file mode 100644
index 0000000..b9e8f16
--- /dev/null
+++ b/libtecla-1.6.1/ioutil.h
@@ -0,0 +1,73 @@
+#ifndef ioutil_h
+#define ioutil_h
+
+/*
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
+ *
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, and/or sell copies of the Software, and to permit persons
+ * to whom the Software is furnished to do so, provided that the above
+ * copyright notice(s) and this permission notice appear in all copies of
+ * the Software and that both the above copyright notice(s) and this
+ * permission notice appear in supporting documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+ * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
+ * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder
+ * shall not be used in advertising or otherwise to promote the sale, use
+ * or other dealings in this Software without prior written authorization
+ * of the copyright holder.
+ */
+
+/*.......................................................................
+ * Callback functions of the following type can be registered to write
+ * to a terminal, when the default blocking writes to a local terminal
+ * aren't appropriate. In particular, if you don't want gl_get_line()
+ * to block, then this function should return before writing the
+ * specified number of characters if doing otherwise would involve
+ * waiting.
+ *
+ * Input:
+ * data void * The anonymous data pointer that was registered with
+ * this callback function.
+ * s const char * The string to be written. Beware that this string
+ * may not have a terminating '\0' character.
+ * n int The length of the prefix of s[] to attempt to
+ * write.
+ * Output:
+ * return int The number of characters written from s[]. This
+ * should normally be a number in the range 0 to n.
+ * To signal that an I/O error occurred, return -1.
+ */
+#define GL_WRITE_FN(fn) int (fn)(void *data, const char *s, int n)
+typedef GL_WRITE_FN(GlWriteFn);
+
+/*
+ * The following output callback function requires a (FILE *) callback
+ * data argument, and writes to this stream using the fwrite stdio
+ * function.
+ */
+GL_WRITE_FN(_io_write_stdio);
+
+/*
+ * Left justify text within the bounds of the terminal adding optional
+ * indentation, prefixes and suffixes to each line if requested.
+ */
+int _io_display_text(GlWriteFn *write_fn, void *data, int indentation,
+ const char *prefix, const char *suffix, int fill_char,
+ int term_width, int start, const char *string);
+
+#endif
diff --git a/libtecla-1.4.1/keytab.c b/libtecla-1.6.1/keytab.c
index b2bab8b..0820960 100644
--- a/libtecla-1.4.1/keytab.c
+++ b/libtecla-1.6.1/keytab.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2001 by Martin C. Shepherd.
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
*
* All rights reserved.
*
@@ -33,19 +33,49 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
+#include <errno.h>
#include "keytab.h"
-#include "getline.h"
#include "strngmem.h"
+#include "getline.h"
+#include "errmsg.h"
+#include "hash.h"
+
+/*
+ * When allocating or reallocating the key-binding table, how
+ * many entries should be added?
+ */
+#define KT_TABLE_INC 100
+
+/*
+ * Define the size of the hash table that is used to associate action
+ * names with action functions. This should be a prime number.
+ */
+#define KT_HASH_SIZE 113
+
+/*
+ * Define a binary-symbol-table object.
+ */
+struct KeyTab {
+ ErrMsg *err; /* Information about the last error */
+ int size; /* The allocated dimension of table[] */
+ int nkey; /* The current number of members in the table */
+ KeySym *table; /* The table of lexically sorted key sequences */
+ HashTable *actions; /* The hash table of actions */
+ StringMem *smem; /* Memory for allocating strings */
+};
static int _kt_extend_table(KeyTab *kt);
static int _kt_parse_keybinding_string(const char *keyseq,
char *binary, int *nc);
static int _kt_compare_strings(const char *s1, int n1, const char *s2, int n2);
-static void _kt_assign_action(KeySym *sym, KtBinder binder, KtKeyFn *keyfn);
+static void _kt_assign_action(KeySym *sym, KtBinder binder, KtKeyFn *keyfn,
+ void *data);
static char _kt_backslash_escape(const char *string, const char **endp);
static int _kt_is_emacs_meta(const char *string);
static int _kt_is_emacs_ctrl(const char *string);
+static KtKeyMatch _kt_locate_keybinding(KeyTab *kt, const char *binary_keyseq,
+ int nc, int *first, int *last);
/*.......................................................................
* Create a new key-binding symbol table.
@@ -61,7 +91,7 @@ KeyTab *_new_KeyTab(void)
*/
kt = (KeyTab *) malloc(sizeof(KeyTab));
if(!kt) {
- fprintf(stderr, "new_KeyTab: Insufficient memory.\n");
+ errno = ENOMEM;
return NULL;
};
/*
@@ -69,18 +99,24 @@ KeyTab *_new_KeyTab(void)
* container at least up to the point at which it can safely be passed
* to del_KeyTab().
*/
+ kt->err = NULL;
kt->size = KT_TABLE_INC;
kt->nkey = 0;
kt->table = NULL;
kt->actions = NULL;
kt->smem = NULL;
/*
+ * Allocate a place to record error messages.
+ */
+ kt->err = _new_ErrMsg();
+ if(!kt->err)
+ return _del_KeyTab(kt);
+/*
* Allocate the table.
*/
kt->table = (KeySym *) malloc(sizeof(kt->table[0]) * kt->size);
if(!kt->table) {
- fprintf(stderr, "new_KeyTab: Insufficient memory for table of size %d.\n",
- kt->size);
+ errno = ENOMEM;
return _del_KeyTab(kt);
};
/*
@@ -93,7 +129,7 @@ KeyTab *_new_KeyTab(void)
* Allocate a string allocation object. This allows allocation of
* small strings without fragmenting the heap.
*/
- kt->smem = _new_StringMem("new_KeyTab", KT_TABLE_INC);
+ kt->smem = _new_StringMem(KT_TABLE_INC);
if(!kt->smem)
return _del_KeyTab(kt);
return kt;
@@ -113,7 +149,8 @@ KeyTab *_del_KeyTab(KeyTab *kt)
if(kt->table)
free(kt->table);
kt->actions = _del_HashTable(kt->actions);
- kt->smem = _del_StringMem("del_KeyTab", kt->smem, 1);
+ kt->smem = _del_StringMem(kt->smem, 1);
+ kt->err = _del_ErrMsg(kt->err);
free(kt);
};
return NULL;
@@ -139,8 +176,8 @@ static int _kt_extend_table(KeyTab *kt)
* Failed?
*/
if(!newtab) {
- fprintf(stderr,
- "getline(): Insufficient memory to extend keybinding table.\n");
+ _err_record_msg(kt->err, "Can't extend keybinding table", END_ERR_MSG);
+ errno = ENOMEM;
return 1;
};
/*
@@ -169,11 +206,14 @@ int _kt_set_keybinding(KeyTab *kt, KtBinder binder, const char *keyseq,
const char *action)
{
KtKeyFn *keyfn; /* The action function */
+ void *data; /* The callback data of the action function */
/*
* Check arguments.
*/
if(kt==NULL || !keyseq) {
- fprintf(stderr, "kt_set_keybinding: NULL argument(s).\n");
+ errno = EINVAL;
+ if(kt)
+ _err_record_msg(kt->err, "NULL argument(s)", END_ERR_MSG);
return 1;
};
/*
@@ -181,18 +221,22 @@ int _kt_set_keybinding(KeyTab *kt, KtBinder binder, const char *keyseq,
*/
if(!action) {
keyfn = 0;
+ data = NULL;
} else {
Symbol *sym = _find_HashSymbol(kt->actions, action);
if(!sym) {
- fprintf(stderr, "getline: Unknown key-binding action: %s\n", action);
+ _err_record_msg(kt->err, "Unknown key-binding action: ", action,
+ END_ERR_MSG);
+ errno = EINVAL;
return 1;
};
keyfn = (KtKeyFn *) sym->fn;
+ data = sym->data;
};
/*
* Record the action in the table.
*/
- return _kt_set_keyfn(kt, binder, keyseq, keyfn);
+ return _kt_set_keyfn(kt, binder, keyseq, keyfn, data);
}
/*.......................................................................
@@ -205,12 +249,14 @@ int _kt_set_keybinding(KeyTab *kt, KtBinder binder, const char *keyseq,
* keyseq char * The key-sequence to bind.
* keyfn KtKeyFn * The action function, or NULL to remove any existing
* action function.
+ * data void * A pointer to anonymous data to be passed to keyfn
+ * whenever it is called.
* Output:
* return int 0 - OK.
* 1 - Error.
*/
int _kt_set_keyfn(KeyTab *kt, KtBinder binder, const char *keyseq,
- KtKeyFn *keyfn)
+ KtKeyFn *keyfn, void *data)
{
const char *kptr; /* A pointer into keyseq[] */
char *binary; /* The binary version of keyseq[] */
@@ -218,11 +264,14 @@ int _kt_set_keyfn(KeyTab *kt, KtBinder binder, const char *keyseq,
int first,last; /* The first and last entries in the table which */
/* minimally match. */
int size; /* The size to allocate for the binary string */
+ int i;
/*
* Check arguments.
*/
if(kt==NULL || !keyseq) {
- fprintf(stderr, "kt_set_keybinding: NULL argument(s).\n");
+ errno = EINVAL;
+ if(kt)
+ _err_record_msg(kt->err, "NULL argument(s)", END_ERR_MSG);
return 1;
};
/*
@@ -237,8 +286,9 @@ int _kt_set_keyfn(KeyTab *kt, KtBinder binder, const char *keyseq,
*/
binary = _new_StringMemString(kt->smem, size + 1);
if(!binary) {
- fprintf(stderr,
- "gl_get_line: Insufficient memory to record key sequence.\n");
+ errno = ENOMEM;
+ _err_record_msg(kt->err, "Insufficient memory to record key sequence",
+ END_ERR_MSG);
return 1;
};
/*
@@ -251,7 +301,7 @@ int _kt_set_keyfn(KeyTab *kt, KtBinder binder, const char *keyseq,
/*
* Lookup the position in the table at which to insert the binding.
*/
- switch(_kt_lookup_keybinding(kt, binary, nc, &first, &last)) {
+ switch(_kt_locate_keybinding(kt, binary, nc, &first, &last)) {
/*
* If an exact match for the key-sequence is already in the table,
* simply replace its binding function (or delete the entry if
@@ -259,7 +309,7 @@ int _kt_set_keyfn(KeyTab *kt, KtBinder binder, const char *keyseq,
*/
case KT_EXACT_MATCH:
if(keyfn) {
- _kt_assign_action(kt->table + first, binder, keyfn);
+ _kt_assign_action(kt->table + first, binder, keyfn, data);
} else {
_del_StringMemString(kt->smem, kt->table[first].keyseq);
memmove(kt->table + first, kt->table + first + 1,
@@ -275,10 +325,11 @@ int _kt_set_keyfn(KeyTab *kt, KtBinder binder, const char *keyseq,
*/
case KT_AMBIG_MATCH:
if(keyfn) {
- fprintf(stderr,
- "getline: Can't bind \"%s\", because it's a prefix of another binding.\n",
- keyseq);
+ _err_record_msg(kt->err, "Can't bind \"", keyseq,
+ "\", because it is a prefix of another binding",
+ END_ERR_MSG);
binary = _del_StringMemString(kt->smem, binary);
+ errno = EPERM;
return 1;
};
break;
@@ -313,8 +364,13 @@ int _kt_set_keyfn(KeyTab *kt, KtBinder binder, const char *keyseq,
sym = kt->table + last;
sym->keyseq = binary;
sym->nc = nc;
- sym->user_fn = sym->term_fn = sym->norm_fn = sym->keyfn = 0;
- _kt_assign_action(sym, binder, keyfn);
+ for(i=0; i<KTB_NBIND; i++) {
+ KtAction *action = sym->actions + i;
+ action->fn = 0;
+ action->data = NULL;
+ };
+ sym->binder = -1;
+ _kt_assign_action(sym, binder, keyfn, data);
kt->nkey++;
};
break;
@@ -330,39 +386,31 @@ int _kt_set_keyfn(KeyTab *kt, KtBinder binder, const char *keyseq,
* Perform a min-match lookup of a key-binding.
*
* Input:
- * kt KeyTab * The keybinding table to lookup in.
- * binary_keyseq char * The binary key-sequence to lookup.
- * nc int the number of characters in keyseq[].
+ * kt KeyTab * The keybinding table to lookup in.
+ * binary_keyseq char * The binary key-sequence to lookup.
+ * nc int the number of characters in keyseq[].
* Input/Output:
- * first,last int * If there is an ambiguous or exact match, the indexes
- * of the first and last symbols that minimally match
- * will be assigned to *first and *last respectively.
- * If there is no match, then first and last will
- * bracket the location where the symbol should be
- * inserted.
- *
+ * first,last int * If there is an ambiguous or exact match, the indexes
+ * of the first and last symbols that minimally match
+ * will be assigned to *first and *last respectively.
+ * If there is no match, then first and last will
+ * bracket the location where the symbol should be
+ * inserted.
* Output:
- * return KtKeyMatch One of the following enumerators:
- * KT_EXACT_MATCH - An exact match was found.
- * KT_AMBIG_MATCH - An ambiguous match was found.
- * KT_NO_MATCH - No match was found.
- * KT_BAD_MATCH - An error occurred while searching.
- */
-KtKeyMatch _kt_lookup_keybinding(KeyTab *kt, const char *binary_keyseq, int nc,
- int *first, int *last)
+ * return KtKeyMatch One of the following enumerators:
+ * KT_EXACT_MATCH - An exact match was found.
+ * KT_AMBIG_MATCH - An ambiguous match was found.
+ * KT_NO_MATCH - No match was found.
+ * KT_BAD_MATCH - An error occurred while searching.
+ */
+static KtKeyMatch _kt_locate_keybinding(KeyTab *kt, const char *binary_keyseq,
+ int nc, int *first, int *last)
{
int mid; /* The index at which to bisect the table */
int bot; /* The lowest index of the table not searched yet */
int top; /* The highest index of the table not searched yet */
int test; /* The return value of strcmp() */
/*
- * Check the arguments.
- */
- if(!kt || !binary_keyseq || !first || !last || nc < 0) {
- fprintf(stderr, "kt_lookup_keybinding: NULL argument(s).\n");
- return KT_BAD_MATCH;
- };
-/*
* Perform a binary search for the key-sequence.
*/
bot = 0;
@@ -406,6 +454,68 @@ KtKeyMatch _kt_lookup_keybinding(KeyTab *kt, const char *binary_keyseq, int nc,
}
/*.......................................................................
+ * Lookup the sub-array of key-bindings who's key-sequences minimally
+ * match a given key-sequence.
+ *
+ * Input:
+ * kt KeyTab * The keybinding table to lookup in.
+ * binary_keyseq char * The binary key-sequence to lookup.
+ * nc int the number of characters in keyseq[].
+ * Input/Output:
+ * matches KeySym ** The array of minimally matching symbols
+ * can be found in (*matches)[0..nmatch-1], unless
+ * no match was found, in which case *matches will
+ * be set to NULL.
+ * nmatch int The number of ambiguously matching symbols. This
+ * will be 0 if there is no match, 1 for an exact
+ * match, and a number greater than 1 for an ambiguous
+ * match.
+ * Output:
+ * return KtKeyMatch One of the following enumerators:
+ * KT_EXACT_MATCH - An exact match was found.
+ * KT_AMBIG_MATCH - An ambiguous match was found.
+ * KT_NO_MATCH - No match was found.
+ * KT_BAD_MATCH - An error occurred while searching.
+ */
+KtKeyMatch _kt_lookup_keybinding(KeyTab *kt, const char *binary_keyseq,
+ int nc, KeySym **matches, int *nmatch)
+{
+ KtKeyMatch status; /* The return status */
+ int first,last; /* The indexes of the first and last matching entry */
+ /* in the symbol table. */
+/*
+ * Check the arguments.
+ */
+ if(!kt || !binary_keyseq || !matches || !nmatch || nc < 0) {
+ errno = EINVAL;
+ if(kt)
+ _err_record_msg(kt->err, "NULL argument(s)", END_ERR_MSG);
+ return KT_BAD_MATCH;
+ };
+/*
+ * Lookup the indexes of the binding-table entries that bracket the
+ * target key-sequence.
+ */
+ status = _kt_locate_keybinding(kt, binary_keyseq, nc, &first, &last);
+/*
+ * Translate the indexes into the corresponding subarray of matching
+ * table entries.
+ */
+ switch(status) {
+ case KT_EXACT_MATCH:
+ case KT_AMBIG_MATCH:
+ *matches = kt->table + first;
+ *nmatch = last - first + 1;
+ break;
+ default:
+ *matches = NULL;
+ *nmatch = 0;
+ break;
+ };
+ return status;
+}
+
+/*.......................................................................
* Convert a keybinding string into a uniq binary representation.
*
* Control characters can be given directly in their binary form,
@@ -436,6 +546,7 @@ static int _kt_parse_keybinding_string(const char *keyseq, char *binary,
{
const char *iptr = keyseq; /* Pointer into keyseq[] */
char *optr = binary; /* Pointer into binary[] */
+ char c; /* An intermediate character */
/*
* Parse the input characters until they are exhausted or the
* output string becomes full.
@@ -452,8 +563,19 @@ static int _kt_parse_keybinding_string(const char *keyseq, char *binary,
* record a literal caret.
*/
if(iptr[1]) {
- *optr++ = MAKE_CTRL(iptr[1]);
- iptr += 2;
+/*
+ * Get the next, possibly escaped, character.
+ */
+ if(iptr[1] == '\\') {
+ c = _kt_backslash_escape(iptr+2, &iptr);
+ } else {
+ c = iptr[1];
+ iptr += 2;
+ };
+/*
+ * Convert the character to a control character.
+ */
+ *optr++ = MAKE_CTRL(c);
} else {
*optr++ = *iptr++;
};
@@ -530,18 +652,22 @@ static int _kt_parse_keybinding_string(const char *keyseq, char *binary,
* action char * The name of the action.
* fn KtKeyFn * The function that implements the action, or NULL
* to remove an existing action.
+ * data void * A pointer to arbitrary callback data to pass to the
+ * action function whenever it is called.
* Output:
* return int 0 - OK.
* 1 - Error.
*/
-int _kt_set_action(KeyTab *kt, const char *action, KtKeyFn *fn)
+int _kt_set_action(KeyTab *kt, const char *action, KtKeyFn *fn, void *data)
{
Symbol *sym; /* The symbol table entry of the action */
/*
* Check the arguments.
*/
if(!kt || !action) {
- fprintf(stderr, "kt_set_action: NULL argument(s).\n");
+ errno = EINVAL;
+ if(kt)
+ _err_record_msg(kt->err, "NULL argument(s)", END_ERR_MSG);
return 1;
};
/*
@@ -557,13 +683,15 @@ int _kt_set_action(KeyTab *kt, const char *action, KtKeyFn *fn)
sym = _find_HashSymbol(kt->actions, action);
if(sym) {
sym->fn = (void (*)(void))fn;
+ sym->data = data;
return 0;
};
/*
* Add a new action.
*/
- if(!_new_HashSymbol(kt->actions, action, 0, (void (*)(void))fn, NULL, 0)) {
- fprintf(stderr, "Insufficient memory to record new key-binding action.\n");
+ if(!_new_HashSymbol(kt->actions, action, 0, (void (*)(void))fn, data, 0)) {
+ _err_record_msg(kt->err, "Insufficient memory to record key-binding action",
+ END_ERR_MSG);
return 1;
};
return 0;
@@ -616,33 +744,37 @@ static int _kt_compare_strings(const char *s1, int n1, const char *s2, int n2)
* sym KeySym * The binding table entry to be modified.
* binder KtBinder The source of the binding.
* keyfn KtKeyFn * The action function.
+ * data void * A pointer to arbitrary callback data to pass to
+ * the action function whenever it is called.
*/
-static void _kt_assign_action(KeySym *sym, KtBinder binder, KtKeyFn *keyfn)
+static void _kt_assign_action(KeySym *sym, KtBinder binder, KtKeyFn *keyfn,
+ void *data)
{
+ KtAction *action; /* An action function/data pair */
+ int i;
+/*
+ * Unknown binding source?
+ */
+ if(binder < 0 || binder >= KTB_NBIND)
+ return;
/*
* Record the action according to its source.
*/
- switch(binder) {
- case KTB_USER:
- sym->user_fn = keyfn;
- break;
- case KTB_TERM:
- sym->term_fn = keyfn;
- break;
- case KTB_NORM:
- default:
- sym->norm_fn = keyfn;
- break;
- };
+ action = sym->actions + binder;
+ action->fn = keyfn;
+ action->data = data;
+/*
+ * Find the highest priority binding source that has supplied an
+ * action. Note that the actions[] array is ordered in order of
+ * descreasing priority, so the first entry that contains a function
+ * is the one to use.
+ */
+ for(i=0; i<KTB_NBIND && !sym->actions[i].fn; i++)
+ ;
/*
- * Which of the current set of bindings should be used?
+ * Record the index of this action for use during lookups.
*/
- if(sym->user_fn)
- sym->keyfn = sym->user_fn;
- else if(sym->norm_fn)
- sym->keyfn = sym->norm_fn;
- else
- sym->keyfn = sym->term_fn;
+ sym->binder = i < KTB_NBIND ? i : -1;
return;
}
@@ -666,14 +798,14 @@ void _kt_clear_bindings(KeyTab *kt, KtBinder binder)
* Clear bindings of the given source.
*/
for(oldkey=0; oldkey<kt->nkey; oldkey++)
- _kt_assign_action(kt->table + oldkey, binder, 0);
+ _kt_assign_action(kt->table + oldkey, binder, 0, NULL);
/*
* Delete entries that now don't have a binding from any source.
*/
newkey = 0;
for(oldkey=0; oldkey<kt->nkey; oldkey++) {
KeySym *sym = kt->table + oldkey;
- if(!sym->keyfn) {
+ if(sym->binder < 0) {
_del_StringMemString(kt->smem, sym->keyseq);
} else {
if(oldkey != newkey)
@@ -812,7 +944,9 @@ int _kt_add_bindings(KeyTab *kt, KtBinder binder, const KtKeyBinding *bindings,
* Check the arguments.
*/
if(!kt || !bindings) {
- fprintf(stderr, "_kt_add_bindings: NULL argument(s).\n");
+ errno = EINVAL;
+ if(kt)
+ _err_record_msg(kt->err, "NULL argument(s)", END_ERR_MSG);
return 1;
};
/*
@@ -825,3 +959,64 @@ int _kt_add_bindings(KeyTab *kt, KtBinder binder, const KtKeyBinding *bindings,
return 0;
}
+/*.......................................................................
+ * Lookup the function that implements a given action.
+ *
+ * Input:
+ * kt KeyTab * The table of key bindings.
+ * action const char * The name of the action to look up.
+ * Input/Output:
+ * fn KtKeyFn ** If the action is found, the function that
+ * implements it will be assigned to *fn. Note
+ * that fn can be NULL.
+ * data void ** If the action is found, the callback data
+ * associated with the action function, will be
+ * assigned to *data. Note that data can be NULL.
+ * Output:
+ * return int 0 - OK.
+ * 1 - Action not found.
+ */
+int _kt_lookup_action(KeyTab *kt, const char *action,
+ KtKeyFn **fn, void **data)
+{
+ Symbol *sym; /* The symbol table entry of the action */
+/*
+ * Check the arguments.
+ */
+ if(!kt || !action) {
+ errno = EINVAL;
+ if(kt)
+ _err_record_msg(kt->err, "NULL argument(s)", END_ERR_MSG);
+ return 1;
+ };
+/*
+ * Lookup the symbol table entry of the action.
+ */
+ sym = _find_HashSymbol(kt->actions, action);
+ if(!sym)
+ return 1;
+/*
+ * Return the function and ccallback data associated with the action.
+ */
+ if(fn)
+ *fn = (KtKeyFn *) sym->fn;
+ if(data)
+ *data = sym->data;
+ return 0;
+}
+
+/*.......................................................................
+ * Return extra information (ie. in addition to that provided by errno)
+ * about the last error to occur in any of the public functions of this
+ * module.
+ *
+ * Input:
+ * kt KeyTab * The table of key bindings.
+ * Output:
+ * return const char * A pointer to the internal buffer in which
+ * the error message is temporarily stored.
+ */
+const char *_kt_last_error(KeyTab *kt)
+{
+ return kt ? _err_get_msg(kt->err) : "NULL KeyTab argument";
+}
diff --git a/libtecla-1.4.1/keytab.h b/libtecla-1.6.1/keytab.h
index 9436e8f..b275c98 100644
--- a/libtecla-1.4.1/keytab.h
+++ b/libtecla-1.6.1/keytab.h
@@ -2,7 +2,7 @@
#define keytab_h
/*
- * Copyright (c) 2000, 2001 by Martin C. Shepherd.
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
*
* All rights reserved.
*
@@ -33,8 +33,6 @@
*/
#include "libtecla.h"
-#include "hash.h"
-#include "strngmem.h"
/*-----------------------------------------------------------------------*
* This module defines a binary-search symbol table of key-bindings. *
@@ -49,69 +47,77 @@
* or 1. Action functions should ignore this if
* repeating the action multiple times isn't
* appropriate.
+ * data void * A pointer to action-specific data,
+ * cast to (void *).
* Output:
* return int 0 - OK.
* 1 - Error.
*/
-#define KT_KEY_FN(fn) int (fn)(GetLine *gl, int count)
+#define KT_KEY_FN(fn) int (fn)(GetLine *gl, int count, void *data)
typedef KT_KEY_FN(KtKeyFn);
/*
- * Define an entry of a key-binding binary symbol table.
+ * Allow the association of arbitrary callback data with each action
+ * function.
*/
typedef struct {
- char *keyseq; /* The key sequence that triggers the macro */
- int nc; /* The number of characters in keyseq[] */
- KtKeyFn *user_fn; /* A user specified binding (or 0 if none) */
- KtKeyFn *term_fn; /* A terminal-specific binding (or 0 if none) */
- KtKeyFn *norm_fn; /* The default binding (or 0 if none) */
- KtKeyFn *keyfn; /* The function to execute when this key sequence */
- /* is seen. This is the function above which has */
- /* the highest priority. */
-} KeySym;
+ KtKeyFn *fn; /* The acion function */
+ void *data; /* A pointer to arbitrary data to be passed to */
+ /* fn() whenever it is called. */
+} KtAction;
/*
- * When allocating or reallocating the key-binding table, how
- * many entries should be added?
+ * Enumerate the possible sources of key-bindings in order of decreasing
+ * priority.
*/
-#define KT_TABLE_INC 100
+typedef enum {
+ KTB_USER, /* This is a binding being set by the user */
+ KTB_NORM, /* This is the default binding set by the library */
+ KTB_TERM, /* This is a binding taken from the terminal settings */
+/* The following entry must always be last */
+ KTB_NBIND /* The number of binding sources listed above */
+} KtBinder;
/*
- * Define the size of the hash table that is used to associate action
- * names with action functions. This should be a prime number.
+ * Define an entry of a key-binding binary symbol table.
*/
-#define KT_HASH_SIZE 113
+typedef struct {
+ char *keyseq; /* The key sequence that triggers the macro */
+ int nc; /* The number of characters in keyseq[] */
+ KtAction actions[KTB_NBIND]; /* Bindings from different sources */
+ int binder; /* The index of the highest priority element */
+ /* of actions[] that has been assigned an */
+ /* action function, or -1 if none have. */
+} KeySym;
/*
- * Define a binary-symbol-table object.
+ * Provide an opaque type alias to the symbol table container.
*/
-typedef struct {
- int size; /* The allocated dimension of table[] */
- int nkey; /* The current number of members in the table */
- KeySym *table; /* The table of lexically sorted key sequences */
- HashTable *actions; /* The hash table of actions */
- StringMem *smem; /* Memory for allocating strings */
-} KeyTab;
+typedef struct KeyTab KeyTab;
+/*
+ * Create a new symbol table.
+ */
KeyTab *_new_KeyTab(void);
-KeyTab *_del_KeyTab(KeyTab *kt);
/*
- * Enumerate the possible sources of key-bindings.
+ * Delete the symbol table.
*/
-typedef enum {
- KTB_USER, /* This is a binding being set by the user */
- KTB_TERM, /* This is a binding taken from the terminal settings */
- KTB_NORM /* This is the default binding set by the library */
-} KtBinder;
+KeyTab *_del_KeyTab(KeyTab *kt);
int _kt_set_keybinding(KeyTab *kt, KtBinder binder,
const char *keyseq, const char *action);
int _kt_set_keyfn(KeyTab *kt, KtBinder binder, const char *keyseq,
- KtKeyFn *keyfn);
+ KtKeyFn *fn, void *data);
-int _kt_set_action(KeyTab *kt, const char *action, KtKeyFn *fn);
+int _kt_set_action(KeyTab *kt, const char *action, KtKeyFn *fn, void *data);
+
+/*
+ * Lookup the function that implements a given action.
+ */
+int _kt_lookup_action(KeyTab *kt, const char *action,
+ KtKeyFn **fn, void **data);
typedef enum {
KT_EXACT_MATCH, /* An exact match was found */
@@ -121,7 +127,7 @@ typedef enum {
} KtKeyMatch;
KtKeyMatch _kt_lookup_keybinding(KeyTab *kt, const char *binary_keyseq,
- int nc, int *first,int *last);
+ int nc, KeySym **matches, int *nmatch);
/*
* Remove all key bindings that came from a specified source.
@@ -143,4 +149,9 @@ typedef struct {
int _kt_add_bindings(KeyTab *kt, KtBinder binder, const KtKeyBinding *bindings,
unsigned n);
+/*
+ * Get information about the last error in this module.
+ */
+const char *_kt_last_error(KeyTab *kt);
+
#endif
diff --git a/libtecla-1.4.1/libtecla.h b/libtecla-1.6.1/libtecla.h
index f124dd0..fbbf220 100644
--- a/libtecla-1.4.1/libtecla.h
+++ b/libtecla-1.6.1/libtecla.h
@@ -2,7 +2,7 @@
#define libtecla_h
/*
- * Copyright (c) 2000, 2001 by Martin C. Shepherd.
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
*
* All rights reserved.
*
@@ -39,6 +39,7 @@ extern "C" {
#include <stdio.h> /* FILE * */
#include <stdlib.h> /* size_t */
#include <time.h> /* time_t */
+#include <signal.h> /* struct sigaction */
/*
* The following are the three components of the libtecla version number.
@@ -49,7 +50,7 @@ extern "C" {
* actually linked to.
*/
#define TECLA_MAJOR_VER 1
-#define TECLA_MINOR_VER 4
+#define TECLA_MINOR_VER 6
#define TECLA_MICRO_VER 1
/*.......................................................................
@@ -98,6 +99,37 @@ GetLine *del_GetLine(GetLine *gl);
char *gl_get_line(GetLine *gl, const char *prompt, const char *start_line,
int start_pos);
+/*.......................................................................
+ * Prompt the user for a single-character reply.
+ *
+ * Input:
+ * gl GetLine * A resource object returned by new_GetLine().
+ * prompt char * The prompt to prefix the query with, or NULL
+ * to reuse the previous prompt.
+ * defchar char The character to substitute if the
+ * user simply hits return, or '\n' if you don't
+ * need to substitute anything.
+ * Output:
+ * return int The character that was read, or EOF if the read
+ * had to be aborted (in which case you can call
+ * gl_return_status() to find out why).
+ */
+int gl_query_char(GetLine *gl, const char *prompt, char defchar);
+
+/*.......................................................................
+ * Read a single uninterpretted character from the user, without
+ * displaying anything.
+ *
+ * Input:
+ * gl GetLine * A resource object previously returned by
+ * new_GetLine().
+ * Output:
+ * return int The character that was read, or EOF if the read
+ * had to be aborted (in which case you can call
+ * gl_return_status() to find out why).
+ */
+int gl_read_char(GetLine *gl);
+
/*
* Configure the application specific and/or user-specific behavior of
* gl_get_line().
@@ -105,6 +137,23 @@ char *gl_get_line(GetLine *gl, const char *prompt, const char *start_line,
int gl_configure_getline(GetLine *gl, const char *app_string,
const char *app_file, const char *user_file);
+/*
+ * The following enumerators specify the origin of a key binding, and
+ * are listed in order of decreasing priority, such that user-specified
+ * key-bindings take precedence over application default bindings.
+ */
+typedef enum {
+ GL_USER_KEY, /* A key-binding specified by the user */
+ GL_APP_KEY /* A key-binding specified by the application */
+} GlKeyOrigin;
+
+/*
+ * Bind a key sequence to a given action. If action==NULL, unbind the
+ * key-sequence.
+ */
+int gl_bind_keyseq(GetLine *gl, GlKeyOrigin origin, const char *keyseq,
+ const char *action);
+
/*-----------------------------------------------------------------------
* The file-expansion module provides facilities for expanding ~user/ and
* $envvar expressions, and for expanding glob-style wildcards.
@@ -413,6 +462,40 @@ void cpl_record_error(WordCompletion *cpl, const char *errmsg);
int gl_customize_completion(GetLine *gl, void *data, CplMatchFn *match_fn);
/*.......................................................................
+ * This function allows you to install alternate completion action
+ * functions or completion listing functions, or to change the
+ * completion function of an existing action of the same type. This
+ * should preferably be called before the first call to gl_get_line()
+ * so that the name of the action becomes defined before the user's
+ * configuration file is read.
+ *
+ * Input:
+ * gl GetLine * The resource object of the command-line input
+ * module.
+ * data void * This is passed to match_fn() whenever it is
+ * called. It could, for example, point to a
+ * symbol table that match_fn() would look up
+ * matches in.
+ * match_fn CplMatchFn * The function that will identify the prefix
+ * to be completed from the input line, and
+ * report matching symbols.
+ * list_only int If non-zero, install an action that only lists
+ * possible completions, rather than attempting
+ * to perform the completion.
+ * name const char * The name with which users can refer to the
+ * binding in tecla configuration files.
+ * keyseq const char * The key sequence with which to invoke
+ * the binding. This should be specified in the
+ * same manner as key-sequences in tecla
+ * configuration files (eg. "M-^I").
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+int gl_completion_action(GetLine *gl, void *data, CplMatchFn *match_fn,
+ int list_only, const char *name, const char *keyseq);
+
+/*.......................................................................
* Change the terminal (or stream) that getline interacts with.
*
* Input:
@@ -476,17 +559,17 @@ typedef enum {
} GlFdStatus;
/*.......................................................................
- * While gl_get_line() is waiting for terminal input, it can also be
- * asked to listen for activity on arbitrary file descriptors.
- * Callback functions of the following type can be registered to be
- * called when activity is seen. If your callback needs to write to
- * the terminal or use signals, please see the gl_get_line(3) man
- * page.
+ * On systems that have the select() system call, while gl_get_line()
+ * is waiting for terminal input, it can also be asked to listen for
+ * activity on arbitrary file descriptors. Callback functions of the
+ * following type can be registered to be called when activity is
+ * seen. If your callback needs to write to the terminal or use
+ * signals, please see the gl_get_line(3) man page.
*
* Input:
* gl GetLine * The gl_get_line() resource object. You can use
* this safely to call gl_watch_fd() or
- * gl_watch_time(). The effect of calling other
+ * gl_inactivity_timeout(). The effect of calling other
* functions that take a gl argument is undefined,
* and must be avoided.
* data void * A pointer to arbitrary callback data, as originally
@@ -533,6 +616,89 @@ typedef GL_FD_EVENT_FN(GlFdEventFn);
int gl_watch_fd(GetLine *gl, int fd, GlFdEvent event,
GlFdEventFn *callback, void *data);
+/*
+ * Enumerators from the following list are returned by activity
+ * timeout callbacks registered by gl_inactivity_timeout(). They tell
+ * gl_get_line() whether and how to procede.
+ */
+typedef enum {
+ GLTO_ABORT, /* Cause gl_get_line() to abort with an error */
+ GLTO_REFRESH, /* Redraw the input line and continue waiting for input */
+ GLTO_CONTINUE /* Continue to wait for input, without redrawing the line */
+} GlAfterTimeout;
+
+/*.......................................................................
+ * On systems that have the select() system call, the application has
+ * the option of providing a callback function of the following type,
+ * which is called whenever no terminal input or other I/O activity is
+ * seen for the timeout duration specified in the last call to
+ * gl_inactivity_timeout().
+ *
+ * Input:
+ * gl GetLine * The gl_get_line() resource object. You can use
+ * this safely to call gl_watch_fd() or
+ * gl_inactivity_timeout(). The effect of calling other
+ * functions that take a gl argument is undefined,
+ * and must be avoided.
+ * data void * A pointer to arbitrary callback data, as
+ * originally registered with gl_inactivity_timeout().
+ * Output:
+ * return GlAfterTimeout GLTO_ABORT - Cause gl_get_line() to
+ * abort with an error (set
+ * errno if you need it).
+ * GLTO_REFRESH - Redraw the input line and
+ * continue waiting for
+ * input. Use this if you
+ * wrote something to the
+ * terminal.
+ * GLTO_CONTINUE - Continue to wait for
+ * input, without redrawing
+ * the line.
+ */
+#define GL_TIMEOUT_FN(fn) GlAfterTimeout (fn)(GetLine *gl, void *data)
+typedef GL_TIMEOUT_FN(GlTimeoutFn);
+
+/*.......................................................................
+ * On systems with the select() system call, the gl_inactivity_timeout()
+ * function provides the option of setting (or cancelling) an
+ * inactivity timeout. Inactivity, in this case, refers both to
+ * terminal input received from the user, and to I/O on any file
+ * descriptors registered by calls to gl_watch_fd(). If at any time,
+ * no activity is seen for the requested time period, the specified
+ * timeout callback function is called. On returning, this callback
+ * returns a code which tells gl_get_line() what to do next. Note that
+ * each call to gl_inactivity_timeout() replaces any previously installed
+ * timeout callback, and that specifying a callback of 0, turns off
+ * inactivity timing.
+ *
+ * Beware that although the timeout argument includes a nano-second
+ * component, few computer clocks presently have resolutions finer
+ * than a few milliseconds, so asking for less than a few milliseconds
+ * is equivalent to zero on a lot of systems.
+ *
+ * Input:
+ * gl GetLine * The resource object of the command-line input
+ * module.
+ * callback GlTimeoutFn * The function to call when the inactivity
+ * timeout is exceeded. To turn off
+ * inactivity timeouts altogether, send 0.
+ * data void * A pointer to arbitrary data to pass to the
+ * callback function.
+ * sec unsigned long The number of whole seconds in the timeout.
+ * nsec unsigned long The fractional number of seconds in the
+ * timeout, expressed in nano-seconds (see
+ * the caveat above).
+ * Output:
+ * return int 0 - OK.
+ * 1 - Either gl==NULL, or this facility isn't
+ * available on the the host system
+ * (ie. select() isn't available). No
+ * error message is generated in the latter
+ * case.
+ */
+int gl_inactivity_timeout(GetLine *gl, GlTimeoutFn *timeout_fn, void *data,
+ unsigned long sec, unsigned long nsec);
+
/*.......................................................................
* Switch history streams. History streams represent separate history
* lists recorded within a single history buffer. Different streams
@@ -654,6 +820,21 @@ typedef struct {
*/
GlTerminalSize gl_terminal_size(GetLine *gl, int def_ncolumn, int def_nline);
+/*.......................................................................
+ * Tell gl_get_line() the current terminal size. Note that this is only
+ * necessary on systems where changes in terminal size aren't reported
+ * via SIGWINCH.
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ * ncolumn int The number of columns in the terminal.
+ * nline int The number of rows in the terminal.
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+int gl_set_term_size(GetLine *gl, int ncolumn, int nline);
+
/*
* The gl_lookup_history() function returns information in an
* argument of the following type.
@@ -764,6 +945,37 @@ typedef struct {
void gl_size_of_history(GetLine *gl, GlHistorySize *size);
/*.......................................................................
+ * Enable or disable the automatic addition of newly entered lines to the
+ * history list.
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ * enable int If true, subsequently entered lines will
+ * automatically be added to the history list
+ * before they are returned to the caller of
+ * gl_get_line(). If 0, the choice of how and
+ * when to archive lines in the history list,
+ * is left up to the calling application, which
+ * can do so via calls to gl_append_history().
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+int gl_automatic_history(GetLine *gl, int enable);
+
+/*.......................................................................
+ * Append a specified line to the history list.
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ * line const char * The line to be added.
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+int gl_append_history(GetLine *gl, const char *line);
+
+/*.......................................................................
* Specify whether text that users type should be displayed or hidden.
* In the latter case, only the prompt is displayed, and the final
* input line is not archived in the history list.
@@ -891,6 +1103,63 @@ int gl_trap_signal(GetLine *gl, int signo, unsigned flags,
GlAfterSignal after, int errno_value);
/*.......................................................................
+ * By default, gl_get_line() doesn't trap signals that are blocked
+ * when it is called. This default can be changed either on a
+ * per-signal basis by calling gl_trap_signal(), or on a global basis
+ * by calling this function. What this function does is add the
+ * GLS_UNBLOCK_SIG flag to all signals that are currently configured
+ * to be trapped by gl_get_line(), such that when subsequent calls to
+ * gl_get_line() wait for I/O, these signals are temporarily
+ * unblocked. This behavior is useful in non-blocking server-I/O mode,
+ * where it is used to avoid race conditions related to handling these
+ * signals externally to gl_get_line(). See the demonstration code in
+ * demo3.c, or the gl_handle_signal() man page for further
+ * information.
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ */
+void gl_catch_blocked(GetLine *gl);
+
+/*.......................................................................
+ * In server-I/O mode the terminal is left in raw mode between calls
+ * to gl_get_line(), so it is necessary for the application to install
+ * terminal restoring signal handlers for signals that could terminate
+ * or suspend the process, plus a terminal reconfiguration handler to
+ * be called when a process resumption signal is received, and finally
+ * a handler to be called when a terminal-resize signal is received.
+ *
+ * Since there are many signals that by default terminate or suspend
+ * processes, and different systems support different sub-sets of
+ * these signals, this function provides a convenient wrapper around
+ * sigaction() for assigning the specified handlers to all appropriate
+ * signals. It also arranges that when any one of these signals is
+ * being handled, all other catchable signals are blocked. This is
+ * necessary so that the specified signal handlers can safely call
+ * gl_raw_io(), gl_normal_io() and gl_update_size() without reentrancy
+ * issues.
+ *
+ * Input:
+ * term_handler void (*)(int) The signal handler to invoke when
+ * a process terminating signal is
+ * received.
+ * susp_handler void (*)(int) The signal handler to invoke when
+ * a process suspending signal is
+ * received.
+ * cont_handler void (*)(int) The signal handler to invoke when
+ * a process resumption signal is
+ * received (ie. SIGCONT).
+ * size_handler void (*)(int) The signal handler to invoke when
+ * a terminal-resize signal (ie. SIGWINCH)
+ * is received.
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+int gl_tty_signals(void (*term_handler)(int), void (*susp_handler)(int),
+ void (*cont_handler)(int), void (*size_handler)(int));
+
+/*.......................................................................
* Return the last signal that was caught by the most recent call to
* gl_get_line(), or -1 if no signals were caught. This is useful if
* gl_get_line() returns errno=EINTR and you need to find out what signal
@@ -903,7 +1172,358 @@ int gl_trap_signal(GetLine *gl, int signo, unsigned flags,
* call to gl_get_line(), or -1 if no signals
* were caught.
*/
-int gl_last_signal(const GetLine *gl);
+int gl_last_signal(GetLine *gl);
+
+/*.......................................................................
+ * Return the signal mask used by gl_get_line(). This is the set of
+ * signals that gl_get_line() is currently configured to trap.
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ * Input/Output:
+ * set sigset_t * The set of signals will be returned in *set,
+ * in the form of a signal process mask, as
+ * used by sigaction(), sigprocmask(),
+ * sigpending(), sigsuspend(), sigsetjmp() and
+ * other standard POSIX signal-aware
+ * functions.
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error (examine errno for reason).
+ */
+int gl_list_signals(GetLine *gl, sigset_t *set);
+
+/*.......................................................................
+ * Respond to signals who's default effects have important
+ * consequences to gl_get_line(). This is intended for use in
+ * non-blocking server mode, where the external event loop is
+ * responsible for catching signals. Signals that are handled include
+ * those that by default terminate or suspend the process, and the
+ * signal that indicates that the terminal size has changed. Note that
+ * this function is not signal safe and should thus not be called from
+ * a signal handler itself. See the gl_io_mode() man page for how it
+ * should be used.
+ *
+ * In the case of signals that by default terminate or suspend
+ * processes, command-line editing will be suspended, the terminal
+ * returned to a usable state, then the default disposition of the
+ * signal restored and the signal resent, in order to suspend or
+ * terminate the process. If the process subsequently resumes,
+ * command-line editing is resumed.
+ *
+ * In the case of signals that indicate that the terminal has been
+ * resized, the new size will be queried, and any input line that is
+ * being edited will be redrawn to fit the new dimensions of the
+ * terminal.
+ *
+ * Input:
+ * signo int The number of the signal to respond to.
+ * gl GetLine * The first element of an array of 'ngl' GetLine
+ * objects.
+ * ngl int The number of elements in the gl[] array. Normally
+ * this will be one.
+ */
+void gl_handle_signal(int signo, GetLine *gl, int ngl);
+
+/*.......................................................................
+ * Return extra information (ie. in addition to that provided by errno)
+ * about the last error to occur in either gl_get_line() or its
+ * associated public functions.
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ * Input/Output:
+ * buff char * An optional output buffer. Note that if the
+ * calling application calls any gl_*()
+ * functions from signal handlers, it should
+ * provide a buffer here, so that a copy of
+ * the latest error message can safely be made
+ * while signals are blocked.
+ * n size_t The allocated size of buff[].
+ * Output:
+ * return const char * A pointer to the error message. This will
+ * be the buff argument, unless buff==NULL, in
+ * which case it will be a pointer to an
+ * internal error buffer. In the latter case,
+ * note that the contents of the returned buffer
+ * will change on subsequent calls to any gl_*()
+ * functions.
+ */
+const char *gl_error_message(GetLine *gl, char *buff, size_t n);
+
+/*.......................................................................
+ * Clear the terminal and leave the cursor at the home position. In
+ * server I/O mode, arrange for the input line to be redrawn from scratch
+ * when gl_get_line() is next called.
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+int gl_erase_terminal(GetLine *gl);
+
+/*.......................................................................
+ * Display a left-justified string over multiple terminal lines,
+ * taking account of the current width of the terminal. Optional
+ * indentation and an optional prefix string can be specified to be
+ * displayed at the start of each new terminal line used. Similarly,
+ * an optional suffix can be specified to be displayed at the end of
+ * each terminal line. If needed, a single paragraph can be broken
+ * across multiple calls. Note that literal newlines in the input
+ * string can be used to force a newline at any point and that you
+ * should use this feature to explicitly end all paragraphs, including
+ * at the end of the last string that you write. Note that when a new
+ * line is started between two words that are separated by spaces,
+ * those spaces are not output, whereas when a new line is started
+ * because a newline character was found in the string, only the
+ * spaces before the newline character are discarded.
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ * indentation int The number of spaces of indentation to write
+ * at the beginning of each new terminal line.
+ * prefix const char * An optional prefix string to write after the
+ * indentation margin at the start of each new
+ * terminal line. You can specify NULL if no
+ * prefix is required.
+ * suffix const char * An optional suffix string to draw at the end
+ * of the terminal line. Spaces will be added
+ * where necessary to ensure that the suffix ends
+ * in the last column of the terminal line. If
+ * no suffix is desired, specify NULL.
+ * fill_char int The padding character to use when indenting
+ * the line or padding up to the suffix.
+ * def_width int If the terminal width isn't known, such as when
+ * writing to a pipe or redirecting to a file,
+ * this number specifies what width to assume.
+ * start int The number of characters already written to
+ * the start of the current terminal line. This
+ * is primarily used to allow individual
+ * paragraphs to be written over multiple calls
+ * to this function, but can also be used to
+ * allow you to start the first line of a
+ * paragraph with a different prefix or
+ * indentation than those specified above.
+ * string const char * The string to be written.
+ * Output:
+ * return int On error -1 is returned. Otherwise the
+ * return value is the terminal column index at
+ * which the cursor was left after writing the
+ * final word in the string. Successful return
+ * values can thus be passed verbatim to the
+ * 'start' arguments of subsequent calls to
+ * gl_display_text() to allow the printing of a
+ * paragraph to be broken across multiple calls
+ * to gl_display_text().
+ */
+int gl_display_text(GetLine *gl, int indentation, const char *prefix,
+ const char *suffix, int fill_char, int def_width,
+ int start, const char *string);
+
+
+/*
+ * Enumerate the I/O modes supported by gl_get_line().
+ */
+typedef enum {
+ GL_NORMAL_MODE, /* Normal line-at-a-time mode using gl_get_line()'s */
+ /* internal event loop. */
+ GL_SERVER_MODE /* Non-blocking server mode, driven by an external */
+ /* event loop. */
+} GlIOMode;
+
+/*.......................................................................
+ * Select the I/O mode to be used by gl_get_line().
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ * mode GlIOMode The I/O mode to establish. Note that
+ * when server mode, the terminal is placed
+ * in raw mode, as though gl_raw_io() had
+ * been called.
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+int gl_io_mode(GetLine *gl, GlIOMode mode);
+
+/*.......................................................................
+ * In server mode, this function configures the terminal for non-blocking
+ * raw terminal I/O. In normal I/O mode it does nothing.
+ *
+ * Callers of this function must be careful to trap all signals that
+ * terminate or suspend the program, and call gl_normal_io()
+ * from the corresponding signal handlers in order to restore the
+ * terminal to its original settings before the program is terminated
+ * or suspended. They should also trap the SIGCONT signal to detect
+ * when the program resumes, and ensure that its signal handler
+ * call gl_raw_io() to redisplay the line and resume editing.
+ *
+ * Input:
+ * gl GetLine * The line editor resource object.
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+int gl_raw_io(GetLine *gl);
+
+/*.......................................................................
+ * Restore the terminal to the state that it had when gl_raw_io() was
+ * last called. After calling gl_raw_io(), this function must be called
+ * before terminating or suspending the program, and before attempting
+ * other uses of the terminal from within the program. See gl_raw_io()
+ * for more details.
+ *
+ * Input:
+ * gl GetLine * The line editor resource object.
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+int gl_normal_io(GetLine *gl);
+
+/*.......................................................................
+ * When in non-blocking server mode, this function can be used to abandon
+ * the current incompletely entered input line, and prepare to start
+ * editing a new line on the next call to gl_get_line().
+ *
+ * Input:
+ * gl GetLine * The line editor resource object.
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+void gl_abandon_line(GetLine *gl);
+
+/*
+ * Enumerators of the following type are used to report why
+ * gl_get_line() returned. This is most useful in non-blocking
+ * server mode, since in that mode a NULL return value can mean
+ * either that an error occurred, or that I/O blocked.
+ */
+typedef enum {
+ GLR_NEWLINE, /* A new input line was returned */
+ GLR_BLOCKED, /* The terminal was in non-blocking mode, and input */
+ /* or output would have blocked. */
+ GLR_SIGNAL, /* A signal caused gl_get_line() to return. */
+ GLR_TIMEOUT, /* An application timeout callback returned GLTO_ABORT */
+ GLR_FDABORT, /* An application I/O callack returned GLFD_ABORT */
+ GLR_EOF, /* End of file reached */
+ GLR_ERROR /* An unexpected error caused gl_get_line() to abort */
+} GlReturnStatus;
+
+/*.......................................................................
+ * Ask gl_get_line() what caused it to return.
+ *
+ * Input:
+ * gl GetLine * The line editor resource object.
+ * Output:
+ * return GlReturnStatus The return status of the last call to
+ * gl_get_line().
+ */
+GlReturnStatus gl_return_status(GetLine *gl);
+
+/*
+ * Enumerate the types of I/O that gl_get_line() can be waiting for
+ * in non-blocking sedrver I/O mode.
+ */
+typedef enum {
+ GLP_READ, /* gl_get_line() is waiting to write to the terminal */
+ GLP_WRITE /* gl_get_line() is waiting to read from the terminal */
+} GlPendingIO;
+
+/*.......................................................................
+ * In non-blocking server-I/O mode, this function should be called
+ * from the application's external event loop to see what type of
+ * terminal I/O is being waited for by gl_get_line(), and thus what
+ * direction of I/O to wait for with select() or poll().
+ *
+ * Input:
+ * gl GetLine * The resource object of gl_get_line().
+ * Output:
+ * return GlPendingIO The type of pending I/O being waited for.
+ */
+GlPendingIO gl_pending_io(GetLine *gl);
+
+/*
+ * The following enumerators are returned by externally defined action
+ * functions to tell gl_get_line() how to procede after the action
+ * function returns.
+ */
+typedef enum {
+ GLA_ABORT, /* Cause gl_get_line() to return NULL */
+ GLA_RETURN, /* Return the line as though the user had pressed the */
+ /* return key. */
+ GLA_CONTINUE /* Resume command-line editing */
+} GlAfterAction;
+
+/*.......................................................................
+ * Functions of the following form implement external
+ * application-specific action functions, which can then be bound to
+ * sequences of terminal keys.
+ *
+ * Input:
+ * gl GetLine * The line editor resource object.
+ * data void * The anonymous 'data' argument that was
+ * passed to gl_external_action() when the
+ * callback function was registered.
+ * count int A positive repeat count specified by the user,
+ * or 1 if not specified. Action functions should
+ * ignore this if repeating the action multiple
+ * times isn't appropriate. Alternatively they
+ * can interpret it as a general numeric
+ * argument.
+ * curpos size_t The position of the cursor within the input
+ * line, expressed as the index of the
+ * corresponding character within the line[]
+ * array.
+ * line const char * A read-only copy of the current input line.
+ * Output
+ * return GlAfterAction What should gl_get_line() do when the action
+ * function returns?
+ * GLA_ABORT - Cause gl_get_line() to
+ * abort with an error (set
+ * errno if you need it).
+ * GLA_RETURN - Return the input line as
+ * though the user had typed
+ * the return key.
+ * GLA_CONTINUE - Resume waiting for keyboard
+ * input.
+ */
+#define GL_ACTION_FN(fn) GlAfterAction (fn)(GetLine *gl, void *data, \
+ int count, size_t curpos, const char *line)
+
+typedef GL_ACTION_FN(GlActionFn);
+
+/*.......................................................................
+ * Register an application-provided function as an action function.
+ * This should preferably be called before the first call to gl_get_line()
+ * so that the name of the action becomes defined before the user's
+ * configuration file is read.
+ *
+ * Input:
+ * gl GetLine * The resource object of the command-line input
+ * module.
+ * data void * Arbitrary application-specific callback
+ * data to be passed to the callback
+ * function, fn().
+ * fn GlActionFn * The application-specific function that
+ * implements the action. This will be invoked
+ * whenever the user presses any
+ * key-sequence which is bound to this action.
+ * name const char * The name with which users can refer to the
+ * binding in tecla configuration files.
+ * keyseq const char * The key sequence with which to invoke
+ * the binding. This should be specified in the
+ * same manner as key-sequences in tecla
+ * configuration files (eg. "M-^I").
+ * Output:
+ * return int 0 - OK.
+ * 1 - Error.
+ */
+int gl_register_action(GetLine *gl, void *data, GlActionFn *fn,
+ const char *name, const char *keyseq);
/*.......................................................................
* This function is designed to be called by CPL_MATCH_FN() callback
@@ -993,13 +1613,33 @@ typedef struct {
* completions. The returned pointer refers
* to a container owned by the parent Completion
* object, and its contents thus potentially
- * change on every call to cpl_matches().
+ * change on every call to cpl_complete_word().
*/
CplMatches *cpl_complete_word(WordCompletion *cpl, const char *line,
int word_end, void *data,
CplMatchFn *match_fn);
/*.......................................................................
+ * Recall the return value of the last call to cpl_complete_word().
+ *
+ * Input:
+ * cpl WordCompletion * The completion resource object.
+ * Output:
+ * return CplMatches * The container of the array of possible
+ * completions, as returned by the last call to
+ * cpl_complete_word(). The returned pointer refers
+ * to a container owned by the parent WordCompletion
+ * object, and its contents thus potentially
+ * change on every call to cpl_complete_word().
+ * On error, either in the execution of this
+ * function, or in the last call to
+ * cpl_complete_word(), NULL is returned, and a
+ * description of the error can be acquired by
+ * calling cpl_last_error(cpl).
+ */
+CplMatches *cpl_recall_matches(WordCompletion *cpl);
+
+/*.......................................................................
* Print out an array of matching completions.
*
* Input:
diff --git a/libtecla-1.4.1/libtecla.map b/libtecla-1.6.1/libtecla.map
index 7e774b7..a63378e 100644
--- a/libtecla-1.4.1/libtecla.map
+++ b/libtecla-1.6.1/libtecla.map
@@ -122,3 +122,34 @@ tecla_1.4 {
gl_trap_signal;
gl_last_signal;
} tecla_1.3;
+
+tecla_l.5 {
+ global:
+ gl_inactivity_timeout;
+ gl_completion_action;
+ gl_register_action;
+ gl_display_text;
+ gl_error_message;
+ gl_return_status;
+ gl_set_term_size;
+ gl_list_signals;
+ gl_catch_blocked;
+ gl_io_mode;
+ gl_raw_io;
+ gl_normal_io;
+ gl_tty_signals;
+ gl_abandon_line;
+ gl_handle_signal;
+ gl_pending_io;
+ gl_bind_keyseq;
+ cpl_recall_matches;
+ gl_erase_terminal;
+} tecla_1.4;
+
+tecla_1.6 {
+ global:
+ gl_append_history;
+ gl_automatic_history;
+ gl_query_char;
+ gl_read_char;
+} tecla_l.5;
diff --git a/libtecla-1.6.1/man/file/teclarc.in b/libtecla-1.6.1/man/file/teclarc.in
new file mode 100644
index 0000000..b5ee705
--- /dev/null
+++ b/libtecla-1.6.1/man/file/teclarc.in
@@ -0,0 +1 @@
+.so @MISC_MANDIR@/tecla.@MISC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/cfc_file_start.in b/libtecla-1.6.1/man/func/cfc_file_start.in
new file mode 100644
index 0000000..734f281
--- /dev/null
+++ b/libtecla-1.6.1/man/func/cfc_file_start.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/cpl_complete_word.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/cfc_literal_escapes.in b/libtecla-1.6.1/man/func/cfc_literal_escapes.in
new file mode 100644
index 0000000..734f281
--- /dev/null
+++ b/libtecla-1.6.1/man/func/cfc_literal_escapes.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/cpl_complete_word.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/cfc_set_check_fn.in b/libtecla-1.6.1/man/func/cfc_set_check_fn.in
new file mode 100644
index 0000000..734f281
--- /dev/null
+++ b/libtecla-1.6.1/man/func/cfc_set_check_fn.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/cpl_complete_word.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/cpl_add_completion.in b/libtecla-1.6.1/man/func/cpl_add_completion.in
new file mode 100644
index 0000000..734f281
--- /dev/null
+++ b/libtecla-1.6.1/man/func/cpl_add_completion.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/cpl_complete_word.@FUNC_MANEXT@
diff --git a/libtecla-1.4.1/man3/cpl_complete_word.3 b/libtecla-1.6.1/man/func/cpl_complete_word.in
index ae76439..d5331e9 100644
--- a/libtecla-1.4.1/man3/cpl_complete_word.3
+++ b/libtecla-1.6.1/man/func/cpl_complete_word.in
@@ -1,4 +1,4 @@
-.\" Copyright (C) 2000, 2001 by Martin C. Shepherd
+.\" Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd
.\"
.\" All rights reserved.
.\"
@@ -26,9 +26,9 @@
.\" shall not be used in advertising or otherwise to promote the sale, use
.\" or other dealings in this Software without prior written authorization
.\" of the copyright holder.
-.TH cpl_complete_word 3
+.TH cpl_complete_word @FUNC_MANEXT@
.SH NAME
-cpl_complete_word, cfc_file_start, cfc_literal_escapes, cfc_set_check_fn, cpl_add_completion, cpl_file_completions, cpl_last_error, cpl_list_completions, cpl_record_error, del_CplFileConf, del_WordCompletion, new_CplFileConf, new_WordCompletion \- lookup possible completions for a word
+cpl_complete_word, cfc_file_start, cfc_literal_escapes, cfc_set_check_fn, cpl_add_completion, cpl_file_completions, cpl_last_error, cpl_list_completions, cpl_recall_matches, cpl_record_error, del_CplFileConf, del_WordCompletion, new_CplFileConf, new_WordCompletion \- lookup possible completions for a word
.SH SYNOPSIS
.nf
#include <stdio.h>
@@ -38,6 +38,7 @@ WordCompletion *new_WordCompletion(void);
WordCompletion *del_WordCompletion(WordCompletion *cpl);
+
#define CPL_MATCH_FN(fn) int (fn)(WordCompletion *cpl, \\
void *data, \\
const char *line, \\
@@ -46,11 +47,14 @@ typedef CPL_MATCH_FN(CplMatchFn);
CPL_MATCH_FN(cpl_file_completions);
+
CplMatches *cpl_complete_word(WordCompletion *cpl,
const char *line,
int word_end, void *data,
CplMatchFn *match_fn);
+CplMatches *cpl_recall_matches(WordCompletion *cpl);
+
int cpl_list_completions(CplMatches *result, FILE *fp,
int term_width);
@@ -65,13 +69,32 @@ void cpl_record_error(WordCompletion *cpl,
const char *cpl_last_error(WordCompletion *cpl);
+
+#define CPL_CHECK_FN(fn) int (fn)(void *data, \\
+ const char *pathname)
+
+typedef CPL_CHECK_FN(CplCheckFn);
+
+CPL_CHECK_FN(cpl_check_exe);
+
+CplFileConf *new_CplFileConf(void);
+
+CplFileConf *del_CplFileConf(CplFileConf *cfc);
+
+void cfc_literal_escapes(CplFileConf *cfc, int literal);
+
+void cfc_file_start(CplFileConf *cfc, int start_index);
+
+void cfc_set_check_fn(CplFileConf *cfc, CplCheckFn *chk_fn,
+ void *chk_data);
+
.fi
.SH DESCRIPTION
The \f3cpl_complete_word()\f1 function is part of the tecla library
-(see the libtecla(3) man page). It is usually called behind the scenes
-by \f3gl_get_line(3)\f1, but can also be called separately.
+(see the libtecla(@LIBR_MANEXT@) man page). It is usually called behind the scenes
+by \f3gl_get_line(@FUNC_MANEXT@)\f1, but can also be called separately.
Given an input line containing an incomplete word to be completed, it
calls a user-provided callback function (or the provided
@@ -86,7 +109,7 @@ calling \f3cpl_add_completion()\f1.
Descriptions of the functions of this module are as follows:
.sp
.nf
- CompleteWord *new_CompleteWord(void)
+ WordCompletion *new_WordCompletion(void)
.fi
.sp
This function creates the resources used by the \f3cpl_complete_word()\f1
@@ -94,11 +117,11 @@ function. In particular, it maintains the memory that is used to
return the results of calling \f3cpl_complete_word()\f1.
.sp
.nf
- CompleteWord *del_CompleteWord(CompleteWord *cpl)
+ WordCompletion *del_WordCompletion(WordCompletion *cpl)
.fi
.sp
This function deletes the resources that were returned by a previous
-call to \f3new_CompleteWord()\f1. It always returns \f3NULL\f1 (ie. a
+call to \f3new_WordCompletion()\f1. It always returns \f3NULL\f1 (ie. a
deleted object). It does nothing if the \f3cpl\f1 argument is
\f3NULL\f1.
.sp
@@ -204,11 +227,11 @@ by arranging for an open parenthesis to be appended.
.fi
.sp
The \f3cpl_complete_word()\f1 is normally called behind the scenes by
-\f3gl_get_line(3)\f1, but can also be called separately if you
+\f3gl_get_line(@FUNC_MANEXT@)\f1, but can also be called separately if you
separately allocate a \f3WordCompletion\f1 object. It performs word
completion, as described at the beginning of this section. Its first
argument is a resource object previously returned by
-\f3new_CompleteWord()\f1. The \f3line\f1 argument is the input line
+\f3new_WordCompletion()\f1. The \f3line\f1 argument is the input line
string, containing the word to be completed. The \f3word_end\f1
argument contains the index of the character in the input line, that
just follows the last character of the word to be completed. When
@@ -271,6 +294,15 @@ error which occurred on the last call to \f3cpl_complete_word()\f1 or
\f3cpl_add_completion()\f1.
.sp
.nf
+ CplMatches *cpl_recall_matches(WordCompletion *cpl);
+.fi
+.sp
+As a convenience, the return value of the last call to
+\f3cpl_complete_word()\f1 can be recalled at a later time by calling
+\f3cpl_recall_matches()\f1. If \f3cpl_complete_word()\f1 returned
+\f3NULL\f1, so will \f3cpl_recall_matches()\f1.
+.sp
+.nf
int cpl_list_completions(CplMatches *result, FILE *fp,
int terminal_width);
.fi
@@ -285,7 +317,7 @@ thus indicating their types to the user.
.SH THE BUILT-IN FILENAME-COMPLETION CALLBACK
-By default the \f3gl_get_line(3)\f1 function, passes the following
+By default the \f3gl_get_line(@FUNC_MANEXT@)\f1 function, passes the following
completion callback function to \f3cpl_complete_word()\f1. This
function can also be used separately, either by sending it to
\f3cpl_complete_word()\f1, or by calling it directly from your
@@ -399,7 +431,11 @@ libtecla.h - The tecla header file.
.fi
.SH SEE ALSO
-libtecla(3), gl_get_line(3), ef_expand_file(3), pca_lookup_file(3)
-
+
+.nf
+libtecla(@LIBR_MANEXT@), gl_get_line(@FUNC_MANEXT@), ef_expand_file(@FUNC_MANEXT@),
+pca_lookup_file(@FUNC_MANEXT@)
+.fi
+
.SH AUTHOR
Martin Shepherd (mcs@astro.caltech.edu)
diff --git a/libtecla-1.6.1/man/func/cpl_file_completions.in b/libtecla-1.6.1/man/func/cpl_file_completions.in
new file mode 100644
index 0000000..734f281
--- /dev/null
+++ b/libtecla-1.6.1/man/func/cpl_file_completions.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/cpl_complete_word.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/cpl_last_error.in b/libtecla-1.6.1/man/func/cpl_last_error.in
new file mode 100644
index 0000000..734f281
--- /dev/null
+++ b/libtecla-1.6.1/man/func/cpl_last_error.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/cpl_complete_word.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/cpl_list_completions.in b/libtecla-1.6.1/man/func/cpl_list_completions.in
new file mode 100644
index 0000000..734f281
--- /dev/null
+++ b/libtecla-1.6.1/man/func/cpl_list_completions.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/cpl_complete_word.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/cpl_recall_matches.in b/libtecla-1.6.1/man/func/cpl_recall_matches.in
new file mode 100644
index 0000000..734f281
--- /dev/null
+++ b/libtecla-1.6.1/man/func/cpl_recall_matches.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/cpl_complete_word.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/cpl_record_error.in b/libtecla-1.6.1/man/func/cpl_record_error.in
new file mode 100644
index 0000000..734f281
--- /dev/null
+++ b/libtecla-1.6.1/man/func/cpl_record_error.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/cpl_complete_word.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/del_CplFileConf.in b/libtecla-1.6.1/man/func/del_CplFileConf.in
new file mode 100644
index 0000000..734f281
--- /dev/null
+++ b/libtecla-1.6.1/man/func/del_CplFileConf.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/cpl_complete_word.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/del_ExpandFile.in b/libtecla-1.6.1/man/func/del_ExpandFile.in
new file mode 100644
index 0000000..3d0a884
--- /dev/null
+++ b/libtecla-1.6.1/man/func/del_ExpandFile.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/ef_expand_file.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/del_GetLine.in b/libtecla-1.6.1/man/func/del_GetLine.in
new file mode 100644
index 0000000..6e46fc6
--- /dev/null
+++ b/libtecla-1.6.1/man/func/del_GetLine.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_get_line.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/del_PathCache.in b/libtecla-1.6.1/man/func/del_PathCache.in
new file mode 100644
index 0000000..dbc4da7
--- /dev/null
+++ b/libtecla-1.6.1/man/func/del_PathCache.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/pca_lookup_file.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/del_PcaPathConf.in b/libtecla-1.6.1/man/func/del_PcaPathConf.in
new file mode 100644
index 0000000..dbc4da7
--- /dev/null
+++ b/libtecla-1.6.1/man/func/del_PcaPathConf.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/pca_lookup_file.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/del_WordCompletion.in b/libtecla-1.6.1/man/func/del_WordCompletion.in
new file mode 100644
index 0000000..734f281
--- /dev/null
+++ b/libtecla-1.6.1/man/func/del_WordCompletion.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/cpl_complete_word.@FUNC_MANEXT@
diff --git a/libtecla-1.4.1/man3/ef_expand_file.3 b/libtecla-1.6.1/man/func/ef_expand_file.in
index 88c2d54..f23f3eb 100644
--- a/libtecla-1.4.1/man3/ef_expand_file.3
+++ b/libtecla-1.6.1/man/func/ef_expand_file.in
@@ -1,4 +1,4 @@
-.\" Copyright (C) 2000, 2001 by Martin C. Shepherd
+.\" Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd
.\"
.\" All rights reserved.
.\"
@@ -26,7 +26,7 @@
.\" shall not be used in advertising or otherwise to promote the sale, use
.\" or other dealings in this Software without prior written authorization
.\" of the copyright holder.
-.TH ef_expand_file 3
+.TH ef_expand_file @FUNC_MANEXT@
.SH NAME
ef_expand_file, del_ExpandFile, ef_last_error, ef_list_expansions, new_ExpandFile \- expand filenames containing ~user/$envvar and wildcard expressions
.SH SYNOPSIS
@@ -50,7 +50,7 @@ const char *ef_last_error(ExpandFile *ef);
.SH DESCRIPTION
The \f3ef_expand_file()\f1 function is part of the tecla library
-(see the libtecla(3) man page). It expands a specified filename,
+(see the libtecla(@LIBR_MANEXT@) man page). It expands a specified filename,
converting \f3~user/\f1 and \f3~/\f1 expressions at the start of the
filename to the corresponding home directories, replacing
\f3$envvar\f1 with the value of the corresponding environment
@@ -239,7 +239,10 @@ libtecla.h - The tecla header file.
.fi
.SH SEE ALSO
-libtecla(3), gl_get_line(3), cpl_complete_word(3), pca_lookup_file(3)
-
+.nf
+libtecla(@LIBR_MANEXT@), gl_get_line(@FUNC_MANEXT@), cpl_complete_word(@FUNC_MANEXT@),
+pca_lookup_file(@FUNC_MANEXT@)
+.fi
+
.SH AUTHOR
Martin Shepherd (mcs@astro.caltech.edu)
diff --git a/libtecla-1.6.1/man/func/ef_last_error.in b/libtecla-1.6.1/man/func/ef_last_error.in
new file mode 100644
index 0000000..3d0a884
--- /dev/null
+++ b/libtecla-1.6.1/man/func/ef_last_error.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/ef_expand_file.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/ef_list_expansions.in b/libtecla-1.6.1/man/func/ef_list_expansions.in
new file mode 100644
index 0000000..3d0a884
--- /dev/null
+++ b/libtecla-1.6.1/man/func/ef_list_expansions.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/ef_expand_file.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/gl_abandon_line.in b/libtecla-1.6.1/man/func/gl_abandon_line.in
new file mode 100644
index 0000000..24798bc
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_abandon_line.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_io_mode.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/gl_bind_keyseq.in b/libtecla-1.6.1/man/func/gl_bind_keyseq.in
new file mode 100644
index 0000000..6e46fc6
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_bind_keyseq.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_get_line.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/gl_catch_blocked.in b/libtecla-1.6.1/man/func/gl_catch_blocked.in
new file mode 100644
index 0000000..6e46fc6
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_catch_blocked.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_get_line.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/gl_change_terminal.in b/libtecla-1.6.1/man/func/gl_change_terminal.in
new file mode 100644
index 0000000..6e46fc6
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_change_terminal.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_get_line.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/gl_clear_history.in b/libtecla-1.6.1/man/func/gl_clear_history.in
new file mode 100644
index 0000000..6e46fc6
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_clear_history.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_get_line.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/gl_completion_action.in b/libtecla-1.6.1/man/func/gl_completion_action.in
new file mode 100644
index 0000000..6e46fc6
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_completion_action.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_get_line.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/gl_configure_getline.in b/libtecla-1.6.1/man/func/gl_configure_getline.in
new file mode 100644
index 0000000..6e46fc6
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_configure_getline.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_get_line.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/gl_customize_completion.in b/libtecla-1.6.1/man/func/gl_customize_completion.in
new file mode 100644
index 0000000..6e46fc6
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_customize_completion.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_get_line.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/gl_display_text.in b/libtecla-1.6.1/man/func/gl_display_text.in
new file mode 100644
index 0000000..6e46fc6
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_display_text.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_get_line.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/gl_echo_mode.in b/libtecla-1.6.1/man/func/gl_echo_mode.in
new file mode 100644
index 0000000..6e46fc6
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_echo_mode.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_get_line.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/gl_erase_terminal.in b/libtecla-1.6.1/man/func/gl_erase_terminal.in
new file mode 100644
index 0000000..6e46fc6
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_erase_terminal.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_get_line.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/gl_error_message.in b/libtecla-1.6.1/man/func/gl_error_message.in
new file mode 100644
index 0000000..6e46fc6
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_error_message.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_get_line.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/gl_get_line.in b/libtecla-1.6.1/man/func/gl_get_line.in
new file mode 100644
index 0000000..1995108
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_get_line.in
@@ -0,0 +1,2236 @@
+.\" Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd
+.\"
+.\" All rights reserved.
+.\"
+.\" Permission is hereby granted, free of charge, to any person obtaining a
+.\" copy of this software and associated documentation files (the
+.\" "Software"), to deal in the Software without restriction, including
+.\" without limitation the rights to use, copy, modify, merge, publish,
+.\" distribute, and/or sell copies of the Software, and to permit persons
+.\" to whom the Software is furnished to do so, provided that the above
+.\" copyright notice(s) and this permission notice appear in all copies of
+.\" the Software and that both the above copyright notice(s) and this
+.\" permission notice appear in supporting documentation.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+.\" OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+.\" OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+.\" HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
+.\" INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
+.\" FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+.\" NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+.\" WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\" Except as contained in this notice, the name of a copyright holder
+.\" shall not be used in advertising or otherwise to promote the sale, use
+.\" or other dealings in this Software without prior written authorization
+.\" of the copyright holder.
+.TH gl_get_line @FUNC_MANEXT@
+.SH NAME
+gl_get_line, new_GetLine, del_GetLine, gl_customize_completion,
+gl_change_terminal, gl_configure_getline, gl_load_history,
+gl_save_history, gl_group_history, gl_show_history, gl_watch_fd,
+gl_inactivity_timeout, gl_terminal_size, gl_set_term_size,
+gl_resize_history, gl_limit_history, gl_clear_history,
+gl_toggle_history, gl_lookup_history, gl_state_of_history,
+gl_range_of_history, gl_size_of_history, gl_echo_mode,
+gl_replace_prompt, gl_prompt_style, gl_ignore_signal, gl_trap_signal,
+gl_last_signal, gl_completion_action, gl_display_text,
+gl_return_status, gl_error_message, gl_catch_blocked, gl_list_signals,
+gl_bind_keyseq, gl_erase_terminal, gl_automatic_history, gl_append_history,
+gl_query_char, gl_read_char \- allow the user to compose an input line
+.SH SYNOPSIS
+.nf
+#include <stdio.h>
+#include <libtecla.h>
+
+GetLine *new_GetLine(size_t linelen, size_t histlen);
+
+GetLine *del_GetLine(GetLine *gl);
+
+char *gl_get_line(GetLine *gl, const char *prompt,
+ const char *start_line, int start_pos);
+
+int gl_query_char(GetLine *gl, const char *prompt,
+ char defchar);
+
+int gl_read_char(GetLine *gl);
+
+int gl_customize_completion(GetLine *gl, void *data,
+ CplMatchFn *match_fn);
+
+int gl_change_terminal(GetLine *gl, FILE *input_fp,
+ FILE *output_fp, const char *term);
+
+int gl_configure_getline(GetLine *gl,
+ const char *app_string,
+ const char *app_file,
+ const char *user_file);
+
+int gl_bind_keyseq(GetLine *gl, GlKeyOrigin origin,
+ const char *keyseq, const char *action);
+
+int gl_save_history(GetLine *gl, const char *filename,
+ const char *comment, int max_lines);
+
+int gl_load_history(GetLine *gl, const char *filename,
+ const char *comment);
+
+int gl_watch_fd(GetLine *gl, int fd, GlFdEvent event,
+ GlFdEventFn *callback, void *data);
+
+int gl_inactivity_timeout(GetLine *gl, GlTimeoutFn *callback,
+ void *data, unsigned long sec,
+ unsigned long nsec);
+
+int gl_group_history(GetLine *gl, unsigned stream);
+
+int gl_show_history(GetLine *gl, FILE *fp,
+ const char *fmt, int all_groups,
+ int max_lines);
+
+int gl_resize_history(GetLine *gl, size_t bufsize);
+
+void gl_limit_history(GetLine *gl, int max_lines);
+
+void gl_clear_history(GetLine *gl, int all_groups);
+
+void gl_toggle_history(GetLine *gl, int enable);
+
+GlTerminalSize gl_terminal_size(GetLine *gl,
+ int def_ncolumn,
+ int def_nline);
+
+int gl_set_term_size(GetLine *gl, int ncolumn, int nline);
+
+int gl_lookup_history(GetLine *gl, unsigned long id,
+ GlHistoryLine *hline);
+
+void gl_state_of_history(GetLine *gl,
+ GlHistoryState *state);
+
+void gl_range_of_history(GetLine *gl,
+ GlHistoryRange *range);
+
+void gl_size_of_history(GetLine *gl, GlHistorySize *size);
+
+void gl_echo_mode(GetLine *gl, int enable);
+
+void gl_replace_prompt(GetLine *gl, const char *prompt);
+
+void gl_prompt_style(GetLine *gl, GlPromptStyle style);
+
+int gl_ignore_signal(GetLine *gl, int signo);
+
+int gl_trap_signal(GetLine *gl, int signo, unsigned flags,
+ GlAfterSignal after, int errno_value);
+
+int gl_last_signal(GetLine *gl);
+
+int gl_completion_action(GetLine *gl,
+ void *data, CplMatchFn *match_fn,
+ int list_only, const char *name,
+ const char *keyseq);
+
+int gl_register_action(GetLine *gl, void *data,
+ GlActionFn *fn, const char *name,
+ const char *keyseq);
+
+int gl_display_text(GetLine *gl, int indentation,
+ const char *prefix,
+ const char *suffix, int fill_char,
+ int def_width, int start,
+ const char *string);
+
+GlReturnStatus gl_return_status(GetLine *gl);
+
+const char *gl_error_message(GetLine *gl, char *buff,
+ size_t n);
+
+void gl_catch_blocked(GetLine *gl);
+
+int gl_list_signals(GetLine *gl, sigset_t *set);
+
+int gl_append_history(GetLine *gl, const char *line);
+
+int gl_automatic_history(GetLine *gl, int enable);
+
+.fi
+
+.SH DESCRIPTION
+
+The \f3gl_get_line()\f1 function is part of the tecla library (see the
+\f3libtecla(@LIBR_MANEXT@)\f1 man page). If the user is typing at a terminal, each
+call prompts them for an line of input, then provides interactive
+editing facilities, similar to those of the unix \f3tcsh\f1 shell. In
+addition to simple command-line editing, it supports recall of
+previously entered command lines, TAB completion of file names, and
+in-line wild-card expansion of filenames. Documentation of both the
+user-level command-line editing features and all user configuration
+options, can be found in the \f3tecla(@MISC_MANEXT@)\f1 man page. This man page
+concerns itself with documentation for programmers interested in using
+this library in their application.
+.sp
+.SH AN EXAMPLE
+
+The following shows a complete example of how to use the
+\f3gl_get_line()\f1 function to get input from the user:
+
+.nf
+ #include <stdio.h>
+ #include <locale.h>
+ #include <libtecla.h>
+
+ int main(int argc, char *argv[])
+ {
+ char *line; /* The line that the user typed */
+ GetLine *gl; /* The gl_get_line() resource object */
+
+ setlocale(LC_CTYPE, ""); /* Adopt the user's choice */
+ /* of character set. */
+
+ gl = new_GetLine(1024, 2048);
+ if(!gl)
+ return 1;
+
+ while((line=gl_get_line(gl, "$ ", NULL, -1)) != NULL &&
+ strcmp(line, "exit\\n") != 0)
+ printf("You typed: %s\\n", line);
+
+ gl = del_GetLine(gl);
+ return 0;
+ }
+.fi
+.sp
+In the example, first the resources needed by the \f3gl_get_line()\f1 function
+are created by calling \f3new_GetLine()\f1. This allocates the memory used in
+subsequent calls to the \f3gl_get_line()\f1 function, including the history
+buffer for recording previously entered lines. Then one or more lines are read
+from the user, until either an error occurs, or the user types \f3exit\f1. Then
+finally the resources that were allocated by \f3new_GetLine()\f1, are returned
+to the system by calling \f3del_GetLine()\f1. Note the use of the \f3NULL\f1
+return value of \f3del_GetLine()\f1 to make \f3gl\f1 \f3NULL\f1. This is a
+safety precaution. If the program subsequently attempts to pass \f3gl\f1 to
+\f3gl_get_line()\f1, said function will complain, and return an error, instead of
+attempting to use the deleted resource object.
+
+.sp
+.SH THE FUNCTIONS USED IN THE EXAMPLE
+The descriptions of the functions used in the example are as follows:
+.sp
+.nf
+ GetLine *new_GetLine(size_t linelen, size_t histlen)
+.fi
+.sp
+This function creates the resources used by the \f3gl_get_line()\f1
+function and returns an opaque pointer to the object that contains
+them. The maximum length of an input line is specified via the
+\f3linelen\f1 argument, and the number of bytes to allocate for
+storing history lines is set by the \f3histlen\f1 argument. History
+lines are stored back-to-back in a single buffer of this size. Note
+that this means that the number of history lines that can be stored at
+any given time, depends on the lengths of the individual lines. If
+you want to place an upper limit on the number of lines that can be
+stored, see the \f3gl_limit_history()\f1 function described later. If
+you don't want history at all, specify \f3histlen\f1 as zero, and no
+history buffer will be allocated.
+.sp
+On error, a message is printed to \f3stderr\f1 and \f3NULL\f1 is returned.
+.sp
+.nf
+ GetLine *del_GetLine(GetLine *gl)
+.fi
+.sp
+This function deletes the resources that were returned by a previous
+call to \f3new_GetLine()\f1. It always returns \f3NULL\f1 (ie a
+deleted object). It does nothing if the \f3gl\f1 argument is
+\f3NULL\f1.
+.sp
+.nf
+ char *gl_get_line(GetLine *gl, const char *prompt,
+ const char *start_line, int start_pos);
+.fi
+.sp
+The \f3gl_get_line()\f1 function can be called any number of
+times to read input from the user. The \f3gl\f1 argument
+must have been previously returned by a call to
+\f3new_GetLine()\f1. The \f3prompt\f1 argument should be a
+normal \f3NUL\f1 terminated string, specifying the prompt to
+present the user with. By default prompts are displayed
+literally, but if enabled with the \f3gl_prompt_style()\f1
+function (see later), prompts can contain directives to do
+underlining, switch to and from bold fonts, or turn
+highlighting on and off.
+
+If you want to specify the initial contents of the line, for the user
+to edit, pass the desired string via the \f3start_line\f1
+argument. You can then specify which character of this line the cursor
+is initially positioned over, using the \f3start_pos\f1 argument. This
+should be -1 if you want the cursor to follow the last character of
+the start line. If you don't want to preload the line in this manner,
+send \f3start_line\f1 as \f3NULL\f1, and set \f3start_pos\f1 to
+-1. Note that the line pointer returned by one call to
+\f3gl_get_line()\f1 can be passed back to the next call to
+\f3gl_get_line()\f1 via the \f3start_line\f1. This allows the
+application to take the last entered line, and if it contains an
+error, to then present it back to the user for re-editing, with the
+cursor initially positioned where the error was encountered.
+
+The \f3gl_get_line()\f1 function returns a pointer to the line entered
+by the user, or \f3NULL\f1 on error or at the end of the input. The
+returned pointer is part of the specified \f3gl\f1 resource object,
+and thus should not be free'd by the caller, or assumed to be
+unchanging from one call to the next. When reading from a user at a
+terminal, there will always be a newline character at the end of the
+returned line. When standard input is being taken from a pipe or a
+file, there will similarly be a newline unless the input line was too
+long to store in the internal buffer. In the latter case you should
+call \f3gl_get_line()\f1 again to read the rest of the line. Note that
+this behavior makes \f3gl_get_line()\f1 similar to \f3fgets()\f1. In
+fact when \f3stdin\f1 isn't connected to a terminal,\f3gl_get_line()\f1
+just calls \f3fgets()\f1.
+
+.SH THE RETURN STATUS OF GL_GET_LINE
+
+As described above, the \f3gl_get_line()\f1 function has two possible
+return values; a pointer to the completed input line, or
+\f3NULL\f1. Extra information about what caused \f3gl_get_line()\f1 to
+return is available both by inspecting \f3errno\f1, and by calling the
+\f3gl_return_status()\f1 function.
+
+.sp
+.nf
+ GlReturnStatus gl_return_status(GetLine *gl);
+.fi
+.sp
+
+The following are the possible enumerated values that this
+function returns.
+
+.sp
+.nf
+ GLR_NEWLINE - The last call to \f3gl_get_line()\f1
+ successfully returned a completed
+ input line.
+
+ GLR_BLOCKED - \f3gl_get_line()\f1 was in non-blocking
+ server mode, and returned early to
+ avoid blocking the process while
+ waiting for terminal I/O. The
+ \f3gl_pending_io()\f1 function can be
+ used to see what type of I/O
+ \f3gl_get_line()\f1 was waiting for.
+ (see the \f3gl_io_mode(@FUNC_MANEXT@)\f1 man page
+ for details).
+
+ GLR_SIGNAL - A signal was caught by
+ \f3gl_get_line()\f1 that had an
+ after-signal disposition of
+ \f3GLS_ABORT\f1 (See \f3gl_trap_signal()\f1).
+
+ GLR_TIMEOUT - The inactivity timer expired while
+ \f3gl_get_line()\f1 was waiting for
+ input, and the timeout callback
+ function returned \f3GLTO_ABORT\f1.
+ See \f3gl_inactivity_timeout()\f1 for
+ information about timeouts.
+
+ GLR_FDABORT - An application I/O callack returned
+ \f3GLFD_ABORT\f1 (see \f3gl_watch_fd()\f1).
+
+ GLR_EOF - End of file reached. This can happen
+ when input is coming from a file or a
+ pipe, instead of the terminal. It also
+ occurs if the user invokes the
+ \f3list-or-eof\f1 or \f3del-char-or-list-or-eof\f1
+ actions at the start of a new line.
+
+ GLR_ERROR - An unexpected error caused
+ \f3gl_get_line()\f1 to abort (consult
+ \f3errno\f1 and/or
+ \f3gl_error_message()\f1 for details.
+.fi
+.sp
+
+When \f3gl_return_status()\f1 returns \f3GLR_ERROR\f1, and the
+value of \f3errno\f1 isn't sufficient to explain what
+happened, you can use the \f3gl_error_message()\f1 function
+to request a description of the last error that occurred.
+
+.sp
+.nf
+ const char *gl_error_message(GetLine *gl, char *buff,
+ size_t n);
+.fi
+.sp
+
+The return value is a pointer to the message that
+occurred. If the \f3buff\f1 argument is \f3NULL\f1, this
+will be a pointer to a buffer within \f3gl\f1, who's value
+will probably change on the next call to any function
+associated with \f3gl_get_line()\f1. Otherwise, if a
+non-\f3NULL\f1 \f3buff\f1 argument is provided, the error
+message, including a \f3'\\0'\f1 terminator, will be written
+within the first \f3n\f1 elements of this buffer, and the
+return value will be a pointer to the first element of this
+buffer. If the message won't fit in the provided buffer, it
+will be truncated to fit.
+
+.SH OPTIONAL PROMPT FORMATTING
+
+Whereas by default the prompt string that you specify is
+displayed literally, without any special interpretation of
+the characters within it, the \f3gl_prompt_style()\f1
+function can be used to enable optional formatting
+directives within the prompt.
+.sp
+.nf
+ void gl_prompt_style(GetLine *gl, GlPromptStyle style);
+.fi
+.sp
+The \f3style\f1 argument, which specifies the formatting
+style, can take any of the following values:
+.sp
+.nf
+ GL_FORMAT_PROMPT - In this style, the formatting
+ directives described below, when
+ included in prompt strings, are
+ interpreted as follows:
+
+ %B - Display subsequent
+ characters with a bold
+ font.
+ %b - Stop displaying characters
+ with the bold font.
+ %F - Make subsequent characters
+ flash.
+ %f - Turn off flashing
+ characters.
+ %U - Underline subsequent
+ characters.
+ %u - Stop underlining
+ characters.
+ %P - Switch to a pale (half
+ brightness) font.
+ %p - Stop using the pale font.
+ %S - Highlight subsequent
+ characters (also known as
+ standout mode).
+ %s - Stop highlighting
+ characters.
+ %V - Turn on reverse video.
+ %v - Turn off reverse video.
+ %% - Display a single %
+ character.
+
+ For example, in this mode, a prompt
+ string like \f3"%UOK%u$ "\f1 would
+ display the prompt \f3"OK$ "\f1,
+ but with the \f3OK\f1 part
+ underlined.
+
+ Note that although a pair of
+ characters that starts with a %
+ character, but doesn't match any of
+ the above directives is displayed
+ literally, if a new directive is
+ subsequently introduced which does
+ match, the displayed prompt will
+ change, so it is better to always
+ use %% to display a literal %.
+
+ Also note that not all terminals
+ support all of these text
+ attributes, and that some substitute
+ a different attribute for missing
+ ones.
+
+ GL_LITERAL_PROMPT - In this style, the prompt string is
+ printed literally. This is the
+ default style.
+.fi
+
+.SH ALTERNATE CONFIGURATION SOURCES
+
+As mentioned above, by default users have the option of configuring
+the behavior of \f3gl_get_line()\f1 via a configuration file called
+\f3\&.teclarc\f1 in their home directories. The fact that all
+applications share this same configuration file is both an advantage
+and a disadvantage. In most cases it is an advantage, since it
+encourages uniformity, and frees the user from having to configure
+each application separately. In some applications, however, this
+single means of configuration is a problem. This is particularly true
+of embedded software, where there's no filesystem to read a
+configuration file from, and also in applications where a radically
+different choice of keybindings is needed to emulate a legacy keyboard
+interface. To cater for such cases, the following function allows the
+application to control where configuration information is read from.
+
+.sp
+.nf
+ int gl_configure_getline(GetLine *gl,
+ const char *app_string,
+ const char *app_file,
+ const char *user_file);
+.fi
+.sp
+
+It allows the configuration commands that would normally be read from
+a user's \f3~/.teclarc\f1 file, to be read from any or none of, a
+string, an application specific configuration file, and/or a
+user-specific configuration file. If this function is called before
+the first call to \f3gl_get_line()\f1, the default behavior of
+reading \f3~/.teclarc\f1 on the first call to \f3gl_get_line()\f1 is
+disabled, so all configuration must be achieved using the
+configuration sources specified with this function.
+
+If \f3app_string != NULL\f1, then it is interpreted as a string
+containing one or more configuration commands, separated from each
+other in the string by embedded newline characters. If \f3app_file !=
+NULL\f1 then it is interpreted as the full pathname of an
+application-specific configuration file. If \f3user_file != NULL\f1
+then it is interpreted as the full pathname of a user-specific
+configuration file, such as \f3~/.teclarc\f1. For example, in the
+following call,
+
+.sp
+.nf
+ gl_configure_getline(gl, "edit-mode vi \\n nobeep",
+ "/usr/share/myapp/teclarc",
+ "~/.teclarc");
+.fi
+.sp
+
+the \f3app_string\f1 argument causes the calling application to start
+in vi edit-mode, instead of the default emacs mode, and turns off the
+use of the terminal bell by the library. It then attempts to read
+system-wide configuration commands from an optional file called
+\f3/usr/share/myapp/teclarc\f1, then finally reads user-specific
+configuration commands from an optional \f3\&.teclarc\f1 file in the
+user's home directory. Note that the arguments are listed in ascending
+order of priority, with the contents of \f3app_string\f1 being
+potentially overriden by commands in \f3app_file\f1, and commands in
+\f3app_file\f1 potentially being overriden by commands in
+\f3user_file\f1.
+.sp
+You can call this function as many times as needed, the results being
+cumulative, but note that copies of any filenames specified via the
+\f3app_file\f1 and \f3user_file\f1 arguments are recorded internally
+for subsequent use by the \f3read-init-files\f1 key-binding function,
+so if you plan to call this function multiple times, be sure that the
+last call specifies the filenames that you want re-read when the user
+requests that the configuration files be re-read.
+.sp
+Individual key sequences can also be bound and unbound using the
+\f3gl_bind_keyseq()\f1 function.
+
+.sp
+.nf
+ int gl_bind_keyseq(GetLine *gl, GlKeyOrigin origin,
+ const char *keyseq,
+ const char *action);
+.fi
+.sp
+
+The \f3origin\f1 argument specifies the priority of the binding,
+according to who it is being established for, and must be one of
+the following two values.
+.sp
+.nf
+ GL_USER_KEY - The user requested this key-binding.
+ GL_APP_KEY - This is a default binding set by the
+ application.
+.fi
+.sp
+When both user and application bindings for a given key-sequence have
+been specified, the user binding takes precedence. The application's
+binding is subsequently reinstated if the user's binding is later
+unbound via either another to this function, or a call to
+\f3gl_configure_getline()\f1.
+
+The \f3keyseq\f1 argument specifies the key-sequence to be bound or
+unbound, and is expressed in the same way as in a \f3~/.teclarc\f1
+configuration file. The \f3action\f1 argument must either be a string
+containing the name of the action to bind the key-sequence to, or it
+must be \f3NULL\f1 or "" to unbind the key-sequence.
+
+.SH CUSTOMIZED WORD COMPLETION
+
+If in your application, you would like to have TAB completion complete
+other things in addition to or instead of filenames, you can arrange
+this by registering an alternate completion callback function, via a
+call to the \f3gl_customize_completion()\f1 function.
+.sp
+.nf
+ int gl_customize_completion(GetLine *gl, void *data,
+ CplMatchFn *match_fn);
+.fi
+.sp
+The \f3data\f1 argument provides a way for your application to pass
+arbitrary, application-specific information to the callback
+function. This is passed to the callback every time that it is
+called. It might for example, point to the symbol table from which
+possible completions are to be sought. The \f3match_fn\f1 argument
+specifies the callback function to be called. The \f3CplMatchFn\f1
+function type is defined in \f3libtecla.h\f1, as is a
+\f3CPL_MATCH_FN()\f1 macro that you can use to declare and prototype
+callback functions. The declaration and responsibilities of callback
+functions are described in depth in the \f1cpl_complete_word(@FUNC_MANEXT@)\f1 man
+page.
+.sp
+In brief, the callback function is responsible for looking backwards
+in the input line, back from the point at which the user pressed TAB,
+to find the start of the word being completed. It then must lookup
+possible completions of this word, and record them one by one in the
+\f3WordCompletion\f1 object that is passed to it as an argument, by
+calling the \f3cpl_add_completion()\f1 function. If the callback
+function wishes to provide filename completion in addition to its own
+specific completions, it has the option of itself calling the builtin
+file-name completion callback. This also, is documented in the
+\f3cpl_complete_word(@FUNC_MANEXT@)\f1 man page.
+.sp
+Note that if you would like \f3gl_get_line()\f1 to return the current
+input line when a successful completion is been made, you can arrange
+this when you call \f3cpl_add_completion()\f1, by making the last
+character of the continuation suffix a newline character. If you do
+this, the input line will be updated to display the completion,
+together with any contiuation suffix up to the newline character, then
+\f3gl_get_line()\f1 will return this input line.
+.sp
+
+If, for some reason, your callback function needs to write something
+to the terminal, it must call \f3gl_normal_io()\f1 before doing
+so. This will start a new line after the input line that is currently
+being edited, reinstate normal terminal I/O, and tell
+\f3gl_get_line()\f1 that the input line will need to be redrawn when
+the callback returns.
+
+.SH ADDING COMPLETION ACTIONS
+
+In the previous section the ability to customize the behavior of the
+only default completion action, \f3complete-word\f1, was described.
+In this section the ability to install additional action functions, so
+that different types of word completion can be bound to different
+key-sequences, is described. This is achieved by using the
+\f3gl_completion_action()\f1 function.
+
+.sp
+.nf
+ int gl_completion_action(GetLine *gl,
+ void *data, CplMatchFn *match_fn,
+ int list_only, const char *name,
+ const char *keyseq);
+.fi
+.sp
+
+The \f3data\f1 and \f3match_fn\f1 arguments are as described
+in the \f3cpl_complete_word\f1 man page, and specify the
+callback function that should be invoked to identify
+possible completions. The \f3list_only\f1 argument
+determines whether the action that is being defined should
+attempt to complete the word as far as possible in the input
+line before displaying any possible ambiguous completions,
+or whether it should simply display the list of possible
+completions without touching the input line. The former
+option is selected by specifying a value of \f30\f1, and the
+latter by specifying a value of \f31\f1. The \f3name\f1
+argument specifies the name by which configuration files and
+future invokations of this function should refer to the
+action. This must either be the name of an existing
+completion action to be changed, or be a new unused name for
+a new action. Finally, the \f3keyseq\f1 argument specifies
+the default key-sequence to bind the action to. If this is
+\f3NULL\f1, no new keysequence will be bound to the action.
+
+Beware that in order for the user to be able to change the
+key-sequence that is bound to actions that are installed in
+this manner, when you call \f3gl_completion_action()\f1 to
+install a given action for the first time, you should do
+this between calling \f3new_GetLine()\f1 and the first call
+to \f3gl_get_line()\f1. Otherwise, when the user's
+configuration file is read on the first call to
+\f3gl_get_line()\f1, the name of the your additional action
+won't be known, and any reference to it in the configuration
+file will generate an error.
+
+As discussed for \f3gl_customize_completion()\f1, if your callback
+function, for some reason, needs to write anything to the terminal, it
+must call \f3gl_normal_io()\f1 before doing so.
+
+.SH DEFINING CUSTOM ACTIONS
+
+Although the built-in key-binding actions are sufficient for the needs
+of most applications, occasionally a specialized application may need
+to define one or more custom actions, bound to application-specific
+key-sequences. For example, a sales application would benefit from
+having a key-sequence that displayed the part name that corresponded
+to a part number preceding the cursor. Such a feature is clearly
+beyond the scope of the built-in action functions. So for such special
+cases, the \f3gl_register_action()\f1 function is provided.
+
+.sp
+.nf
+ int gl_register_action(GetLine *gl, void *data,
+ GlActionFn *fn, const char *name,
+ const char *keyseq);
+.fi
+.sp
+
+This function lets the application register an external function,
+\f3fn\f1, that will thereafter be called whenever either the specified
+key-sequence, \f3keyseq\f1, is entered by the user, or the user enters
+any other key-sequence that the user subsequently binds to the
+specified action name, \f3name\f1, in their configuration file. The
+\f3data\f1 argument can be a pointer to anything that the application
+wishes to have passed to the action function, \f3fn\f1, whenever that
+function is invoked.
+
+The action function, \f3fn\f1, should be declared using the following
+macro, which is defined in \f3libtecla.h\f1.
+
+.sp
+.nf
+ #define GL_ACTION_FN(fn) GlAfterAction (fn)(GetLine *gl, \\
+ void *data, int count, size_t curpos, \\
+ const char *line)
+.fi
+.sp
+
+The \f3gl\f1 and \f3data\f1 arguments are those that were previously
+passed to \f3gl_register_action()\f1 when the action function was
+registered. The \f3count\f1 argument is a numeric argument which the
+user has the option of entering using the \f3digit-argument\f1 action,
+before invoking the action. If the user doesn't enter a number, then
+the \f3count\f1 argument is set to 1. Nominally this argument is
+interpreted as a repeat count, meaning that the action should be
+repeated that many times. In practice however, for some actions a
+repeat count makes little sense. In such cases, actions can either
+simply ignore the \f3count\f1 argument, or use its value for a
+different purpose.
+
+A copy of the current input line is passed in the read-only \f3line\f1
+argument. The current cursor position within this string is given by
+the index contained in the \f3curpos\f1 argument. Note that direct
+manipulation of the input line and the cursor position is not
+permitted. This is because the rules dicated by various modes, such as
+vi mode versus emacs mode, no-echo mode, and insert mode versus
+overstrike mode etc, make it too complex for an application writer to
+write a conforming editing action, as well as constrain future changes
+to the internals of \f3gl_get_line()\f1. A potential solution to this
+dilema would be to allow the action function to edit the line using
+the existing editing actions. This is currently under consideration.
+
+If the action function wishes to write text to the terminal, without
+this getting mixed up with the displayed text of the input line, or
+read from the terminal without having to handle raw terminal I/O, then
+before doing either of these operations, it must temporarily suspend
+line editing by calling the \f3gl_normal_io()\f1 function. This
+function flushes any pending output to the terminal, moves the cursor
+to the start of the line that follows the last terminal line of the
+input line, then restores the terminal to a state that is suitable for
+use with the C stdio facilities. The latter includes such things as
+restoring the normal mapping of \f3\\n\f1 to \f3\\r\\n\f1, and, when
+in server mode, restoring the normal blocking form of terminal
+I/O. Having called this function, the action function can read from
+and write to the terminal without the fear of creating a mess. It
+isn't necessary for the action function to restore the original
+editing environment before it returns. This is done automatically by
+\f3gl_get_line()\f1 after the action function returns. The following
+is a simple example of an action function which writes the sentence
+"Hello world" on a new terminal line after the line being edited. When
+this function returns, the input line is redrawn on the line that
+follows the "Hello world" line, and line editing resumes.
+
+.sp
+.nf
+ static GL_ACTION_FN(say_hello_fn)
+ {
+ if(gl_normal_io(gl)) /* Temporarily suspend editing */
+ return GLA_ABORT;
+ printf("Hello world\\n");
+ return GLA_CONTINUE;
+ }
+.fi
+.sp
+
+Action functions must return one of the following values, to tell
+\f3gl_get_line()\f1 how to procede.
+
+.sp
+.nf
+ GLA_ABORT - Cause gl_get_line() to return NULL.
+ GLA_RETURN - Cause gl_get_line() to return the
+ completed input line.
+ GLA_CONTINUE - Resume command-line editing.
+.fi
+.sp
+
+Note that the \f3name\f1 argument of \f3gl_register_action()\f1
+specifies the name by which a user can refer to the action in their
+configuration file. This allows them to re-bind the action to an
+alternate key-seqeunce. In order for this to work, it is necessary to
+call \f3gl_register_action()\f1 between calling \f3new_GetLine()\f1
+and the first call to \f3gl_get_line()\f1.
+
+.SH HISTORY FILES
+
+To save the contents of the history buffer before quitting your
+application, and subsequently restore them when you next start the
+application, the following functions are provided.
+
+.sp
+.nf
+ int gl_save_history(GetLine *gl, const char *filename,
+ const char *comment, int max_lines);
+ int gl_load_history(GetLine *gl, const char *filename,
+ const char *comment);
+.fi
+.sp
+
+The \f3filename\f1 argument specifies the name to give the history
+file when saving, or the name of an existing history file, when
+loading. This may contain home-directory and environment variable
+expressions, such as "~/.myapp_history" or "$HOME/.myapp_history".
+.sp
+Along with each history line, extra information about it, such as when
+it was entered by the user, and what its nesting level is, is recorded
+as a comment preceding the line in the history file. Writing this as a
+comment allows the history file to double as a command file, just in
+case you wish to replay a whole session using it. Since comment
+prefixes differ in different languages, the \f3comment\f1 argument is
+provided for specifying the comment prefix. For example, if your
+application were a unix shell, such as the bourne shell, you would
+specify "#" here. Whatever you choose for the comment character, you
+must specify the same prefix to \f3gl_load_history()\f1 that you used
+when you called \f3gl_save_history()\f1 to write the history file.
+.sp
+The \f3max_lines\f1 must be either -1 to specify that all lines in the
+history list be saved, or a positive number specifying a ceiling on
+how many of the most recent lines should be saved.
+.sp
+Both fuctions return non-zero on error, after writing an error message
+to stderr. Note that \f3gl_load_history()\f1 does not consider the
+non-existence of a file to be an error.
+
+.SH MULTIPLE HISTORY LISTS
+
+If your application uses a single \f3GetLine\f1 object for entering
+many different types of input lines, you may wish \f3gl_get_line()\f1
+to distinguish the different types of lines in the history list, and
+only recall lines that match the current type of line. To support this
+requirement, \f3gl_get_line()\f1 marks lines being recorded in the
+history list with an integer identifier chosen by the application.
+Initially this identifier is set to \f10\f3 by \f3new_GetLine()\f1,
+but it can be changed subsequently by calling
+\f3gl_group_history()\f1.
+
+.sp
+.nf
+ int gl_group_history(GetLine *gl, unsigned id);
+.fi
+.sp
+
+The integer identifier \f3id\f1 can be any number chosen by the
+application, but note that \f3gl_save_history()\f1 and
+\f3gl_load_history()\f1 preserve the association between identifiers
+and historical input lines between program invokations, so you should
+choose fixed identifiers for the different types of input line used by
+your application.
+.sp
+Whenever \f3gl_get_line()\f1 appends a new input line to the history
+list, the current history identifier is recorded with it, and when it
+is asked to recall a historical input line, it only recalls lines that
+are marked with the current identifier.
+
+.SH DISPLAYING HISTORY
+
+The history list can be displayed by calling \f3gl_show_history()\f1.
+
+.sp
+.nf
+ int gl_show_history(GetLine *gl, FILE *fp,
+ const char *fmt,
+ int all_groups,
+ int max_lines);
+.fi
+.sp
+
+This displays the current contents of the history list to the stdio
+output stream \f3fp\f1. If the \f3max_lines\f1 argument is greater
+than or equal to zero, then no more than this number of the most
+recent lines will be displayed. If the \f3all_groups\f1 argument is
+non-zero, lines from all history groups are displayed. Otherwise just
+those of the currently selected history group are displayed. The
+format string argument, \f3fmt\f1, determines how the line is
+displayed. This can contain arbitrary characters which are written
+verbatim, interleaved with any of the following format directives:
+
+.nf
+ %D - The date on which the line was originally
+ entered, formatted like 2001-11-20.
+ %T - The time of day when the line was entered,
+ formatted like 23:59:59.
+ %N - The sequential entry number of the line in
+ the history buffer.
+ %G - The number of the history group which the
+ line belongs to.
+ %% - A literal % character.
+ %H - The history line itself.
+.fi
+
+Thus a format string like \f3"%D %T %H\n"\f1 would output something like:
+
+.nf
+ 2001-11-20 10:23:34 Hello world
+.fi
+
+Note the inclusion of an explicit newline character in the format
+string.
+
+.SH LOOKING UP HISTORY
+
+The \f3gl_lookup_history()\f1 function allows the calling application
+to look up lines in the history list.
+
+.sp
+.nf
+ typedef struct {
+ const char *line; /* The requested historical */
+ /* line. */
+ unsigned group; /* The history group to which */
+ /* the line belongs. */
+ time_t timestamp; /* The date and time at which */
+ /* the line was originally */
+ /* entered. */
+ } GlHistoryLine;
+
+ int gl_lookup_history(GetLine *gl, unsigned long id,
+ GlHistoryLine *hline);
+.fi
+.sp
+
+The \f3id\f1 argument indicates which line to look up, where the first
+line that was entered in the history list after \f3new_GetLine()\f1
+was called, is denoted by 0, and subsequently entered lines are
+denoted with successively higher numbers. Note that the range of lines
+currently preserved in the history list can be queried by calling the
+\f3gl_range_of_history()\f1 function, described later. If the
+requested line is in the history list, the details of the line are
+recorded in the variable pointed to by the \f3hline\f1 argument, and
+\f31\f1 is returned. Otherwise \f30\f1 is returned, and the variable
+pointed to by \f3hline\f1 is left unchanged.
+.sp
+Beware that the string returned in \f3hline->line\f1 is part of the
+history buffer, so it must not be modified by the caller, and will be
+recycled on the next call to any function that takes \f3gl\f1 as its
+argument. Therefore you should make a private copy of this string if
+you need to keep it around.
+
+.SH MANUAL HISTORY ARCHIVAL
+
+By default, whenever a line is entered by the user, it is
+automatically appended to the history list, just before
+\f3gl_get_line()\f1 returns the line to the caller. This is convenient
+for the majority of applications, but there are also applications that
+need finer grained control over what gets added to the history
+list. In such cases, the automatic addition of entered lines to the
+history list can be turned off by calling the
+\f3gl_automatic_history()\f1 function.
+
+.sp
+.nf
+ int gl_automatic_history(GetLine *gl, int enable);
+.fi
+.sp
+
+If this function is called with its \f3enable\f1 argument set to
+\f30\f1, \f3gl_get_line()\f1 won't automatically archive subsequently
+entered lines. Automatic archiving can be reenabled at a later time,
+by calling this function again, with its \f3enable\f1 argument set to
+1. While automatic history archiving is disabled, the calling
+application can use the \f3gl_append_history()\f1 to append lines to
+the history list as needed.
+
+.sp
+.nf
+ int gl_append_history(GetLine *gl, const char *line);
+.fi
+.sp
+
+The \f3line\f1 argument specifies the line to be added to the history
+list. This must be a normal \f3'\0'\f1 terminated string. If this
+string contains any newline characters, the line that gets archived in
+the history list will be terminated by the first of these. Otherwise
+it will be terminated by the \f3'\0'\f1 terminator. If the line is
+longer than the maximum input line length, that was specified when
+\f3new_GetLine()\f1 was called, when the line is recalled, it will get
+truncated to the actual \f3gl_get_line()\f1 line length.
+
+If successful, \f3gl_append_history()\f1 returns 0. Otherwise it
+returns non-zero, and sets \f3errno\f1 to one of the following values.
+
+.sp
+.nf
+ EINVAL - One of the arguments passed to
+ gl_append_history() was NULL.
+ ENOMEM - The specified line was longer than the allocated
+ size of the history buffer (as specified when
+ new_GetLine() was called), so it couldn't be
+ archived.
+.fi
+.sp
+
+A textual description of the error can optionally be obtained by
+calling \f3gl_error_message()\f1. Note that after such an error, the
+history list remains in a valid state to receive new history lines, so
+there is little harm in simply ignoring the return status of
+\f3gl_append_history()\f1.
+
+.SH MISCELLANEOUS HISTORY CONFIGURATION
+
+If you wish to change the size of the history buffer that was
+originally specified in the call to \f3new_GetLine()\f1, you can do so
+with the \f3gl_resize_history()\f1 function.
+
+.sp
+.nf
+ int gl_resize_history(GetLine *gl, size_t histlen);
+.fi
+.sp
+
+The \f3histlen\f1 argument specifies the new size in bytes, and if you
+specify this as 0, the buffer will be deleted.
+.sp
+As mentioned in the discussion of \f3new_GetLine()\f1, the number of
+lines that can be stored in the history buffer, depends on the lengths
+of the individual lines. For example, a 1000 byte buffer could equally
+store 10 lines of average length 100 bytes, or 2 lines of average
+length 50 bytes. Although the buffer is never expanded when new lines
+are added, a list of pointers into the buffer does get expanded when
+needed to accomodate the number of lines currently stored in the
+buffer. To place an upper limit on the number of lines in the buffer,
+and thus a ceiling on the amount of memory used in this list, you can
+call the \f3gl_limit_history()\f1 function.
+
+.sp
+.nf
+ void gl_limit_history(GetLine *gl, int max_lines);
+.fi
+.sp
+
+The \f3max_lines\f1 should either be a positive number \f3>= 0\f1,
+specifying an upper limit on the number of lines in the buffer, or be
+\f3-1\f1 to cancel any previously specified limit. When a limit is in
+effect, only the \f3max_lines\f1 most recently appended lines are kept
+in the buffer. Older lines are discarded.
+.sp
+To discard lines from the history buffer, use the
+\f3gl_clear_history()\f1 function.
+.sp
+.nf
+ void gl_clear_history(GetLine *gl, int all_groups);
+.fi
+.sp
+The \f3all_groups\f1 argument tells the function whether to delete
+just the lines associated with the current history group (see
+\f3gl_group_history()\f1), or all historical lines in the buffer.
+.sp
+The \f3gl_toggle_history()\f1 function allows you to toggle history on
+and off without losing the current contents of the history list.
+
+.sp
+.nf
+ void gl_toggle_history(GetLine *gl, int enable);
+.fi
+.sp
+
+Setting the \f3enable\f1 argument to 0 turns off the history
+mechanism, and setting it to 1 turns it back on. When history is
+turned off, no new lines will be added to the history list, and
+history lookup key-bindings will act as though there is nothing in the
+history buffer.
+
+.SH QUERYING HISTORY INFORMATION
+
+The configured state of the history list can be queried with the
+\f3gl_history_state()\f1 function.
+
+.sp
+.nf
+ typedef struct {
+ int enabled; /* True if history is enabled */
+ unsigned group; /* The current history group */
+ int max_lines; /* The current upper limit on the */
+ /* number of lines in the history */
+ /* list, or -1 if unlimited. */
+ } GlHistoryState;
+
+ void gl_state_of_history(GetLine *gl,
+ GlHistoryState *state);
+.fi
+.sp
+On return, the status information is recorded in the variable pointed
+to by the \f3state\f1 argument.
+.sp
+The \f3gl_range_of_history()\f1 function returns the number and
+range of lines in the history list.
+
+.sp
+.nf
+typedef struct {
+ unsigned long oldest; /* The sequential entry number */
+ /* of the oldest line in the */
+ /* history list. */
+ unsigned long newest; /* The sequential entry number */
+ /* of the newest line in the */
+ /* history list. */
+ int nlines; /* The number of lines in the */
+ /* history list. */
+} GlHistoryRange;
+
+void gl_range_of_history(GetLine *gl, GlHistoryRange *range);
+.fi
+.sp
+The return values are recorded in the variable pointed to by the
+\f3range\f1 argument. If the \f3nlines\f1 member of this structure is
+greater than zero, then the \f3oldest\f1 and \f3newest\f1 members
+report the range of lines in the list, and \f3newest=oldest+nlines-1\f1.
+Otherwise they are both zero.
+.sp
+The \f3gl_size_of_history()\f1 function returns the total size of the
+history buffer and the amount of the buffer that is currently
+occupied.
+.sp
+.nf
+ typedef struct {
+ size_t size; /* The size of the history buffer */
+ /* (bytes). */
+ size_t used; /* The number of bytes of the */
+ /* history buffer that are */
+ /* currently occupied. */
+ } GlHistorySize;
+
+ void gl_size_of_history(GetLine *gl, GlHistorySize *size);
+.fi
+.sp
+On return, the size information is recorded in the variable pointed to
+by the \f3size\f1 argument.
+
+.SH CHANGING TERMINALS
+
+The \f3new_GetLine()\f1 constructor function assumes that input is to
+be read from \f3stdin\f1, and output written to \f3stdout\f1. The
+following function allows you to switch to different input and output
+streams.
+.sp
+.nf
+ int gl_change_terminal(GetLine *gl, FILE *input_fp,
+ FILE *output_fp, const char *term);
+.fi
+.sp
+The \f3gl\f1 argument is the object that was returned by
+\f3new_GetLine()\f1. The \f3input_fp\f1 argument specifies the stream
+to read from, and \f3output_fp\f1 specifies the stream to be written
+to. Only if both of these refer to a terminal, will interactive
+terminal input be enabled. Otherwise \f3gl_get_line()\f1 will simply
+call \f3fgets()\f1 to read command input. If both streams refer to a
+terminal, then they must refer to the same terminal, and the type of
+this terminal must be specified via the \f3term\f1 argument. The value
+of the \f3term\f1 argument is looked up in the terminal information
+database (terminfo or termcap), in order to determine which special
+control sequences are needed to control various aspects of the
+terminal. \f3new_GetLine()\f1 for example, passes the return value of
+\f3getenv("TERM")\f1 in this argument. Note that if one or both of
+\f3input_fp\f1 and \f3output_fp\f1 don't refer to a terminal, then it
+is legal to pass \f3NULL\f1 instead of a terminal type.
+.sp
+Note that if you want to pass file descriptors to
+\f3gl_change_terminal()\f1, you can do this by creating stdio stream
+wrappers using the POSIX \f3fdopen()\f1 function.
+
+.SH EXTERNAL EVENT HANDLING
+
+By default, \f3gl_get_line()\f1 doesn't return until either a complete
+input line has been entered by the user, or an error occurs. In
+programs that need to watch for I/O from other sources than the
+terminal, there are two options.
+
+.sp
+.nf
+ 1. Use the functions described in the
+ \f3gl_io_mode(@FUNC_MANEXT@)\f1 man page to switch
+ \f3gl_get_line()\f1 into non-blocking server mode. In this mode,
+ \f3gl_get_line()\f1 becomes a non-blocking, incremental
+ line-editing function that can safely be called from
+ an external event loop. Although this is a very
+ versatile method, it involves taking on some
+ responsibilities that are normally performed behind
+ the scenes by \f3gl_get_line()\f1.
+
+ 2. While \f3gl_get_line()\f1 is waiting for keyboard
+ input from the user, you can ask it to also watch for
+ activity on arbitrary file descriptors, such as
+ network sockets, pipes etc, and have it call functions
+ of your choosing when activity is seen. This works on
+ any system that has the \f3select()\f1 system call,
+ which is most, if not all flavors of unix.
+.fi
+.sp
+
+Registering a file descriptor to be watched by
+\f3gl_get_line()\f1 involves calling the \f3gl_watch_fd()\f1 function.
+
+.sp
+.nf
+ int gl_watch_fd(GetLine *gl, int fd, GlFdEvent event,
+ GlFdEventFn *callback, void *data);
+.fi
+.sp
+
+If this returns non-zero, then it means that either your arguments are
+invalid, or that this facility isn't supported on the host system.
+.sp
+The \f3fd\f1 argument is the file descriptor to be watched. The
+\f3event\f1 argument specifies what type of activity is of interest,
+chosen from the following enumerated values:
+
+.sp
+.nf
+ GLFD_READ - Watch for the arrival of data to be read.
+ GLFD_WRITE - Watch for the ability to write to the file
+ descriptor without blocking.
+ GLFD_URGENT - Watch for the arrival of urgent
+ out-of-band data on the file descriptor.
+.fi
+.sp
+
+The \f3callback\f1 argument is the function to call when the selected
+activity is seen. It should be defined with the following macro, which
+is defined in libtecla.h.
+
+.sp
+.nf
+ #define GL_FD_EVENT_FN(fn) GlFdStatus (fn)(GetLine *gl, \\
+ void *data, int fd, \\
+ GlFdEvent event)
+.fi
+.sp
+The \f3data\f1 argument of the \f3gl_watch_fd()\f1 function is passed
+to the callback function for its own use, and can point to anything
+you like, including \f3NULL\f1. The file descriptor and the event
+argument are also passed to the callback function, and this
+potentially allows the same callback function to be registered to more
+than one type of event and/or more than one file descriptor. The
+return value of the callback function should be one of the following
+values.
+
+.sp
+.nf
+ GLFD_ABORT - Tell gl_get_line() to abort. When this
+ happens, \f3gl_get_line()\f1 returns
+ \f3NULL\f1, and a following call to
+ \f3gl_return_status()\f1 will return
+ \f3GLR_FDABORT\f1. Note that if the
+ application needs \f3errno\f1 always to
+ have a meaningful value when
+ \f3gl_get_line()\f1 returns \f3NULL\f1,
+ the callback function should set
+ \f3errno\f1 appropriately.
+ GLFD_REFRESH - Redraw the input line then continue
+ waiting for input. Return this if
+ your callback wrote to the terminal.
+ GLFD_CONTINUE - Continue to wait for input, without
+ redrawing the line.
+.fi
+.sp
+Note that before calling the callback, \f3gl_get_line()\f1 blocks most
+signals, and leaves its own signal handlers installed, so if you need
+to catch a particular signal you will need to both temporarily install
+your own signal handler, and unblock the signal. Be sure to re-block
+the signal (if it was originally blocked) and reinstate the original
+signal handler, if any, before returning.
+
+.sp
+
+If the callback function needs to read or write to the terminal, it
+should ideally first call \f3gl_normal_io(gl)\f1 to temporarily
+suspend line editing. This will restore the terminal to canonical,
+blocking-I/O, mode, and move the cursor to the start of a new terminal
+line. Later, when the callback returns, \f3gl_get_line()\f1 will
+notice that \f3gl_normal_io()\f1 was called, redisplay the input line
+and resume editing. Note that in this case the return values,
+\f3GLFD_REFRESH\f1 and \f3GLFD_CONTINUE\f1 are equivalent.
+
+.sp
+
+To support cases where the callback function calls a third-party
+function which occasionally and unpredictably writes to the terminal,
+the automatic conversion of \f3"\n"\f1 to \f3"\r\n"\f1 is re-enabled
+before the callback function is called. If the callack knows that the
+third-party function wrote to the terminal, it should then return the
+\f3GLFD_REFRESH\f1 return value, to tell \f3gl_get_line()\f1 to
+redisplay the input line.
+
+.sp
+
+To remove a callback function that you previously registered for a
+given file descriptor and event, simply call \f3gl_watch_fd()\f1 with
+the same file descriptor and \f3event\f1 arguments, but with a
+\f3callback\f1 argument of \f30\f1. The \f3data\f1 argument is ignored
+in this case.
+
+.SH SETTING AN INACTIVITY TIMEOUT
+
+On systems with the \f3select()\f1 system call, the
+\f3gl_inactivity_timeout()\f1 function can be used to set or cancel an
+inactivity timeout. Inactivity in this case refers both to keyboard
+input, and to I/O on any file descriptors registered by prior and
+subsequent calls to \f3gl_watch_fd()\f1. On oddball systems that don't
+have \f3select()\f1, this call has no effect.
+
+.sp
+.nf
+ int gl_inactivity_timeout(GetLine *gl, GlTimeoutFn *callback,
+ void *data, unsigned long sec,
+ unsigned long nsec);
+.fi
+.sp
+
+The timeout is specified in the form of an integral number of seconds
+and an integral number of nanoseconds, via the \f3sec\f1 and
+\f3nsec\f1 arguments respectively. Subsequently, whenever no activity
+is seen for this time period, the function specified via the
+\f3callback\f1 argument is called. The \f3data\f1 argument of
+\f3gl_inactivity_timeout()\f1 is passed verbatim to this callback function
+whenever it is invoked, and can thus be used to pass arbitrary
+application-specific information to the callback. The following macro
+is provided in \f3libtecla.h\f1 for applications to use to declare and
+prototype timeout callback functions.
+
+.sp
+.nf
+ #define GL_TIMEOUT_FN(fn) \\
+ GlAfterTimeout (fn)(GetLine *gl, void *data)
+.fi
+.sp
+
+On returning, the application's callback is expected to return one of
+the following enumerators to tell \f3gl_get_line()\f1 how to procede
+after the timeout has been handled by the callback.
+
+.sp
+.nf
+ GLTO_ABORT - Tell gl_get_line() to abort. When
+ this happens, \f3gl_get_line()\f1 will
+ return \f3NULL\f1, and a following call
+ to \f3gl_return_status()\f1 will return
+ \f3GLR_TIMEOUT\f1. Note that if the
+ application needs \f3errno\f1 always to
+ have a meaningful value when
+ \f3gl_get_line()\f1 returns \f3NULL\f1,
+ the callback function should set
+ \f3errno\f1 appropriately.
+ GLTO_REFRESH - Redraw the input line, then continue
+ waiting for input. You should return
+ this value if your callback wrote to the
+ terminal without having first called
+ \f3gl_normal_io(gl)\f1.
+ GLTO_CONTINUE - In normal blocking-I/O mode, continue to
+ wait for input, without redrawing the
+ user's input line.
+ In non-blocking server I/O mode (see
+ gl_io_mode(@FUNC_MANEXT@)), cause \f3gl_get_line()\f1
+ to act as though I/O blocked. This means
+ that \f3gl_get_line()\f1 will immediately
+ return \f3NULL\f1, and a following call
+ to \f3gl_return_status()\f1 will return
+ \f3GLR_BLOCKED\f1.
+.fi
+.sp
+
+Note that before calling the callback, \f3gl_get_line()\f1 blocks most
+signals, and leaves its own signal handlers installed, so if you need
+to catch a particular signal you will need to both temporarily install
+your own signal handler, and unblock the signal. Be sure to re-block
+the signal (if it was originally blocked) and reinstate the original
+signal handler, if any, before returning.
+
+.sp
+
+If the callback function needs to read or write to the terminal, it
+should ideally first call \f3gl_normal_io(gl)\f1 to temporarily
+suspend line editing. This will restore the terminal to canonical,
+blocking-I/O, mode, and move the cursor to the start of a new terminal
+line. Later, when the callback returns, \f3gl_get_line()\f1 will
+notice that \f3gl_normal_io()\f1 was called, redisplay the input line
+and resume editing. Note that in this case the return values,
+\f3GLTO_REFRESH\f1 and \f3GLTO_CONTINUE\f1 are equivalent.
+
+.sp
+
+To support cases where the callback function calls a third-party
+function which occasionally and unpredictably writes to the terminal,
+the automatic conversion of \f3"\n"\f1 to \f3"\r\n"\f1 is re-enabled
+before the callback function is called. If the callack knows that the
+third-party function wrote to the terminal, it should then return the
+\f3GLTO_REFRESH\f1 return value, to tell \f3gl_get_line()\f1 to
+redisplay the input line.
+
+.sp
+
+Note that although the timeout argument includes a nano-second
+component, few computer clocks presently have resolutions that are
+finer than a few milliseconds, so asking for less than a few
+milliseconds is equivalent to requesting zero seconds on a lot of
+systems. If this would be a problem, you should base your timeout
+selection on the actual resolution of the host clock (eg. by calling
+\f3sysconf(_SC_CLK_TCK)\f1).
+
+.sp
+
+To turn off timeouts, simply call \f3gl_inactivity_timeout()\f1 with a
+\f3callback\f1 argument of \f30\f1. The \f3data\f1 argument is ignored
+in this case.
+
+.SH SIGNAL HANDLING DEFAULTS
+
+By default, the \f3gl_get_line()\f1 function intercepts a
+number of signals. This is particularly important for
+signals which would by default terminate the process, since
+the terminal needs to be restored to a usable state before
+this happens. In this section, the signals that are trapped
+by default, and how \f3gl_get_line()\f1 responds to them, is
+described. Changing these defaults is the topic of the
+following section.
+.sp
+When the following subset of signals are caught, \f3gl_get_line()\f1
+first restores the terminal settings and signal handling to how they
+were before \f3gl_get_line()\f1 was called, resends the signal, to
+allow the calling application's signal handlers to handle it, then if
+the process still exists, \f3gl_get_line()\f1 returns \f3NULL\f1 and
+sets \f3errno\f1 as specified below.
+
+.sp
+.nf
+ SIGINT - This signal is generated both by the keyboard
+ interrupt key (usually ^C), and the keyboard
+ break key.
+
+ errno=EINTR
+
+ SIGHUP - This signal is generated when the controlling
+ terminal exits.
+
+ errno=ENOTTY
+
+ SIGPIPE - This signal is generated when a program attempts
+ to write to a pipe who's remote end isn't being
+ read by any process. This can happen for example
+ if you have called \f3gl_change_terminal()\f1 to
+ redirect output to a pipe hidden under a pseudo
+ terminal.
+
+ errno=EPIPE
+
+ SIGQUIT - This signal is generated by the keyboard quit
+ key (usually ^\\).
+
+ errno=EINTR
+
+ SIGABRT - This signal is generated by the standard C,
+ abort() function. By default it both
+ terminates the process and generates a core
+ dump.
+
+ errno=EINTR
+
+ SIGTERM - This is the default signal that the UN*X
+ kill command sends to processes.
+
+ errno=EINTR
+.fi
+.sp
+Note that in the case of all of the above signals, POSIX mandates that
+by default the process is terminated, with the addition of a core dump
+in the case of the \f3SIGQUIT\f1 signal. In other words, if the
+calling application doesn't override the default handler by supplying
+its own signal handler, receipt of the corresponding signal will
+terminate the application before \f3gl_get_line()\f1 returns.
+.sp
+If gl_get_line() aborts with errno set to EINTR, you can find out what
+signal caused it to abort, by calling the following function.
+.sp
+.nf
+ int gl_last_signal(const GetLine *gl);
+.fi
+.sp
+This returns the numeric code (eg. \f3SIGINT\f1) of the last signal
+that was received during the most recent call to \f3gl_get_line()\f1,
+or \f3-1\f1 if no signals were received.
+.sp
+On systems that support it, when a SIGWINCH (window change) signal is
+received, \f3gl_get_line()\f1 queries the terminal to find out its new
+size, redraws the current input line to accomodate the new size, then
+returns to waiting for keyboard input from the user. Unlike other
+signals, this signal isn't resent to the application.
+.sp
+Finally, the following signals cause \f3gl_get_line()\f1 to first
+restore the terminal and signal environment to that which prevailed
+before \f3gl_get_line()\f1 was called, then resend the signal to the
+application. If the process still exists after the signal has been
+delivered, then \f3gl_get_line()\f1 then re-establishes its own signal
+handlers, switches the terminal back to raw mode, redisplays the input
+line, and goes back to awaiting terminal input from the user.
+.sp
+.nf
+ SIGCONT - This signal is generated when a suspended
+ process is resumed.
+
+ SIGPOLL - On SVR4 systems, this signal notifies the
+ process of an asynchronous I/O event. Note
+ that under 4.3+BSD, SIGIO and SIGPOLL are
+ the same. On other systems, SIGIO is ignored
+ by default, so \f3gl_get_line()\f1 doesn't
+ trap it by default.
+
+ SIGPWR - This signal is generated when a power failure
+ occurs (presumably when the system is on a
+ UPS).
+
+ SIGALRM - This signal is generated when a timer
+ expires.
+
+ SIGUSR1 - An application specific signal.
+
+ SIGUSR2 - Another application specific signal.
+
+ SIGVTALRM - This signal is generated when a virtual
+ timer expires (see man setitimer(2)).
+
+ SIGXCPU - This signal is generated when a process
+ exceeds its soft CPU time limit.
+
+ SIGXFSZ - This signal is generated when a process
+ exceeds its soft file-size limit.
+
+ SIGTSTP - This signal is generated by the terminal
+ suspend key, which is usually ^Z, or the
+ delayed terminal suspend key, which is
+ usually ^Y.
+
+ SIGTTIN - This signal is generated if the program
+ attempts to read from the terminal while the
+ program is running in the background.
+
+ SIGTTOU - This signal is generated if the program
+ attempts to write to the terminal while the
+ program is running in the background.
+.fi
+.sp
+
+Obviously not all of the above signals are supported on all systems,
+so code to support them is conditionally compiled into the tecla
+library.
+.sp
+Note that if \f3SIGKILL\f1 or \f3SIGPOLL\f1, which by definition can't
+be caught, or any of the hardware generated exception signals, such as
+\f3SIGSEGV\f1, \f3SIGBUS\f1 and \f3SIGFPE\f1, are received and
+unhandled while \f3gl_get_line()\f1 has the terminal in raw mode, the
+program will be terminated without the terminal having been restored
+to a usable state. In practice, job-control shells usually reset the
+terminal settings when a process relinquishes the controlling
+terminal, so this is only a problem with older shells.
+
+.SH CUSTOMIZED SIGNAL HANDLING
+
+The previous section listed the signals that
+\f3gl_get_line()\f1 traps by default, and described how it
+responds to them. This section describes how to both add and
+remove signals from the list of trapped signals, and how to
+specify how \f3gl_get_line()\f1 should respond to a given
+signal.
+.sp
+If you don't need \f3gl_get_line()\f1 to do anything in
+response to a signal that it normally traps, you can tell to
+\f3gl_get_line()\f1 to ignore that signal by calling
+\f3gl_ignore_signal()\f1.
+.sp
+.nf
+ int gl_ignore_signal(GetLine *gl, int signo);
+.fi
+.sp
+The \f3signo\f1 argument is the number of the signal
+(eg. \f3SIGINT\f1) that you want to have ignored. If the
+specified signal isn't currently one of those being trapped,
+this function does nothing.
+.sp
+The \f3gl_trap_signal()\f1 function allows you to either add
+a new signal to the list that \f3gl_get_line()\f1 traps, or
+modify how it responds to a signal that it already traps.
+.sp
+.nf
+ int gl_trap_signal(GetLine *gl, int signo, unsigned flags,
+ GlAfterSignal after, int errno_value);
+.fi
+.sp
+The \f3signo\f1 argument is the number of the signal that
+you wish to have trapped. The \f3flags\f1 argument is a set
+of flags which determine the environment in which the
+application's signal handler is invoked, the \f3after\f1
+argument tells \f3gl_get_line()\f1 what to do after the
+application's signal handler returns, and \f3errno_value\f1
+tells \f3gl_get_line()\f1 what to set \f3errno\f1 to if told
+to abort.
+.sp
+The \f3flags\f1 argument is a bitwise OR of zero or more of
+the following enumerators:
+.sp
+.nf
+ GLS_RESTORE_SIG - Restore the caller's signal
+ environment while handling the
+ signal.
+
+ GLS_RESTORE_TTY - Restore the caller's terminal settings
+ while handling the signal.
+
+ GLS_RESTORE_LINE - Move the cursor to the start of the
+ line following the input line before
+ invoking the application's signal
+ handler.
+
+ GLS_REDRAW_LINE - Redraw the input line when the
+ application's signal handler returns.
+
+ GLS_UNBLOCK_SIG - Normally, if the calling program has
+ a signal blocked (man sigprocmask),
+ gl_get_line() does not trap that
+ signal. This flag tells gl_get_line()
+ to trap the signal and unblock it for
+ the duration of the call to
+ gl_get_line().
+
+ GLS_DONT_FORWARD - If this flag is included, the signal
+ will not be forwarded to the signal
+ handler of the calling program.
+.fi
+.sp
+Two commonly useful flag combinations are also enumerated as
+follows:
+.sp
+.nf
+ GLS_RESTORE_ENV = GLS_RESTORE_SIG | GLS_RESTORE_TTY |
+ GLS_REDRAW_LINE
+
+ GLS_SUSPEND_INPUT = GLS_RESTORE_ENV | GLS_RESTORE_LINE
+.fi
+.sp
+
+If your signal handler, or the default system signal
+handler for this signal, if you haven't overridden it, never
+either writes to the terminal, nor suspends or terminates
+the calling program, then you can safely set the \f3flags\f1
+argument to \f30\f1.
+.sp
+If your signal handler always writes to the terminal, reads
+from it, or suspends or terminates the program, you should
+specify the \f3flags\f1 argument as \f3GL_SUSPEND_INPUT\f1,
+so that:
+.sp
+.nf
+1. The cursor doesn't get left in the middle of the input
+ line.
+2. So that the user can type in input and have it echoed.
+3. So that you don't need to end each output line with
+ \f3\\r\\n\f1, instead of just \f3\\n\f1.
+.fi
+.sp
+The \f3GL_RESTORE_ENV\f1 combination is the same as
+\f3GL_SUSPEND_INPUT\f1, except that it doesn't move the
+cursor, and if your signal handler doesn't read or write
+anything to the terminal, the user won't see any visible
+indication that a signal was caught. This can be useful if
+you have a signal handler that only occasionally writes to
+the terminal, where using \f3GL_SUSPEND_LINE\f1 would cause
+the input line to be unnecessarily duplicated when nothing
+had been written to the terminal. Such a signal handler,
+when it does write to the terminal, should be sure to start
+a new line at the start of its first write, by writing a
+'\\n' character, and should be sure to leave the cursor on a
+new line before returning. If the signal arrives while the
+user is entering a line that only occupies a signal terminal
+line, or if the cursor is on the last terminal line of a
+longer input line, this will have the same effect as
+\f3GL_SUSPEND_INPUT\f1. Otherwise it will start writing on a
+line that already contains part of the displayed input line.
+This doesn't do any harm, but it looks a bit ugly, which is
+why the \f3GL_SUSPEND_INPUT\f1 combination is better if you
+know that you are always going to be writting to the
+terminal.
+.sp
+The \f3after\f1 argument, which determines what
+\f3gl_get_line()\f1 does after the application's signal
+handler returns (if it returns), can take any one of the
+following values:
+.sp
+.nf
+ GLS_RETURN - Return the completed input line, just as
+ though the user had pressed the return
+ key.
+
+ GLS_ABORT - Cause \f3gl_get_line()\f1 to abort. When
+ this happens, \f3gl_get_line()\f1 returns
+ \f3NULL\f1, and a following call to
+ \f3gl_return_status()\f1 will return
+ \f3GLR_SIGNAL\f1. Note that if the
+ application needs \f3errno\f1 always to
+ have a meaningful value when
+ \f3gl_get_line()\f1 returns \f3NULL\f1,
+ the callback function should set
+ \f3errno\f1 appropriately.
+ GLS_CONTINUE - Resume command line editing.
+.fi
+.sp
+The \f3errno_value\f1 argument is intended to be combined
+with the \f3GLS_ABORT\f1 option, telling \f3gl_get_line()\f1
+what to set the standard \f3errno\f1 variable to before
+returning \f3NULL\f1 to the calling program. It can also,
+however, be used with the \f3GL_RETURN\f1 option, in case
+you wish to have a way to distinguish between an input line
+that was entered using the return key, and one that was
+entered by the receipt of a signal.
+
+.SH RELIABLE SIGNAL HANDLING
+
+Signal handling is suprisingly hard to do reliably without race
+conditions. In \f3gl_get_line()\f1 a lot of care has been taken to
+allow applications to perform reliable signal handling around
+\f3gl_get_line()\f1. This section explains how to make use of this.
+
+As an example of the problems that can arise if the application isn't
+written correctly, imagine that one's application has a SIGINT signal
+handler that sets a global flag. Now suppose that the application
+tests this flag just before invoking \f3gl_get_line()\f1. If a SIGINT
+signal happens to be received in the small window of time between the
+statement that tests the value of this flag, and the statement that
+calls \f3gl_get_line()\f1, then \f3gl_get_line()\f1 will not see the
+signal, and will not be interrupted. As a result, the application
+won't be able to respond to the signal until the user gets around to
+finishing entering the input line and \f3gl_get_line()\f1
+returns. Depending on the application, this might or might not be a
+disaster, but at the very least it would puzzle the user.
+
+The way to avoid such problems is to do the following.
+
+1. If needed, use the \f3gl_trap_signal()\f1 function to
+ configure \f3gl_get_line()\f1 to abort when important
+ signals are caught.
+
+2. Configure \f3gl_get_line()\f1 such that if any of the
+ signals that it catches are blocked when
+ \f3gl_get_line()\f1 is called, they will be unblocked
+ automatically during times when \f3gl_get_line()\f1 is
+ waiting for I/O. This can be done either
+ on a per signal basis, by calling the
+ \f3gl_trap_signal()\f1 function, and specifying the
+ \f3GLS_UNBLOCK\f1 attribute of the signal, or globally by
+ calling the \f3gl_catch_blocked()\f1 function.
+
+.sp
+.nf
+ void gl_catch_blocked(GetLine *gl);
+.fi
+.sp
+
+ This function simply adds the \f3GLS_UNBLOCK\f1 attribute
+ to all of the signals that it is currently configured to
+ trap.
+
+3. Just before calling \f3gl_get_line()\f1, block delivery
+ of all of the signals that \f3gl_get_line()\f1 is
+ configured to trap. This can be done using the POSIX
+ \f3sigprocmask()\f1 function in conjunction with the
+ \f3gl_list_signals()\f1 function.
+
+.sp
+.nf
+ int gl_list_signals(GetLine *gl, sigset_t *set);
+.fi
+.sp
+
+ This function returns the set of signals that it is
+ currently configured to catch in the \f3set\f1 argument,
+ which is in the form required by \f3sigprocmask()\f1.
+
+4. In the example, one would now test the global flag that
+ the signal handler sets, knowing that there is now no
+ danger of this flag being set again until
+ \f3gl_get_line()\f1 unblocks its signals while performing
+ I/O.
+
+5. Eventually \f3gl_get_line()\f1 returns, either because
+ a signal was caught, an error occurred, or the user
+ finished entering their input line.
+
+6. Now one would check the global signal flag again, and if
+ it is set, respond to it, and zero the flag.
+
+7. Use \f3sigprocmask()\f1 to unblock the signals that were
+ blocked in step 3.
+
+The same technique can be used around certain POSIX
+signal-aware functions, such as \f3sigsetjmp()\f1 and
+\f3sigsuspend()\f1, and in particular, the former of these
+two functions can be used in conjunction with
+\f3siglongjmp()\f1 to implement race-condition free signal
+handling around other long-running system calls. The way to
+do this, is explained next, by showing how
+\f3gl_get_line()\f1 manages to reliably trap signals around
+calls to functions like \f3read()\f1 and \f3select()\f1
+without race conditions.
+
+The first thing that \f3gl_get_line()\f1 does, whenever it
+is called, is to use the POSIX \f3sigprocmask()\f1 function
+to block the delivery of all of the signals that it is
+currently configured to catch. This is redundant if the
+application has already blocked them, but it does no
+harm. It undoes this step just before returning.
+
+Whenever \f3gl_get_line()\f1 needs to call \f3read()\f1 or
+\f3select()\f1 to wait for input from the user, it first
+calls the POSIX \f3sigsetjmp()\f1 function, being sure to
+specify a non-zero value for its \f3savesigs\f1 argument.
+The reason for the latter argument will become clear
+shortly.
+
+If \f3sigsetjmp()\f1 returns zero, \f3gl_get_line()\f1 then
+does the following.
+
+.sp
+.nf
+a. It uses the POSIX \f3sigaction()\f1 function to register
+ a temporary signal handler to all of the signals that it
+ is configured to catch. This signal handler does two
+ things.
+
+ 1. It records the number of the signal that was received
+ in a file-scope variable.
+
+ 2. It then calls the POSIX \f3siglongjmp()\f1
+ function using the buffer that was passed to
+ \f3sigsetjmp()\f1 for its first argument, and
+ a non-zero value for its second argument.
+
+ When this signal handler is registered, the \f3sa_mask\f1
+ member of the \f3struct sigaction act\f1 argument of the
+ call to \f3sigaction()\f1 is configured to contain all of
+ the signals that \f3gl_get_line()\f1 is catching. This
+ ensures that only one signal will be caught at once by
+ our signal handler, which in turn ensures that multiple
+ instances of our signal handler don't tread on each
+ other's toes.
+
+b. Now that the signal handler has been set up,
+ \f3gl_get_line()\f1 unblocks all of the signals that it
+ is configured to catch.
+
+c. It then calls the \f3read()\f1 or \f3select()\f1 system
+ calls to wait for keyboard input.
+
+d. If this system call returns (ie. no signal is received),
+ \f3gl_get_line()\f1 blocks delivery of the signals of
+ interest again.
+
+e. It then reinstates the signal handlers that were
+ displaced by the one that was just installed.
+.fi
+.sp
+
+Alternatively, if \f3sigsetjmp()\f1 returns non-zero, this
+means that one of the signals being trapped was caught while
+the above steps were executing. When this happens,
+\f3gl_get_line()\f1 does the following.
+
+First, note that when a call to \f3siglongjmp()\f1 causes
+\f3sigsetjmp()\f1 to return, provided that the
+\f3savesigs\f1 argument of \f3sigsetjmp()\f1 was non-zero,
+as specified above, the signal process mask is restored to
+how it was when \f3sigsetjmp()\f1 was called. This is the
+important difference between \f3sigsetjmp()\f1 and the older
+problematic \f3setjmp()\f1, and is the essential ingredient
+that makes it possible to avoid signal handling race
+conditions. Because of this we are guaranteed that all of
+the signals that we blocked before calling \f3sigsetjmp()\f1
+are blocked again as soon as any signal is caught. The
+following statements, which are then executed, are thus
+guaranteed to be executed without any further signals being
+caught.
+
+1. If so instructed by the \f3gl_get_line()\f1 configuration
+ attributes of the signal that was caught,
+ \f3gl_get_line()\f1 restores the terminal attributes to
+ the state that they had when \f3gl_get_line()\f1 was
+ called. This is particularly important for signals that
+ suspend or terminate the process, since otherwise the
+ terminal would be left in an unusable state.
+
+2. It then reinstates the application's signal handlers.
+
+3. Then it uses the C standard-library \f3raise()\f1
+ function to re-send the application the signal that
+ was caught.
+
+3. Next it unblocks delivery of the signal that we just
+ sent. This results in the signal that was just sent
+ via \f3raise()\f1, being caught by the application's
+ original signal handler, which can now handle it as it
+ sees fit.
+
+4. If the signal handler returns (ie. it doesn't terminate
+ the process), \f3gl_get_line()\f1 blocks delivery of the
+ above signal again.
+
+5. It then undoes any actions performed in the first of the
+ above steps, and redisplays the line, if the signal
+ configuration calls for this.
+
+6. \f3gl_get_line()\f1 then either resumes trying to
+ read a character, or aborts, depending on the
+ configuration of the signal that was caught.
+
+What the above steps do in essence is to take asynchronously
+delivered signals and handle them synchronously, one at a
+time, at a point in the code where \f3gl_get_line()\f1 has
+complete control over its environment.
+
+.SH THE TERMINAL SIZE
+
+On most systems the combination of the \f3TIOCGWINSZ\f1 ioctl and the
+\f3SIGWINCH\f1 signal is used to maintain an accurate idea of the
+terminal size. The terminal size is newly queried every time that
+\f3gl_get_line()\f1 is called and whenever a \f3SIGWINCH\f1 signal is
+received.
+.sp
+On the few systems where this mechanism isn't available, at
+startup \f3new_GetLine()\f1 first looks for the \f3LINES\f1
+and \f3COLUMNS\f1 environment variables. If these aren't
+found, or they contain unusable values, then if a terminal
+information database like terminfo or termcap is available,
+the default size of the terminal is looked up in this
+database. If this too fails to provide the terminal size, a
+default size of 80 columns by 24 lines is used.
+.sp
+Even on systems that do support \f3ioctl(TIOCGWINSZ)\f1, if the
+terminal is on the other end of a serial line, the terminal driver
+generally has no way of detecting when a resize occurs or of querying
+what the current size is. In such cases no \f3SIGWINCH\f1 is sent to
+the process, and the dimensions returned by \f3ioctl(TIOCGWINSZ)\f1
+aren't correct. The only way to handle such instances is to provide a
+way for the user to enter a command that tells the remote system what
+the new size is. This command would then call the
+\f3gl_set_term_size()\f1 function to tell \f3gl_get_line()\f1 about
+the change in size.
+
+.sp
+.nf
+ int gl_set_term_size(GetLine *gl, int ncolumn, int nline);
+.fi
+.sp
+
+The \f3ncolumn\f1 and \f3nline\f1 arguments are used to specify the
+new dimensions of the terminal, and must not be less than 1. On
+systems that do support \f3ioctl(TIOCGWINSZ)\f1, this function first
+calls \f3ioctl(TIOCSWINSZ)\f1 to tell the terminal driver about the
+change in size. In non-blocking server-I/O mode, if a line is
+currently being input, the input line is then redrawn to accomodate
+the changed size. Finally the new values are recorded in \f3gl\f1 for
+future use by \f3gl_get_line()\f1.
+.sp
+The \f3gl_terminal_size()\f1 function allows you to query
+the current size of the terminal, and install an alternate
+fallback size for cases where the size isn't available.
+Beware that the terminal size won't be available if reading
+from a pipe or a file, so the default values can be
+important even on systems that do support ways of finding
+out the terminal size.
+.sp
+.nf
+ typedef struct {
+ int nline; /* The terminal has nline lines */
+ int ncolumn; /* The terminal has ncolumn columns */
+ } GlTerminalSize;
+
+ GlTerminalSize gl_terminal_size(GetLine *gl,
+ int def_ncolumn,
+ int def_nline);
+.fi
+.sp
+This function first updates \f3gl_get_line()\f1's fallback terminal
+dimensions, then records its findings in the return value.
+.sp
+The \f3def_ncolumn\f1 and \f3def_nline\f1 specify the
+default number of terminal columns and lines to use if the
+terminal size can't be determined via \f3ioctl(TIOCGWINSZ)\f1 or
+environment variables.
+
+.SH HIDING WHAT YOU TYPE
+
+When entering sensitive information, such as passwords, it is best not
+to have the text that you are entering echoed on the terminal.
+Furthermore, such text should not be recorded in the history list,
+since somebody finding your terminal unattended could then recall it,
+or somebody snooping through your directories could see it in your
+history file. With this in mind, the \f3gl_echo_mode()\f1
+function allows you to toggle on and off the display and archival of
+any text that is subsequently entered in calls to \f3gl_get_line()\f1.
+
+.sp
+.nf
+ int gl_echo_mode(GetLine *gl, int enable);
+.fi
+.sp
+
+The \f3enable\f1 argument specifies whether entered text
+should be visible or not. If it is \f30\f1, then
+subsequently entered lines will not be visible on the
+terminal, and will not be recorded in the history list. If
+it is \f31\f1, then subsequent input lines will be displayed
+as they are entered, and provided that history hasn't been
+turned off via a call to \f3gl_toggle_history()\f1, then
+they will also be archived in the history list. Finally, if
+the \f3enable\f1 argument is \f3-1\f1, then the echoing mode
+is left unchanged, which allows you to non-destructively
+query the current setting via the return value. In all
+cases, the return value of the function is \f30\f1 if
+echoing was disabled before the function was called, and
+\f31\f1 if it was enabled.
+.sp
+When echoing is turned off, note that although tab
+completion will invisibly complete your prefix as far as
+possible, ambiguous completions will not be displayed.
+
+.SH SINGLE CHARACTER QUERIES
+
+Using \f3gl_get_line()\f1 to query the user for a single character
+reply, is inconvenient for the user, since they must hit the enter or
+return key before the character that they typed is returned to the
+program. Thus the \f3gl_query_char()\f1 function has been provided for
+single character queries like this.
+
+.sp
+.nf
+ int gl_query_char(GetLine *gl, const char *prompt,
+ char defchar);
+.fi
+.sp
+
+This function displays the specified prompt at the start of a new
+line, and waits for the user to type a character. When the user types
+a character, \f3gl_query_char()\f1 displays it to the right of the
+prompt, starts a newline, then returns the character to the calling
+program. The return value of the function is the character that was
+typed. If the read had to be aborted for some reason, \f3EOF\f1 is
+returned instead. In the latter case, the application can call the
+previously documented \f3gl_return_status()\f1, to find out what went
+wrong. This could, for example, have been the reception of a signal,
+or the optional inactivity timer going off.
+
+If the user simply hits enter, the value of the \f3defchar\f1 argument
+is substituted. This means that when the user hits either newline or
+return, the character specified in \f3defchar\f1, is displayed after
+the prompt, as though the user had typed it, as well as being returned
+to the calling application. If such a replacement is not important,
+simply pass \f3'\n'\f1 as the value of \f3defchar\f1.
+
+If the entered character is an unprintable character, it is displayed
+symbolically. For example, control-A is displayed as ^A, and
+characters beyond 127 are displayed in octal, preceded by a
+backslash.
+
+As with \f3gl_get_line()\f1, echoing of the entered character can be
+disabled using the \f3gl_echo_mode()\f1 function.
+
+If the calling process is suspended while waiting for the user to type
+their response, the cursor is moved to the line following the prompt
+line, then when the process resumes, the prompt is redisplayed, and
+\f3gl_query_char()\f1 resumes waiting for the user to type a
+character.
+
+Note that in non-blocking server mode, (see
+gl_io_mode(@FUNC_MANEXT@)), if an incomplete input line is in the
+process of being read when \f3gl_query_char()\f1 is called, the
+partial input line is discarded, and erased from the terminal, before
+the new prompt is displayed. The next call to \f3gl_get_line()\f1 will
+thus start editing a new line.
+
+.SH READING RAW CHARACTERS
+
+Whereas the \f3gl_query_char()\f1 function visibly prompts the user
+for a character, and displays what they typed, the
+\f3gl_read_char()\f1 function reads a signal character from the user,
+without writing anything to the terminal, or perturbing any
+incompletely entered input line. This means that it can be called not
+only from between calls to \f3gl_get_line()\f1, but also from callback
+functions that the application has registered to be called by
+\f3gl_get_line()\f1.
+
+.sp
+.nf
+ int gl_read_char(GetLine *gl);
+.fi
+.sp
+
+On success, the return value of \f3gl_read_char()\f1 is the character
+that was read. On failure, \f3EOF\f1 is returned, and the
+\f3gl_return_status()\f1 function can be called to find out what went
+wrong. Possibilities include the optional inactivity timer going off,
+the receipt of a signal that is configured to abort gl_get_line(), or
+terminal I/O blocking, when in non-blocking server-I/O mode.
+
+Beware that certain keyboard keys, such as function keys, and cursor
+keys, usually generate at least 3 characters each, so a single call to
+\f3gl_read_char()\f1 won't be enough to identify such keystrokes.
+
+.SH CLEARING THE TERMINAL
+
+The calling program can clear the terminal by calling
+\f3gl_erase_terminal()\f1. In non-blocking server-I/O mode, this
+function also arranges for the current input line to be redrawn from
+scratch when \f3gl_get_line()\f1 is next called.
+
+.sp
+.nf
+ int gl_erase_terminal(GetLine *gl);
+.fi
+.sp
+
+.SH DISPLAYING TEXT DYNAMICALLY
+
+Between calls to \f3gl_get_line()\f1, the \f3gl_display_text()\f1
+function provides a convenient way to display paragraphs of text,
+left-justified and split over one or more terminal lines according to
+the constraints of the current width of the terminal. Examples of the
+use of this function may be found in the demo programs, where it is
+used to display introductions. In those examples the advanced use of
+optional prefixes, suffixes and filled lines to draw a box around the
+text is also illustrated.
+
+.sp
+.nf
+ int gl_display_text(GetLine *gl, int indentation,
+ const char *prefix,
+ const char *suffix, int fill_char,
+ int def_width, int start,
+ const char *string);
+.fi
+.sp
+If \f3gl\f1 isn't currently connected to a terminal, for example if
+the output of a program that uses \f3gl_get_line()\f1 is being piped
+to another program or redirected to a file, then the value of the
+\f3def_width\f1 parameter is used as the terminal width.
+
+The \f3indentation\f1 argument specifies the number of characters to
+use to indent each line of ouput. The \f3fill_char\f1 argument
+specifies the character that will be used to perform this indentation.
+
+The \f3prefix\f1 argument can either be \f3NULL\f1, or be a string to
+place at the beginning of each new line (after any indentation).
+Similarly, the \f3suffix\f1 argument can either be \f3NULL\f1, or be a
+string to place at the end of each line. The suffix is placed flush
+against the right edge of the terminal, and any space between its
+first character and the last word on that line is filled with the
+character specified via the \f3fill_char\f1 argument. Normally the
+fill-character is a space.
+
+The \f3start\f1 argument tells \f3gl_display_text()\f1 how many
+characters have already been written to the current terminal line, and
+thus tells it the starting column index of the cursor. Since the
+return value of \f3gl_display_text()\f1 is the ending column index of
+the cursor, by passing the return value of one call to the \f3start\f1
+argument of the next call, a paragraph that is broken between more
+than one string can be composed by calling \f3gl_display_text()\f1 for
+each successive portion of the paragraph. Note that literal newline
+characters are necessary at the end of each paragraph to force a new
+line to be started.
+
+On error, \f3gl_display_text()\f1 returns -1.
+
+.SH CALLBACK FUNCTION FACILITIES
+
+Unless otherwise stated, callback functions, such as tab
+completion callbacks and event callbacks should not call any
+functions in this module. The following functions, however,
+are designed specifically to be used by callback functions.
+.sp
+Calling the \f3gl_replace_prompt()\f1 function from a
+callback tells \f3gl_get_line()\f1 to display a different
+prompt when the callback returns. Except in non-blocking
+server mode, it has no effect if used between calls to
+\f3gl_get_line()\f1. In non-blocking server mode (see the
+\f3gl_io_mode(@FUNC_MANEXT@)\f1 man page, when used between two calls to
+\f3gl_get_line()\f1 that are operating on the same input
+line, the current input line will be re-drawn with the new
+prompt on the following call to \f3gl_get_line()\f1.
+
+.sp
+.nf
+ void gl_replace_prompt(GetLine *gl, const char *prompt);
+.fi
+.sp
+
+.SH INTERNATIONAL CHARACTER SETS
+
+Since libtecla version 1.4.0, \f3gl_get_line()\f1 has been 8-bit
+clean. This means that all 8-bit characters that are printable in the
+user's current locale are now displayed verbatim and included in the
+returned input line. Assuming that the calling program correctly
+contains a call like the following,
+.sp
+.nf
+ setlocale(LC_CTYPE, "");
+.fi
+.sp
+then the current locale is determined by the first of the environment
+variables \f3LC_CTYPE\f1, \f3LC_ALL\f1, and \f3LANG\f1, that is found
+to contain a valid locale name. If none of these variables are
+defined, or the program neglects to call setlocale, then the default
+\f3C\f1 locale is used, which is US 7-bit ASCII. On most unix-like
+platforms, you can get a list of valid locales by typing the command:
+.sp
+.nf
+ locale -a
+.fi
+.sp
+at the shell prompt. Further documentation on how the user can make use
+of this to enter international characters can be found in the
+\f3tecla(@MISC_MANEXT@)\f1 man page.
+
+.SH THREAD SAFETY
+
+In a multi-threaded program, you should use the libtecla_r.a version
+of the library. This uses reentrant versions of system functions,
+where available. Unfortunately neither terminfo nor termcap were
+designed to be reentrant, so you can't safely use the functions of the
+getline module in multiple threads (you can use the separate
+file-expansion and word-completion modules in multiple threads, see
+the corresponding man pages for details). However due to the use of
+POSIX reentrant functions for looking up home directories etc, it is
+safe to use this module from a single thread of a multi-threaded
+program, provided that your other threads don't use any termcap or
+terminfo functions.
+
+.SH FILES
+.nf
+libtecla.a - The tecla library
+libtecla.h - The tecla header file.
+~/.teclarc - The personal tecla customization file.
+.fi
+
+.SH SEE ALSO
+.nf
+libtecla(@LIBR_MANEXT@), gl_io_mode(@FUNC_MANEXT@), tecla(@MISC_MANEXT@), ef_expand_file(@FUNC_MANEXT@),
+cpl_complete_word(@FUNC_MANEXT@), pca_lookup_file(@FUNC_MANEXT@)
+.fi
+
+.SH AUTHOR
+Martin Shepherd (mcs@astro.caltech.edu)
diff --git a/libtecla-1.6.1/man/func/gl_group_history.in b/libtecla-1.6.1/man/func/gl_group_history.in
new file mode 100644
index 0000000..6e46fc6
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_group_history.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_get_line.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/gl_handle_signal.in b/libtecla-1.6.1/man/func/gl_handle_signal.in
new file mode 100644
index 0000000..24798bc
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_handle_signal.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_io_mode.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/gl_ignore_signal.in b/libtecla-1.6.1/man/func/gl_ignore_signal.in
new file mode 100644
index 0000000..6e46fc6
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_ignore_signal.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_get_line.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/gl_inactivity_timeout.in b/libtecla-1.6.1/man/func/gl_inactivity_timeout.in
new file mode 100644
index 0000000..6e46fc6
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_inactivity_timeout.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_get_line.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/gl_io_mode.in b/libtecla-1.6.1/man/func/gl_io_mode.in
new file mode 100644
index 0000000..5789666
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_io_mode.in
@@ -0,0 +1,571 @@
+.\" Copyright (c) 2002, 2003, 2004 by Martin C. Shepherd
+.\"
+.\" All rights reserved.
+.\"
+.\" Permission is hereby granted, free of charge, to any person obtaining a
+.\" copy of this software and associated documentation files (the
+.\" "Software"), to deal in the Software without restriction, including
+.\" without limitation the rights to use, copy, modify, merge, publish,
+.\" distribute, and/or sell copies of the Software, and to permit persons
+.\" to whom the Software is furnished to do so, provided that the above
+.\" copyright notice(s) and this permission notice appear in all copies of
+.\" the Software and that both the above copyright notice(s) and this
+.\" permission notice appear in supporting documentation.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+.\" OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+.\" OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+.\" HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
+.\" INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
+.\" FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+.\" NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+.\" WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\" Except as contained in this notice, the name of a copyright holder
+.\" shall not be used in advertising or otherwise to promote the sale, use
+.\" or other dealings in this Software without prior written authorization
+.\" of the copyright holder.
+.TH gl_io_mode @FUNC_MANEXT@
+.SH NAME
+ gl_io_mode, gl_raw_io, gl_normal_io, gl_tty_signals, gl_abandon_line,
+ gl_handle_signal, gl_pending_io \- How to use gl_get_line() from an external event loop.
+.SH SYNOPSIS
+.nf
+#include <libtecla.h>
+
+int gl_io_mode(GetLine *gl, GlIOMode mode);
+
+int gl_raw_io(GetLine *gl);
+
+int gl_normal_io(GetLine *gl);
+
+int gl_tty_signals(void (*term_handler)(int),
+ void (*susp_handler)(int),
+ void (*cont_handler)(int),
+ void (*size_handler)(int));
+
+void gl_abandon_line(GetLine *gl);
+
+void gl_handle_signal(int signo, GetLine *gl, int ngl);
+
+GlPendingIO gl_pending_io(GetLine *gl);
+
+.fi
+
+.SH DESCRIPTION
+
+The \f3gl_get_line()\f1 function, which is documented separately in
+the \f3gl_get_line(@FUNC_MANEXT@)\f1 man page, supports two different I/O modes.
+These are selected by calling the \f3gl_io_mode()\f1 function.
+
+.sp
+.nf
+ int gl_io_mode(GetLine *gl, GlIOMode mode);
+.fi
+.sp
+
+The \f3mode\f1 argument of this function specifies the new I/O mode,
+and must be one of the following.
+
+.sp
+.nf
+ GL_NORMAL_MODE - Select the normal blocking-I/O mode.
+ In this mode \f3gl_get_line()\f1
+ doesn't return until either an error
+ occurs of the user finishes entering a
+ new line. This mode is the focus of
+ the \f3gl_get_line(@FUNC_MANEXT@)\f1 man page.
+
+ GL_SERVER_MODE - Select non-blocking server I/O mode.
+ In this mode, since non-blocking
+ terminal I/O is used, the entry of
+ each new input line typically requires
+ many calls to \f3gl_get_line()\f1 from
+ an external I/O-driven event loop.
+ This mode is the focus of this man
+ page.
+.fi
+.sp
+
+Newly created \f3GetLine\f1 objects start in normal I/O
+mode, so to switch to non-blocking server mode requires an
+initial call to \f3gl_io_mode()\f1.
+
+.SH SERVER I/O MODE
+
+In non-blocking server I/O mode, the application is required
+to have an event loop which calls \f3gl_get_line()\f1
+whenever the terminal file descriptor can do the type I/O
+that \f3gl_get_line()\f1 is waiting for. To determine which
+type of I/O \f3gl_get_line()\f1 is waiting for, the
+application calls the \f3gl_pending_io()\f1 function.
+
+.sp
+.nf
+ GlPendingIO gl_pending_io(GetLine *gl);
+.fi
+.sp
+
+The return value of this function is one of the following two
+enumerated values.
+
+.sp
+.nf
+ GLP_READ - gl_get_line() is waiting to write a
+ character to the terminal.
+
+ GLP_WRITE - gl_get_line() is waiting to read a
+ character from the keyboad.
+.fi
+.sp
+
+If the application is using either the \f3select()\f1 or \f3poll()\f1
+system calls to watch for I/O on a group of file descriptors, then it
+should call the \f3gl_pending_io()\f1 function before each call to
+these functions to see which direction of I/O it should tell them to
+watch for, and configure their arguments accordingly. In the case of
+the \f3select()\f1 system call, this means using the \f3FD_SET()\f1
+macro to add the terminal file descriptor either to the set of file
+descriptors to be watched for readability, or the set to be watched
+for writability.
+
+As in normal I/O mode, the return value of \f3gl_get_line()\f1 is
+either a pointer to a completed input line, or \f3NULL\f1. However,
+whereas in normal I/O mode a \f3NULL\f1 return value always means that
+an error occurred, in non-blocking server mode, \f3NULL\f1 is also
+returned when \f3gl_get_line()\f1 can't read or write to the terminal
+without blocking. Thus in non-blocking server mode, in order to
+determine when a \f3NULL\f1 return value signifies that an error
+occurred or not, it is necessary to call the \f3gl_return_status()\f1
+function. If this function returns the enumerated value,
+\f3GLR_BLOCKED\f1, as documented in the \f3gl_get_line(@FUNC_MANEXT@)\f1 man page,
+this means that \f3gl_get_line()\f1 is waiting for I/O, and no error
+has occurred.
+
+When \f3gl_get_line()\f1 returns \f3NULL\f1 and
+\f3gl_return_status()\f1 indicates that this is due to blocked
+terminal I/O, the application should call \f3gl_get_line()\f1 again
+when the type of I/O reported by \f3gl_pending_io()\f1 becomes
+possible. The \f3prompt\f1, \f3start_line\f1 and \f3start_pos\f1
+arguments of \f3gl_get_line()\f1 will be ignored on these calls. If
+you need to change the prompt of the line that is currently being
+edited, then you can call the \f3gl_replace_prompt()\f1 function
+(documented in the \f3gl_get_line(@FUNC_MANEXT@) man page) between calls to
+\f3gl_get_line()\f1.
+
+.SH GIVING UP THE TERMINAL
+
+A complication that is unique to non-blocking server mode is that it
+requires that the terminal be left in raw mode between calls to
+\f3gl_get_line()\f1. If this weren't the case, the external event loop
+wouldn't be able to detect individual key-presses, and the basic line
+editing implemented by the terminal driver would clash with the
+editing provided by \f3gl_get_line()\f1. What this means is that any
+time that the terminal needs to be used for other things than entering
+a new input line with \f3gl_get_line()\f1, it needs to be restored to
+a usable state. In particular, whenever the process is suspended or
+terminated, the terminal must be returned to a normal state. If this
+isn't done, then depending on the characteristics of the shell that
+was used to invoke the program, the user may end up with a hung
+terminal. To this end, the \f3gl_normal_io()\f1 function is provided
+for switching the terminal back to the state that it was in when raw
+mode was last established.
+
+.sp
+.nf
+ int gl_normal_io(GetLine *gl);
+.fi
+.sp
+
+What this function does is first flush any pending output to the
+terminal, then move the cursor to the start of the terminal line which
+follows the end of the incompletely entered input line. At this point
+it is safe to suspend or terminate the process, and it is safe for the
+application to read and write to the terminal. To resume entry of the
+input line, the application should call the \f3gl_raw_io()\f1
+function.
+
+.sp
+.nf
+ int gl_raw_io(GetLine *gl);
+.fi
+.sp
+
+This function starts a new line, redisplays the partially completed
+input line (if any), restores the cursor position within this line to
+where it was when \f3gl_normal_io()\f1 was called, then switches back
+to raw, non-blocking terminal mode ready to continue entry of the
+input line when \f3gl_get_line()\f1 is next called.
+
+Note that in non-blocking server mode, if \f3gl_get_line()\f1 is
+called after a call to \f3gl_normal_io()\f1, without an intervening
+call to \f3gl_raw_io()\f1, \f3gl_get_line()\f1 will call
+\f3gl_raw_mode()\f1 itself, and the terminal will remain in this mode
+when \f3gl_get_line()\f1 returns.
+
+.SH SIGNAL HANDLING
+
+In the previous section it was pointed out that in non-blocking server
+mode, the terminal must be restored to a sane state whenever a signal
+is received that either suspends or terminates the process. In normal
+I/O mode, this is done for you by \f3gl_get_line()\f1, but in
+non-blocking server mode, since the terminal is left in raw mode
+between calls to \f3gl_get_line()\f1, this signal handling has to be
+done by the application. Since there are many signals that can suspend
+or terminate a process, as well as other signals that are important to
+\f3gl_get_line()\f1, such as the \f3SIGWINCH\f1 signal, which tells it
+when the terminal size has changed, the \f3gl_tty_signals()\f1
+function is provided for installing signal handlers for all pertinent
+signals.
+
+.sp
+.nf
+ int gl_tty_signals(void (*term_handler)(int),
+ void (*susp_handler)(int),
+ void (*cont_handler)(int),
+ void (*size_handler)(int));
+.fi
+.sp
+
+What this does is use \f3gl_get_line()\f1's internal list of signals
+to assign specified signal handlers to groups of signals. The
+arguments of this function are as follows.
+
+.sp
+.nf
+ term_handler - This is the signal handler that is to be
+ used to trap signals that by default
+ terminate any process that receives
+ them (eg. SIGINT or SIGTERM).
+
+ susp_handler - This is the signal handler that is to be
+ used to trap signals that by default
+ suspend any process that receives them,
+ (eg. SIGTSTP or SIGTTOU).
+
+ cont_handler - This is the signal handler that is to be
+ used to trap signals that are usually
+ sent when a process resumes after being
+ suspended (usually SIGCONT). Beware that there is
+ nothing to stop a user from sending one of these
+ signals at other times.
+
+ size_handler - This signal handler is used to trap
+ signals that are sent to processes when
+ their controlling terminals are resized
+ by the user (eg. SIGWINCH).
+.fi
+.sp
+
+These arguments can all be the same, if so desired, and you can
+specify \f3SIG_IGN\f1 (ignore this signal) or \f3SIG_DFL\f1 (use the
+system-provided default signal handler) instead of a function where
+pertinent. In particular, it is rarely useful to trap \f3SIGCONT\f1,
+so the \f3cont_handler\f1 argument will usually be \f3SIG_DFL\f1 or
+\f3SIG_IGN\f1.
+
+The \f3gl_tty_signals()\f1 function uses the POSIX \f3sigaction()\f1
+function to install these signal handlers, and it is careful to use
+the \f3sa_mask\f1 member of each sigaction structure to ensure that
+only one of these signals is ever delivered at a time. This guards
+against different instances of these signal handlers from
+simultaneously trying to write to common global data, such as a shared
+\f3sigsetjmp()\f1 buffer or a signal-received flag.
+
+The signal handlers that are installed by this function, should call
+the \f3gl_handle_signal().
+
+.sp
+.nf
+ void gl_handle_signal(int signo, GetLine *gl, int ngl);
+.fi
+.sp
+
+The \f3signo\f1 argument tells this function which signal it is being
+asked to respond to, and the \f3gl\f1 argument should be a pointer to
+the first element of an array of \f3ngl\f1 \f3GetLine\f1 objects. If
+your application only has one of these objects, just pass its pointer
+as the \f3gl\f1 argument and specify \f3ngl\f1 as \f31\f1.
+
+Depending on the signal that is being handled, this function does
+different things.
+
+.SS Terminal resize signals (SIGWINCH)
+
+If the signal indicates that the terminal was resized, then it
+arranges for the next call to \f3gl_get_line()\f1 to ask the terminal
+for its new size and redraw the input line accordingly. In order that
+\f3gl_get_line()\f1 be called as soon as possible to do this,
+\f3gl_handle_signal()\f1 also arranges that the next call to
+\f3gl_pending_io()\f1 will return \f3GLP_WRITE\f1. Thus if the
+application waits for I/O in \f3select()\f1 or \f3poll()\f1, then the
+application needs to ensure that these functions will be reliably
+aborted when a signal is caught and handled by the application. More
+on this below.
+
+.SH Process termination signals.
+
+If the signal that was caught is one of those that by default
+terminates any process that receives it, then \f3gl_handle_signal()\f1
+does the following steps.
+
+1. First it blocks the delivery of all signals that can be
+ blocked (ie. \f3SIGKILL\f1 and \f3SIGSTOP\f1 can't be blocked)
+
+2. Next it calls \f3gl_normal_io()\f1 for each of the \f3ngl\f1
+ \f3GetLine\f1 objects. Note that this does nothing to any of the
+ \f3GetLine\f1 objects that aren't currently in raw mode.
+
+3. Next it sets the signal handler of the signal to its default,
+ process-termination disposition.
+
+4. Next it re-sends the process the signal that was caught.
+
+5. Finally it unblocks delivery of this signal, which
+ results in the process being terminated.
+
+.SH Process suspension signals.
+
+If the default disposition of the signal is to suspend the process,
+the same steps are executed as for process termination signals, except
+that when the process is later resumed, \f3gl_handle_signal()\f1
+continues, and does the following steps.
+
+6. It re-blocks delivery of the signal.
+
+7. It reinstates the signal handler of the signal to the one
+ that was displaced when its default disposition was substituted.
+
+8. For any of the \f3GetLine\f1 objects that were in raw mode when
+ \f3gl_handle_signal()\f1 was called, \f3gl_handle_signal()\f1 then
+ calls \f3gl_raw_io()\f1, to resume entry of the input lines on
+ those terminals.
+
+9. Finally, it restores the signal process mask to how it
+ was when \f3gl_handle_signal()\f1 was called.
+
+Note that the process is suspended or terminated using the original
+signal that was caught, rather than using the uncatchable
+\f3SIGSTOP\f1 and \f3SIGKILL\f1 signals. This is important, because
+when a process is suspended or terminated, the parent of the process
+may wish to use the status value returned by the \f3wait()\f1 system
+call to figure out which signal was responsible. In particular, most
+shells use this information to print a corresponding message to the
+terminal. Users would be rightly confused if when their process
+received a \f3SIGPIPE\f1 signal, the program responded by sending
+itself a \f3SIGKILL\f1 signal, and the shell then printed out the
+provocative statement, "Killed!".
+
+.SH INTERRUPTING THE EVENT LOOP
+
+If a signal is caught and handled when the application's event loop is
+waiting in \f3select()\f1 or \f3poll()\f1, these functions will be
+aborted with \f3errno\f1 set to \f3EINTR\f1. When this happens the
+event loop should call \f3gl_pending_io()\f1, before calling
+\f3select()\f1 or \f3poll()\f1 again. It should then arrange for
+\f3select()\f1 or \f3poll()\f1 to wait for the type of I/O that this
+reports. This is necessary, because any signal handler which calls
+\f3gl_handle_signal()\f1, will frequently change the type of I/O that
+\f3gl_get_line()\f1 is waiting for.
+
+Unfortunately, if a signal arrives between the statements which
+configure the arguments of \f3select()\f1 or \f3poll()\f1 and the
+calls to these functions, then the signal will not be seen by these
+functions, which will then not be aborted. If these functions are
+waiting for keyboard input from the user when the signal is received,
+and the signal handler arranges to redraw the input line to accomodate
+a terminal resize or the resumption of the process, then this
+redisplay will be end up being delayed until the user hits the next
+key. Apart from puzzling the user, this clearly isn't a serious
+problem. However there is a way, albeit complicated, to completely
+avoid this race condition. The following steps illustrate this.
+
+1. Block all of the signals that \f3gl_get_line()\f1 catches,
+ by passing the signal set returned by \f3gl_list_signals()\f1 to
+ \f3sigprocmask()\f1.
+
+2. Call \f3gl_pending_io()\f1 and set up the arguments of
+ \f3select()\f1 or \f3poll()\f1 accordingly.
+
+3. Call \f3sigsetjmp()\f1 with a non-zero \f3savesigs\f1 argument.
+
+4. Initially this \f3sigsetjmp()\f1 statement will return zero,
+ indicating that control isn't resuming there after a matching
+ call to \f3siglongjmp()\f1.
+
+5. Replace all of the handlers of the signals that \f3gl_get_line()\f1
+ is configured to catch, with a signal handler that first records
+ the number of the signal that was caught, in a file-scope variable,
+ then calls \f3siglongjmp()\f1 with a non-zero value argument, to
+ return execution to the above \f3sigsetjmp()\f1
+ statement. Registering these signal handlers can conveniently be
+ done using the \f3gl_tty_signals()\f1 function.
+
+6. Set the file-scope variable that the above signal handler uses to
+ record any signal that is caught to -1, so that we can check
+ whether a signal was caught by seeing if it contains a valid signal
+ number.
+
+7. Now unblock the signals that were blocked in step 1. Any signal
+ that was received by the process in between step 1 and now will
+ now be delivered, and trigger our signal handler, as will any
+ signal that is received until we block these signals again.
+
+8. Now call \f3select()\f1 or \f3poll()\f1.
+
+9. When \f3select()\f1 returns, again block the signals that were
+ unblocked in step 7.
+
+If a signal is arrived any time during the above steps, our signal
+handler will be triggered and cause control to return to the
+\f3sigsetjmp()\f1 statement, where this time, \f3sigsetjmp()\f1 will
+return non-zero, indicating that a signal was caught. When this
+happens we simply skip the above block of statements, and continue
+with the following statements, which are executed regardless of
+whether or not a signal is caught. Note that when \f3sigsetjmp()\f1
+returns, regardless of why it returned, the process signal mask is
+returned to how it was when \f3sigsetjmp()\f1 was called. Thus the
+following statements are always executed with all of our signals
+blocked.
+
+9. Reinstate the signal handlers that were displaced in step 5.
+
+10. Check wether a signal was caught, by checking the file-scope
+ variable that the signal handler records signal numbers in.
+
+11. If a signal was caught, send this signal to the application
+ again, and unblock just this signal, so that it invokes the
+ signal handler which we just reinstated in step 10.
+
+12. Unblock all of the signals that were blocked in step 7.
+
+Since this is complicated, note that \f3demo3.c\f1 includes a working
+example of how to do this. The method used there however, is more
+general than the above. What it provides is a wrapper function around
+\f3select()\f1 which encompasses steps 3 to 11. In this wrapper,
+rather than use \f3gl_list_signals()\f1 to figure out the signals to
+block, and and \f3gl_tty_signals()\f1 to assign and revert signal
+handlers, one of its arguments is a \f3sigset_t\f1 which specifies
+which signals to block and assign signal handlers to. This function
+thus doesn't depend on \f3gl_get_line()\f1 and can thus be used in
+other situations where race-condition-free signal handling is
+required.
+
+.SH SIGNALS CAUGHT BY GL_GET_LINE
+
+Since the application is expected to handle signals in non-blocking
+server mode, \f3gl_get_line()\f1 doesn't attempt to duplicate this
+when it is being called. If one of the signals that it is configured
+to catch is sent to the application while \f3gl_get_line()\f1 is being
+called, \f3gl_get_line()\f1 reinstates the caller's signal handlers,
+then just before returning, re-sends the signal to the process to let
+the application's signal handler handle it. If the process isn't
+terminated by this signal, \f3gl_get_line()\f1 returns \f3NULL\f1, and
+a following call to \f3gl_return_status()\f1 returns the enumerated
+value \f3GLR_SIGNAL\f1.
+
+.SH ABORTING LINE INPUT
+
+Often, rather than letting it terminate the process, applications
+respond to the SIGINT user-interrupt signal by aborting the current
+input line. The way to do this in non-blocking server-I/O mode is to
+not call \f3gl_handle_signal()\f1 when this signal is caught, but
+instead to call the \f3gl_abandon_line()\f1.
+
+.sp
+.nf
+ void gl_abandon_line(GetLine *gl);
+.fi
+.sp
+
+This function arranges that when \f3gl_get_line()\f1 is next called,
+it first flushes any pending output to the terminal, then discardes
+the current input line, outputs a new prompt on the next line, and
+finally starts accepting input of a new input line from the user.
+
+.SH SIGNAL SAFE FUNCTIONS
+
+Provided that certain rules are followed, the following functions can
+have been written to be safely callable from signal handlers. Other
+functions in this library should not be called from signal handlers.
+
+.sp
+.nf
+ gl_normal_io()
+ gl_raw_io()
+ gl_handle_signal()
+ gl_abandon_line()
+.fi
+.sp
+
+In order for this to be true, all signal handlers that call these
+functions must be registered in such a way that only one instance of
+any one of them can be running at one time. The way to do this is to
+use the POSIX \f3sigaction()\f1 function to register all signal
+handlers, and when doing this, use the \f3sa_mask\f1 member of the
+corresponding sigaction structure, to indicate that all of the signals
+who's handlers invoke the above functions, should be blocked when the
+current signal is being handled. This prevents two signal handlers
+from operating on a \f3GetLine\f1 object at the same time.
+
+To prevent signal handlers from accessing a \f3GetLine\f1 object while
+\f3gl_get_line()\f1 or any of its associated public functions are
+operating on it, all public functions associated with
+\f3gl_get_line()\f1, including \f3gl_get_line()\f1 itself, temporarily
+block the delivery of signals when they are accessing \f3GetLine\f1
+objects. Beware that the only signals that they block are the signals
+that \f3gl_get_line()\f1 is currently configured to catch, so be sure
+that if you call any of the above functions from signal handlers, that
+the signals that these handlers are assigned to are configured to be
+caught by \f3gl_get_line()\f1 (see \f3gl_trap_signal()\f1).
+
+.SH USING TIMEOUTS TO POLL
+
+If instead of using \f3select()\f1 or \f3poll()\f1 to wait for I/O,
+your application just needs to get out of \f3gl_get_line()\f1
+periodically to briefly do something else before returning to accept
+input from the user, this can be done in non-blocking server mode by
+using the \f3gl_inactivity_timeout()\f1 function (see
+\f3gl_get_line(@FUNC_MANEXT@)\f1), to specify that a callback function that
+returns \f3GLTO_CONTINUE\f1 should be called whenever
+\f3gl_get_line()\f1 has been waiting for I/O for more than a specified
+amount of time.
+
+When this callback is triggered, \f3gl_get_line()\f1 will return
+\f3NULL\f1, and a following call to \f3gl_return_status()\f1 will
+return \f3GLR_BLOCKED\f1.
+
+Beware that \f3gl_get_line()\f1 won't return until the user
+hasn't typed a key for the specified interval, so if the
+interval is long, and the user keeps typing,
+\f3gl_get_line()\f1 may not return for a while. In other
+words there is no guarantee that it will return in the time
+specified.
+
+.SH THE SERVER DEMO PROGRAM
+
+The \f3demo3\f1 program that is distributed with the library, provides
+a working example of how to use non-blocking server I/O mode in a real
+program. As far as the user is concerned, this program operates
+identically to the main demo program (called \f3demo\f1), except that
+whereas the main demo program uses the normal blocking I/O mode,
+\f3demo3\f1 using non-blocking I/O and an external event loop. The
+source code can be found in \f3demo3.c\f1, and the comments therein
+explain the various steps.
+
+.SH FILES
+.nf
+libtecla.a - The tecla library
+libtecla.h - The tecla header file.
+.fi
+
+.SH SEE ALSO
+
+.nf
+libtecla(@LIBR_MANEXT@), gl_get_line(@FUNC_MANEXT@), tecla(@MISC_MANEXT@), ef_expand_file(@FUNC_MANEXT@),
+cpl_complete_word(@FUNC_MANEXT@), pca_lookup_file(@FUNC_MANEXT@)
+.fi
+
+.SH AUTHOR
+Martin Shepherd (mcs@astro.caltech.edu)
diff --git a/libtecla-1.6.1/man/func/gl_last_signal.in b/libtecla-1.6.1/man/func/gl_last_signal.in
new file mode 100644
index 0000000..6e46fc6
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_last_signal.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_get_line.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/gl_limit_history.in b/libtecla-1.6.1/man/func/gl_limit_history.in
new file mode 100644
index 0000000..6e46fc6
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_limit_history.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_get_line.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/gl_list_signals.in b/libtecla-1.6.1/man/func/gl_list_signals.in
new file mode 100644
index 0000000..6e46fc6
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_list_signals.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_get_line.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/gl_load_history.in b/libtecla-1.6.1/man/func/gl_load_history.in
new file mode 100644
index 0000000..6e46fc6
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_load_history.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_get_line.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/gl_lookup_history.in b/libtecla-1.6.1/man/func/gl_lookup_history.in
new file mode 100644
index 0000000..6e46fc6
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_lookup_history.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_get_line.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/gl_normal_io.in b/libtecla-1.6.1/man/func/gl_normal_io.in
new file mode 100644
index 0000000..24798bc
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_normal_io.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_io_mode.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/gl_pending_io.in b/libtecla-1.6.1/man/func/gl_pending_io.in
new file mode 100644
index 0000000..24798bc
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_pending_io.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_io_mode.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/gl_prompt_style.in b/libtecla-1.6.1/man/func/gl_prompt_style.in
new file mode 100644
index 0000000..6e46fc6
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_prompt_style.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_get_line.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/gl_query_char.in b/libtecla-1.6.1/man/func/gl_query_char.in
new file mode 100644
index 0000000..6e46fc6
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_query_char.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_get_line.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/gl_range_of_history.in b/libtecla-1.6.1/man/func/gl_range_of_history.in
new file mode 100644
index 0000000..6e46fc6
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_range_of_history.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_get_line.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/gl_raw_io.in b/libtecla-1.6.1/man/func/gl_raw_io.in
new file mode 100644
index 0000000..24798bc
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_raw_io.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_io_mode.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/gl_read_char.in b/libtecla-1.6.1/man/func/gl_read_char.in
new file mode 100644
index 0000000..6e46fc6
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_read_char.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_get_line.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/gl_register_action.in b/libtecla-1.6.1/man/func/gl_register_action.in
new file mode 100644
index 0000000..6e46fc6
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_register_action.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_get_line.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/gl_resize_history.in b/libtecla-1.6.1/man/func/gl_resize_history.in
new file mode 100644
index 0000000..6e46fc6
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_resize_history.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_get_line.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/gl_return_status.in b/libtecla-1.6.1/man/func/gl_return_status.in
new file mode 100644
index 0000000..6e46fc6
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_return_status.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_get_line.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/gl_save_history.in b/libtecla-1.6.1/man/func/gl_save_history.in
new file mode 100644
index 0000000..6e46fc6
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_save_history.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_get_line.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/gl_set_term_size.in b/libtecla-1.6.1/man/func/gl_set_term_size.in
new file mode 100644
index 0000000..6e46fc6
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_set_term_size.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_get_line.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/gl_show_history.in b/libtecla-1.6.1/man/func/gl_show_history.in
new file mode 100644
index 0000000..6e46fc6
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_show_history.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_get_line.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/gl_size_of_history.in b/libtecla-1.6.1/man/func/gl_size_of_history.in
new file mode 100644
index 0000000..6e46fc6
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_size_of_history.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_get_line.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/gl_state_of_history.in b/libtecla-1.6.1/man/func/gl_state_of_history.in
new file mode 100644
index 0000000..6e46fc6
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_state_of_history.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_get_line.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/gl_terminal_size.in b/libtecla-1.6.1/man/func/gl_terminal_size.in
new file mode 100644
index 0000000..6e46fc6
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_terminal_size.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_get_line.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/gl_toggle_history.in b/libtecla-1.6.1/man/func/gl_toggle_history.in
new file mode 100644
index 0000000..6e46fc6
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_toggle_history.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_get_line.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/gl_trap_signal.in b/libtecla-1.6.1/man/func/gl_trap_signal.in
new file mode 100644
index 0000000..6e46fc6
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_trap_signal.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_get_line.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/gl_tty_signals.in b/libtecla-1.6.1/man/func/gl_tty_signals.in
new file mode 100644
index 0000000..24798bc
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_tty_signals.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_io_mode.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/gl_watch_fd.in b/libtecla-1.6.1/man/func/gl_watch_fd.in
new file mode 100644
index 0000000..6e46fc6
--- /dev/null
+++ b/libtecla-1.6.1/man/func/gl_watch_fd.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_get_line.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/libtecla_version.in b/libtecla-1.6.1/man/func/libtecla_version.in
new file mode 100644
index 0000000..31867c4
--- /dev/null
+++ b/libtecla-1.6.1/man/func/libtecla_version.in
@@ -0,0 +1 @@
+.so @LIBR_MANDIR@/libtecla.@LIBR_MANEXT@
diff --git a/libtecla-1.6.1/man/func/new_CplFileConf.in b/libtecla-1.6.1/man/func/new_CplFileConf.in
new file mode 100644
index 0000000..734f281
--- /dev/null
+++ b/libtecla-1.6.1/man/func/new_CplFileConf.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/cpl_complete_word.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/new_ExpandFile.in b/libtecla-1.6.1/man/func/new_ExpandFile.in
new file mode 100644
index 0000000..3d0a884
--- /dev/null
+++ b/libtecla-1.6.1/man/func/new_ExpandFile.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/ef_expand_file.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/new_GetLine.in b/libtecla-1.6.1/man/func/new_GetLine.in
new file mode 100644
index 0000000..6e46fc6
--- /dev/null
+++ b/libtecla-1.6.1/man/func/new_GetLine.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/gl_get_line.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/new_PathCache.in b/libtecla-1.6.1/man/func/new_PathCache.in
new file mode 100644
index 0000000..dbc4da7
--- /dev/null
+++ b/libtecla-1.6.1/man/func/new_PathCache.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/pca_lookup_file.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/new_PcaPathConf.in b/libtecla-1.6.1/man/func/new_PcaPathConf.in
new file mode 100644
index 0000000..dbc4da7
--- /dev/null
+++ b/libtecla-1.6.1/man/func/new_PcaPathConf.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/pca_lookup_file.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/new_WordCompletion.in b/libtecla-1.6.1/man/func/new_WordCompletion.in
new file mode 100644
index 0000000..734f281
--- /dev/null
+++ b/libtecla-1.6.1/man/func/new_WordCompletion.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/cpl_complete_word.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/pca_last_error.in b/libtecla-1.6.1/man/func/pca_last_error.in
new file mode 100644
index 0000000..dbc4da7
--- /dev/null
+++ b/libtecla-1.6.1/man/func/pca_last_error.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/pca_lookup_file.@FUNC_MANEXT@
diff --git a/libtecla-1.4.1/man3/pca_lookup_file.3 b/libtecla-1.6.1/man/func/pca_lookup_file.in
index 131394a..861d205 100644
--- a/libtecla-1.4.1/man3/pca_lookup_file.3
+++ b/libtecla-1.6.1/man/func/pca_lookup_file.in
@@ -1,4 +1,4 @@
-.\" Copyright (C) 2001 by Martin C. Shepherd
+.\" Copyright (c) 2001, 2002, 2003, 2004 by Martin C. Shepherd
.\"
.\" All rights reserved.
.\"
@@ -26,7 +26,7 @@
.\" shall not be used in advertising or otherwise to promote the sale, use
.\" or other dealings in this Software without prior written authorization
.\" of the copyright holder.
-.TH pca_lookup_file 3
+.TH pca_lookup_file @FUNC_MANEXT@
.SH NAME
pca_lookup_file, del_PathCache, del_PcaPathConf, new_PathCache, new_PcaPathConf, pca_last_error, pca_path_completions, pca_scan_path, pca_set_check_fn, ppc_file_start, ppc_literal_escapes \- lookup a file in a list of directories
.SH SYNOPSIS
@@ -54,7 +54,7 @@ CPL_MATCH_FN(pca_path_completions);
.SH DESCRIPTION
The \f3PathCache\f1 object is part of the tecla library (see the
-libtecla(3) man page).
+libtecla(@LIBR_MANEXT@) man page).
.sp
\f3PathCache\f1 objects allow an application to search for files in
any colon separated list of directories, such as the unix execution
@@ -190,7 +190,7 @@ argument.
Looking up the potential completions of a filename-prefix in the
filename cache, is achieved by passing the provided
\f3pca_path_completions()\f1 callback function to the
-\f3cpl_complete_word()\f1 function (see the \f3cpl_complete_word(3)\f1
+\f3cpl_complete_word()\f1 function (see the \f3cpl_complete_word(@FUNC_MANEXT@)\f1
man page).
.sp
.nf
@@ -355,7 +355,11 @@ libtecla.h - The tecla header file.
.fi
.SH SEE ALSO
-libtecla(3), gl_get_line(3), ef_expand_file(3), cpl_complete_word(3)
-
+
+.nf
+libtecla(@LIBR_MANEXT@), gl_get_line(@FUNC_MANEXT@), ef_expand_file(@FUNC_MANEXT@),
+cpl_complete_word(@FUNC_MANEXT@)
+.fi
+
.SH AUTHOR
Martin Shepherd (mcs@astro.caltech.edu)
diff --git a/libtecla-1.6.1/man/func/pca_path_completions.in b/libtecla-1.6.1/man/func/pca_path_completions.in
new file mode 100644
index 0000000..dbc4da7
--- /dev/null
+++ b/libtecla-1.6.1/man/func/pca_path_completions.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/pca_lookup_file.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/pca_scan_path.in b/libtecla-1.6.1/man/func/pca_scan_path.in
new file mode 100644
index 0000000..dbc4da7
--- /dev/null
+++ b/libtecla-1.6.1/man/func/pca_scan_path.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/pca_lookup_file.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/pca_set_check_fn.in b/libtecla-1.6.1/man/func/pca_set_check_fn.in
new file mode 100644
index 0000000..dbc4da7
--- /dev/null
+++ b/libtecla-1.6.1/man/func/pca_set_check_fn.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/pca_lookup_file.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/ppc_file_start.in b/libtecla-1.6.1/man/func/ppc_file_start.in
new file mode 100644
index 0000000..dbc4da7
--- /dev/null
+++ b/libtecla-1.6.1/man/func/ppc_file_start.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/pca_lookup_file.@FUNC_MANEXT@
diff --git a/libtecla-1.6.1/man/func/ppc_literal_escapes.in b/libtecla-1.6.1/man/func/ppc_literal_escapes.in
new file mode 100644
index 0000000..dbc4da7
--- /dev/null
+++ b/libtecla-1.6.1/man/func/ppc_literal_escapes.in
@@ -0,0 +1 @@
+.so @FUNC_MANDIR@/pca_lookup_file.@FUNC_MANEXT@
diff --git a/libtecla-1.4.1/man3/libtecla.3 b/libtecla-1.6.1/man/libr/libtecla.in
index 611eb57..9f9aa75 100644
--- a/libtecla-1.4.1/man3/libtecla.3
+++ b/libtecla-1.6.1/man/libr/libtecla.in
@@ -1,4 +1,4 @@
-.\" Copyright (C) 2000, 2001 by Martin C. Shepherd
+.\" Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd
.\"
.\" All rights reserved.
.\"
@@ -26,12 +26,12 @@
.\" shall not be used in advertising or otherwise to promote the sale, use
.\" or other dealings in this Software without prior written authorization
.\" of the copyright holder.
-.TH libtecla 3
+.TH libtecla @LIBR_MANEXT@
.SH NAME
libtecla - An interactive command-line input library.
.SH SYNOPSIS
.nf
-gcc ... -ltecla -lcurses
+@CC@ ... -ltecla -lcurses
.fi
.SH DESCRIPTION
@@ -49,18 +49,23 @@ The various parts of the library are documented in the following man
pages:
.nf
- gl_get_line(3) - The interactive line-input module.
- cpl_complete_word(3) - The word completion module.
- ef_expand_file(3) - The filename expansion module.
- pca_lookup_file(3) - A directory-list based filename
- lookup and completion module.
+ tecla(@MISC_MANEXT@) - Use level documentation of the
+ command-line editing facilities
+ provided by \f3gl_get_line()\f1.
+ gl_get_line(@FUNC_MANEXT@) - The interactive line-input module.
+ gl_io_mode(@FUNC_MANEXT@) - How to use \f3gl_get_line()\f1 in an
+ incremental, non-blocking fashion.
+ cpl_complete_word(@FUNC_MANEXT@) - The word completion module.
+ ef_expand_file(@FUNC_MANEXT@) - The filename expansion module.
+ pca_lookup_file(@FUNC_MANEXT@) - A directory-list based filename
+ lookup and completion module.
.fi
In addition there is one optional application distributed
with the library:
.nf
- enhance(3) - Add command-line editing to third
+ enhance(@PROG_MANEXT@) - Add command-line editing to third
party applications.
.fi
@@ -137,9 +142,12 @@ libtecla.h - The tecla header file.
.fi
.SH SEE ALSO
-gl_get_line(3), ef_expand_file(3), cpl_complete_word(3),
-pca_lookup_file(3), enhance(3)
-
+
+.nf
+gl_get_line(@FUNC_MANEXT@), tecla(@MISC_MANEXT@), gl_io_mode(@FUNC_MANEXT@), ef_expand_file(@FUNC_MANEXT@),
+cpl_complete_word(@FUNC_MANEXT@), pca_lookup_file(@FUNC_MANEXT@), enhance(@PROG_MANEXT@)
+.fi
+
.SH AUTHOR
Martin Shepherd (mcs@astro.caltech.edu)
diff --git a/libtecla-1.6.1/man/misc/tecla.in b/libtecla-1.6.1/man/misc/tecla.in
new file mode 100644
index 0000000..1be2902
--- /dev/null
+++ b/libtecla-1.6.1/man/misc/tecla.in
@@ -0,0 +1,1201 @@
+.\" Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd
+.\"
+.\" All rights reserved.
+.\"
+.\" Permission is hereby granted, free of charge, to any person obtaining a
+.\" copy of this software and associated documentation files (the
+.\" "Software"), to deal in the Software without restriction, including
+.\" without limitation the rights to use, copy, modify, merge, publish,
+.\" distribute, and/or sell copies of the Software, and to permit persons
+.\" to whom the Software is furnished to do so, provided that the above
+.\" copyright notice(s) and this permission notice appear in all copies of
+.\" the Software and that both the above copyright notice(s) and this
+.\" permission notice appear in supporting documentation.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+.\" OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+.\" OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+.\" HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
+.\" INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
+.\" FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+.\" NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+.\" WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\" Except as contained in this notice, the name of a copyright holder
+.\" shall not be used in advertising or otherwise to promote the sale, use
+.\" or other dealings in this Software without prior written authorization
+.\" of the copyright holder.
+.TH tecla @MISC_MANEXT@
+.SH NAME
+tecla, teclarc \- The user interface provided by the Tecla library.
+.SH DESCRIPTION
+
+This man page describes the command-line editing features that are
+available to users of programs that read keyboard input via the Tecla
+library. Users of the tcsh shell will find the default key-bindings
+very familiar. Users of the bash shell will also find it quite
+familiar, but with a few minor differences, most notably in how
+forward and backward searches through the list of historical commands
+are performed. There are two major editing modes, one with emacs-like
+key-bindings and another with vi-like key-bindings. By default emacs
+mode is enabled, but vi mode can alternatively be selected via the
+user's configuration file. This file can also be used to change the
+bindings of individual keys to suit the user's preferences. By
+default, tab completion is provided. If the application hasn't
+reconfigured this to complete other types of symbols, then tab
+completion completes file-names.
+
+.SH KEY SEQUENCE NOTATION
+
+In the rest of this man page, and also in all Tecla configuration
+files, key-sequences are expressed as follows.
+
+.sp
+.nf
+\f3^A\f1 or \f3C-a\f1
+ This is a control-A, entered by pressing the control key at
+ the same time as the \f3A\f1 key.
+
+\f3\\E\f1 or \f3M-\f1
+ In key-sequences, both of these notations can be entered
+ either by pressing the escape key, then the following key, or by
+ pressing the Meta key at the same time as the following key. Thus
+ the key sequence \f3M-p\f1 can be typed in two ways, by pressing
+ the escape key, followed by pressing \f3p\f1, or by pressing the
+ Meta key at the same time as \f3p\f1.
+
+\f3up\f1
+ This refers to the up-arrow key.
+
+\f3down\f1
+ This refers to the down-arrow key.
+
+\f3left\f1
+ This refers to the left-arrow key.
+
+\f3right\f1
+ This refers to the right-arrow key.
+
+\f3a\f1
+ This is just a normal A key.
+.fi
+.sp
+
+.SH THE TECLA CONFIGURATION FILE
+
+By default, Tecla looks for a file called \f3\&.teclarc\f1 in your
+home directory (ie. \f3~/.teclarc\f1). If it finds this file, it
+reads it, interpreting each line as defining a new key binding or an
+editing configuration option. Since the emacs keybindings are
+installed by default, if you want to use the non-default vi editing
+mode, the most important item to go in this file is the following
+line:
+
+.nf
+ edit-mode vi
+.fi
+
+This will re-configure the default bindings for vi-mode. The
+complete set of arguments that this command accepts are:
+.sp
+.nf
+ vi - Install key-bindings like those of the vi
+ editor.
+ emacs - Install key-bindings like those of the emacs
+ editor. This is the default.
+ none - Use just the native line editing facilities
+ provided by the terminal driver.
+.fi
+.sp
+To prevent the terminal bell from being rung, such as when
+an unrecognized control-sequence is typed, place the
+following line in the configuration file:
+
+.nf
+ nobeep
+.fi
+
+An example of a key binding line in the configuration file is
+the following.
+
+.nf
+ bind M-[2~ insert-mode
+.fi
+
+On many keyboards, the above key sequence is generated when one
+presses the \f3insert\f1 key, so with this keybinding, one can toggle
+between the emacs-mode insert and overwrite modes by hitting one
+key. One could also do it by typing out the above sequence of
+characters one by one. As explained above, the \f3M-\f1 part of this
+sequence can be typed either by pressing the escape key before the
+following key, or by pressing the Meta key at the same time as the
+following key. Thus if you had set the above key binding, and the
+insert key on your keyboard didn't generate the above key sequence,
+you could still type it in either of the following 2 ways.
+
+.nf
+ 1. Hit the escape key momentarily, then press '[', then '2', then
+ finally '~'.
+
+ 2. Press the meta key at the same time as pressing the '[' key,
+ then press '2', then '~'.
+.fi
+
+If you set a keybinding for a key-sequence that is already bound to a function,
+the new binding overrides the old one. If in the new binding you omit the name
+of the new function to bind to the key-sequence, the original binding becomes
+undefined.
+.sp
+Starting with versions of libtecla later than 1.3.3 it is now possible
+to bind keysequences that begin with a printable character. Previously
+key-sequences were required to start with a control or meta character.
+.sp
+Note that the special keywords "up", "down", "left" and "right" refer
+to the arrow keys, and are thus not treated as keysequences. So, for
+example, to rebind the up and down arrow keys to use the history
+search mechanism instead of the simple history recall method, you
+could place the following in your configuration file:
+
+.nf
+ bind up history-search-backwards
+ bind down history-search-backwards
+.fi
+.sp
+To unbind an existing binding, you can do this with the bind command
+by omitting to name any action to rebind the key sequence to. For
+example, by not specifying an action function, the following command
+unbinds the default beginning-of-line action from the ^A key sequence:
+
+.nf
+ bind ^A
+.fi
+
+If you create a \f3~/.teclarc\f1 configuration file, but it appears to
+have no effect on the program, check the documentation of the program
+to see if the author chose a different name for this file.
+
+.SH FILENAME AND TILDE COMPLETION
+
+With the default key bindings, pressing the TAB key (aka. \f3^I\f1)
+results in Tecla attempting to complete the incomplete filename that
+precedes the cursor. Tecla searches backwards from the cursor, looking
+for the start of the filename, stopping when it hits either a space or
+the start of the line. If more than one file has the specified prefix,
+then Tecla completes the filename up to the point at which the
+ambiguous matches start to differ, then lists the possible matches.
+.sp
+In addition to literally written filenames, Tecla can
+complete files that start with \f3~/\f1 and \f3~user/\f1 expressions
+and that contain \f3$envvar\f1 expressions. In particular, if you hit
+TAB within an incomplete \f3~user\f1, expression, Tecla
+will attempt to complete the username, listing any ambiguous matches.
+.sp
+The completion binding is implemented using the
+\f3cpl_word_completions()\f1 function, which is also available
+separately to users of this library. See the
+\f3cpl_word_completions(@LIBR_MANEXT@)\f1 man page for more details.
+
+.SH FILENAME EXPANSION
+
+With the default key bindings, pressing \f3^X*\f1 causes Tecla to
+expand the filename that precedes the cursor, replacing \f3~/\f1 and
+\f3~user/\f1 expressions with the corresponding home directories, and
+replacing \f3$envvar\f1 expressions with the value of the specified
+environment variable, then if there are any wildcards, replacing the
+so far expanded filename with a space-separated list of the files
+which match the wild cards.
+.sp
+The expansion binding is implemented using the \f3ef_expand_file()\f1 function.
+See the \f3ef_expand_file(@LIBR_MANEXT@)\f1 man page for more details.
+
+.SH RECALLING PREVIOUSLY TYPED LINES
+
+Every time that a new line is entered by the user, it is appended to a
+list of historical input lines maintained within the GetLine resource
+object. You can traverse up and down this list using the up and down
+arrow keys. Alternatively, you can do the same with the \f3^P\f1, and
+\f3^N\f1 keys, and in vi command mode you can alternatively use the k
+and j characters. Thus pressing up-arrow once, replaces the current
+input line with the previously entered line. Pressing up-arrow again,
+replaces this with the line that was entered before it, etc.. Having
+gone back one or more lines into the history list, one can return to
+newer lines by pressing down-arrow one or more times. If you do this
+sufficient times, you will return to the original line that you were
+entering when you first hit up-arrow.
+.sp
+Note that in vi mode, all of the history recall functions switch the
+library into command mode.
+.sp
+In emacs mode the \f3M-p\f1 and \f3M-n\f1 keys work just like the
+\f3^P\f1 and \f3^N\f1 keys, except that they skip all but those
+historical lines which share the prefix that precedes the cursor. In
+vi command mode the upper case \f3K\f1 and \f3J\f1 characters do the
+same thing, except that the string that they search for includes the
+character under the cursor as well as what precedes it.
+.sp
+Thus for example, suppose that you were in emacs mode, and you had
+just entered the following list of commands in the order shown:
+
+.nf
+ ls ~/tecla/
+ cd ~/tecla
+ ls -l getline.c
+ emacs ~/tecla/getline.c
+.fi
+
+If you next typed:
+
+.nf
+ ls
+.fi
+
+and then hit \f3M-p\f1, then rather than returning the previously
+typed emacs line, which doesn't start with "ls", Tecla
+would recall the "ls -l getline.c" line. Pressing \f3M-p\f1 again
+would recall the "ls ~/tecla/" line.
+
+Note that if the string that you are searching for, contains any of
+the special characters, *, ?, or '[', then it is interpretted as a
+pattern to be matched. Thus, cotinuing with the above example, after
+typing in the list of commands shown, if you then typed:
+
+.nf
+ *tecla*
+.fi
+
+and hit \f3M-p\f1, then the "emacs ~/tecla/getline.c" line would be
+recalled first, since it contains the word tecla somewhere in the
+line, Similarly, hitting \f3M-p\f1 again, would recall the "ls
+~/tecla/" line, and hitting it once more would recall the "ls
+~/tecla/" line. The pattern syntax is the same as that described for
+filename expansion, in the \f3ef_expand_file(@LIBR_MANEXT@\f1 man
+page.
+
+.SH HISTORY FILES
+
+Authors of programs that use the Tecla library have the option of
+saving historical command-lines in a file before exiting, and
+subsequently reading them back in from this file when the program is
+next started. There is no standard name for this file, since it makes
+sense for each application to use its own history file, so that
+commands from different applications don't get mixed up.
+
+.SH INTERNATIONAL CHARACTER SETS
+
+Since libtecla version 1.4.0, Tecla has been 8-bit clean. This means
+that all 8-bit characters that are printable in the user's current
+locale are now displayed verbatim and included in the returned input
+line. Assuming that the calling program correctly contains a call
+like the following,
+.sp
+.nf
+ setlocale(LC_CTYPE, "");
+.fi
+.sp
+then the current locale is determined by the first of the environment
+variables \f3LC_CTYPE\f1, \f3LC_ALL\f1, and \f3LANG\f1, that is found
+to contain a valid locale name. If none of these variables are
+defined, or the program neglects to call setlocale, then the default
+\f3C\f1 locale is used, which is US 7-bit ASCII. On most unix-like
+platforms, you can get a list of valid locales by typing the command:
+.sp
+.nf
+ locale -a
+.fi
+.sp
+at the shell prompt.
+.sp
+.SS "Meta keys and locales"
+
+Beware that in most locales other than the default C locale, meta
+characters become printable, and they are then no longer considered to
+match \f3M-c\f1 style key bindings. This allows international
+characters to be entered with the compose key without unexpectedly
+triggering meta key bindings. You can still invoke meta bindings,
+since there are actually two ways to do this. For example the binding
+\f3M-c\f1 can also be invoked by pressing the escape key momentarily,
+then pressing the \f3c\f1 key, and this will work regardless of
+locale. Moreover, many modern terminal emulators, such as gnome's
+gnome-terminal's and KDE's konsole terminals, already generate escape
+pairs like this when you use the meta key, rather than a real meta
+character, and other emulators usually have a way to request this
+behavior, so you can continue to use the meta key on most systems.
+.sp
+For example, although xterm terminal emulators generate real 8-bit
+meta characters by default when you use the meta key, they can be
+configured to output the equivalent escape pair by setting their
+\f3EightBitInput\f1 X resource to \f3False\f1. You can either do this
+by placing a line like the following in your \f3~/.Xdefaults\f1 file,
+.sp
+.nf
+ XTerm*EightBitInput: False
+.sp
+.fi
+or by starting an xterm with an \f3-xrm '*EightBitInput: False'\f1
+command-line argument. In recent versions of xterm you can toggle this
+feature on and off with the \f3"Meta Sends Escape"\f1 option in the
+menu that is displayed when you press the left mouse button and the
+control key within an xterm window. In CDE, dtterms can be similarly
+coerced to generate escape pairs in place of meta characters, by
+setting the \f3Dtterm*KshMode\f1 resource to \f3True\f1.
+.sp
+.SS "Entering international characters"
+
+If you don't have a keyboard that generates all of the
+international characters that you need, there is usually a
+compose key that will allow you to enter special characters,
+or a way to create one. For example, under X windows on
+unix-like systems, if your keyboard doesn't have a compose
+key, you can designate a redundant key to serve this purpose
+with the xmodmap command. For example, on many PC keyboards
+there is a microsoft-windows key, which is otherwise useless
+under Linux. On my laptop the \f3xev\f1 program reports that
+pressing this key generates keycode 115, so to turn this key
+into a compose key, I do the following:
+.sp
+.nf
+ xmodmap -e 'keycode 115 = Multi_key'
+.fi
+.sp
+I can then enter an i with a umlaut over it by typing this key,
+followed by \f3"\f1, followed by i.
+
+.SH THE AVAILABLE KEY BINDING FUNCTIONS
+
+The following is a list of the editing functions provided by the Tecla
+library. The names in the leftmost column of the list can be used in
+configuration files to specify which function a given key or
+combination of keys should invoke. They are also used in the next two
+sections to list the default key-bindings in emacs and vi modes.
+
+.nf
+ user-interrupt - Send a SIGINT signal to the
+ parent process.
+ abort - Send a SIGABRT signal to the
+ parent process.
+ suspend - Suspend the parent process.
+ stop-output - Pause terminal output.
+ start-output - Resume paused terminal output.
+ literal-next - Arrange for the next character
+ to be treated as a normal
+ character. This allows control
+ characters to be entered.
+ cursor-right - Move the cursor one character
+ right.
+ cursor-left - Move the cursor one character
+ left.
+ insert-mode - Toggle between insert mode and
+ overwrite mode.
+ beginning-of-line - Move the cursor to the
+ beginning of the line.
+ end-of-line - Move the cursor to the end of
+ the line.
+ delete-line - Delete the contents of the
+ current line.
+ kill-line - Delete everything that follows
+ the cursor.
+ backward-kill-line - Delete all characters between
+ the cursor and the start of the
+ line.
+ forward-word - Move to the end of the word
+ which follows the cursor.
+ forward-to-word - Move the cursor to the start of
+ the word that follows the
+ cursor.
+ backward-word - Move to the start of the word
+ which precedes the cursor.
+ goto-column - Move the cursor to the
+ 1-relative column in the line
+ specified by any preceding
+ digit-argument sequences (see
+ ENTERING REPEAT COUNTS below).
+ find-parenthesis - If the cursor is currently
+ over a parenthesis character,
+ move it to the matching
+ parenthesis character. If not
+ over a parenthesis character
+ move right to the next close
+ parenthesis.
+ forward-delete-char - Delete the character under the
+ cursor.
+ backward-delete-char - Delete the character which
+ precedes the cursor.
+ list-or-eof - This is intended for binding
+ to ^D. When invoked when the
+ cursor is within the line it
+ displays all possible
+ completions then redisplays
+ the line unchanged. When
+ invoked on an empty line, it
+ signals end-of-input (EOF) to
+ the caller of gl_get_line().
+ del-char-or-list-or-eof - This is intended for binding
+ to ^D. When invoked when the
+ cursor is within the line it
+ invokes forward-delete-char.
+ When invoked at the end of the
+ line it displays all possible
+ completions then redisplays
+ the line unchanged. When
+ invoked on an empty line, it
+ signals end-of-input (EOF) to
+ the caller of gl_get_line().
+ forward-delete-word - Delete the word which follows
+ the cursor.
+ backward-delete-word - Delete the word which precedes
+ the cursor.
+ upcase-word - Convert all of the characters
+ of the word which follows the
+ cursor, to upper case.
+ downcase-word - Convert all of the characters
+ of the word which follows the
+ cursor, to lower case.
+ capitalize-word - Capitalize the word which
+ follows the cursor.
+ change-case - If the next character is upper
+ case, toggle it to lower case
+ and vice versa.
+ redisplay - Redisplay the line.
+ clear-screen - Clear the terminal, then
+ redisplay the current line.
+ transpose-chars - Swap the character under the
+ cursor with the character just
+ before the cursor.
+ set-mark - Set a mark at the position of
+ the cursor.
+ exchange-point-and-mark - Move the cursor to the last
+ mark that was set, and move
+ the mark to where the cursor
+ used to be.
+ kill-region - Delete the characters that lie
+ between the last mark that was
+ set, and the cursor.
+ copy-region-as-kill - Copy the text between the mark
+ and the cursor to the cut
+ buffer, without deleting the
+ original text.
+ yank - Insert the text that was last
+ deleted, just before the
+ current position of the cursor.
+ append-yank - Paste the current contents of
+ the cut buffer, after the
+ cursor.
+ up-history - Recall the next oldest line
+ that was entered. Note that
+ in vi mode you are left in
+ command mode.
+ down-history - Recall the next most recent
+ line that was entered. If no
+ history recall session is
+ currently active, the next
+ line from a previous recall
+ session is recalled. Note that
+ in vi mode you are left in
+ command mode.
+ history-search-backward - Recall the next oldest line
+ who's prefix matches the string
+ which currently precedes the
+ cursor (in vi command-mode the
+ character under the cursor is
+ also included in the search
+ string). Note that in vi mode
+ you are left in command mode.
+ history-search-forward - Recall the next newest line
+ who's prefix matches the string
+ which currently precedes the
+ cursor (in vi command-mode the
+ character under the cursor is
+ also included in the search
+ string). Note that in vi mode
+ you are left in command mode.
+ history-re-search-backward -Recall the next oldest line
+ who's prefix matches that
+ established by the last
+ invocation of either
+ history-search-forward or
+ history-search-backward.
+ history-re-search-forward - Recall the next newest line
+ who's prefix matches that
+ established by the last
+ invocation of either
+ history-search-forward or
+ history-search-backward.
+ complete-word - Attempt to complete the
+ incomplete word which
+ precedes the cursor. Unless
+ the host program has customized
+ word completion, filename
+ completion is attempted. In vi
+ commmand mode the character
+ under the cursor is also
+ included in the word being
+ completed, and you are left in
+ vi insert mode.
+ expand-filename - Within the command line, expand
+ wild cards, tilde expressions
+ and dollar expressions in the
+ filename which immediately
+ precedes the cursor. In vi
+ commmand mode the character
+ under the cursor is also
+ included in the filename being
+ expanded, and you are left in
+ vi insert mode.
+ list-glob - List any filenames which match
+ the wild-card, tilde and dollar
+ expressions in the filename
+ which immediately precedes the
+ cursor, then redraw the input
+ line unchanged.
+ list-history - Display the contents of the
+ history list for the current
+ history group. If a repeat
+ count of > 1 is specified,
+ only that many of the most
+ recent lines are displayed.
+ See the "ENTERING REPEAT
+ COUNTS" section.
+ read-from-file - Temporarily switch to reading
+ input from the file who's
+ name precedes the cursor.
+ read-init-files - Re-read teclarc configuration
+ files.
+ beginning-of-history - Move to the oldest line in the
+ history list. Note that in vi
+ mode you are left in command
+ mode.
+ end-of-history - Move to the newest line in the
+ history list (ie. the current
+ line). Note that in vi mode
+ this leaves you in command
+ mode.
+ digit-argument - Enter a repeat count for the
+ next key-binding function.
+ For details, see the ENTERING
+ REPEAT COUNTS section.
+ newline - Terminate and return the
+ current contents of the
+ line, after appending a
+ newline character. The newline
+ character is normally '\\n',
+ but will be the first
+ character of the key-sequence
+ that invoked the newline
+ action, if this happens to be
+ a printable character. If the
+ action was invoked by the
+ '\\n' newline character or the
+ '\\r' carriage return
+ character, the line is
+ appended to the history
+ buffer.
+ repeat-history - Return the line that is being
+ edited, then arrange for the
+ next most recent entry in the
+ history buffer to be recalled
+ when Tecla is next called.
+ Repeatedly invoking this
+ action causes successive
+ historical input lines to be
+ re-executed. Note that this
+ action is equivalent to the
+ 'Operate' action in ksh.
+ ring-bell - Ring the terminal bell, unless
+ the bell has been silenced via
+ the \f3nobeep\f1 configuration
+ option (see the THE TECLA
+ CONFIGURATION FILE section).
+ forward-copy-char - Copy the next character into
+ the cut buffer (NB. use repeat
+ counts to copy more than one).
+ backward-copy-char - Copy the previous character
+ into the cut buffer.
+ forward-copy-word - Copy the next word into the cut
+ buffer.
+ backward-copy-word - Copy the previous word into the
+ cut buffer.
+ forward-find-char - Move the cursor to the next
+ occurrence of the next
+ character that you type.
+ backward-find-char - Move the cursor to the last
+ occurrence of the next
+ character that you type.
+ forward-to-char - Move the cursor to the
+ character just before the next
+ occurrence of the next
+ character that the user types.
+ backward-to-char - Move the cursor to the
+ character just after the last
+ occurrence before the cursor
+ of the next character that the
+ user types.
+ repeat-find-char - Repeat the last
+ backward-find-char,
+ forward-find-char,
+ backward-to-char or
+ forward-to-char.
+ invert-refind-char - Repeat the last
+ backward-find-char,
+ forward-find-char,
+ backward-to-char, or
+ forward-to-char in the
+ opposite direction.
+ delete-to-column - Delete the characters from the
+ cursor up to the column that
+ is specified by the repeat
+ count.
+ delete-to-parenthesis - Delete the characters from the
+ cursor up to and including
+ the matching parenthesis, or
+ next close parenthesis.
+ forward-delete-find - Delete the characters from the
+ cursor up to and including the
+ following occurence of the
+ next character typed.
+ backward-delete-find - Delete the characters from the
+ cursor up to and including the
+ preceding occurence of the
+ next character typed.
+ forward-delete-to - Delete the characters from the
+ cursor up to, but not
+ including, the following
+ occurence of the next
+ character typed.
+ backward-delete-to - Delete the characters from the
+ cursor up to, but not
+ including, the preceding
+ occurence of the next
+ character typed.
+ delete-refind - Repeat the last *-delete-find
+ or *-delete-to action.
+ delete-invert-refind - Repeat the last *-delete-find
+ or *-delete-to action, in the
+ opposite direction.
+ copy-to-column - Copy the characters from the
+ cursor up to the column that
+ is specified by the repeat
+ count, into the cut buffer.
+ copy-to-parenthesis - Copy the characters from the
+ cursor up to and including
+ the matching parenthesis, or
+ next close parenthesis, into
+ the cut buffer.
+ forward-copy-find - Copy the characters from the
+ cursor up to and including the
+ following occurence of the
+ next character typed, into the
+ cut buffer.
+ backward-copy-find - Copy the characters from the
+ cursor up to and including the
+ preceding occurence of the
+ next character typed, into the
+ cut buffer.
+ forward-copy-to - Copy the characters from the
+ cursor up to, but not
+ including, the following
+ occurence of the next
+ character typed, into the cut
+ buffer.
+ backward-copy-to - Copy the characters from the
+ cursor up to, but not
+ including, the preceding
+ occurence of the next
+ character typed, into the cut
+ buffer.
+ copy-refind - Repeat the last *-copy-find
+ or *-copy-to action.
+ copy-invert-refind - Repeat the last *-copy-find
+ or *-copy-to action, in the
+ opposite direction.
+ vi-mode - Switch to vi mode from emacs
+ mode.
+ emacs-mode - Switch to emacs mode from vi
+ mode.
+ vi-insert - From vi command mode, switch to
+ insert mode.
+ vi-overwrite - From vi command mode, switch to
+ overwrite mode.
+ vi-insert-at-bol - From vi command mode, move the
+ cursor to the start of the line
+ and switch to insert mode.
+ vi-append-at-eol - From vi command mode, move the
+ cursor to the end of the line
+ and switch to append mode.
+ vi-append - From vi command mode, move the
+ cursor one position right, and
+ switch to insert mode.
+ vi-replace-char - From vi command mode, replace
+ the character under the cursor
+ with the the next character
+ entered.
+ vi-forward-change-char - From vi command mode, delete
+ the next character then enter
+ insert mode.
+ vi-backward-change-char - From vi command mode, delete
+ the preceding character then
+ enter insert mode.
+ vi-forward-change-word - From vi command mode, delete
+ the next word then enter
+ insert mode.
+ vi-backward-change-word - From vi command mode, delete
+ the preceding word then
+ enter insert mode.
+ vi-change-rest-of-line - From vi command mode, delete
+ from the cursor to the end of
+ the line, then enter insert
+ mode.
+ vi-change-line - From vi command mode, delete
+ the current line, then enter
+ insert mode.
+ vi-change-to-bol - From vi command mode, delete
+ all characters between the
+ cursor and the beginning of
+ the line, then enter insert
+ mode.
+ vi-change-to-column - From vi command mode, delete
+ the characters from the cursor
+ up to the column that is
+ specified by the repeat count,
+ then enter insert mode.
+ vi-change-to-parenthesis - Delete the characters from the
+ cursor up to and including
+ the matching parenthesis, or
+ next close parenthesis, then
+ enter vi insert mode.
+ vi-forward-change-find - From vi command mode, delete
+ the characters from the
+ cursor up to and including the
+ following occurence of the
+ next character typed, then
+ enter insert mode.
+ vi-backward-change-find - From vi command mode, delete
+ the characters from the
+ cursor up to and including the
+ preceding occurence of the
+ next character typed, then
+ enter insert mode.
+ vi-forward-change-to - From vi command mode, delete
+ the characters from the
+ cursor up to, but not
+ including, the following
+ occurence of the next
+ character typed, then enter
+ insert mode.
+ vi-backward-change-to - From vi command mode, delete
+ the characters from the
+ cursor up to, but not
+ including, the preceding
+ occurence of the next
+ character typed, then enter
+ insert mode.
+ vi-change-refind - Repeat the last
+ vi-*-change-find or
+ vi-*-change-to action.
+ vi-change-invert-refind - Repeat the last
+ vi-*-change-find or
+ vi-*-change-to action, in the
+ opposite direction.
+ vi-undo - In vi mode, undo the last
+ editing operation.
+ vi-repeat-change - In vi command mode, repeat the
+ last command that modified the
+ line.
+.fi
+
+.SH DEFAULT KEY BINDINGS IN EMACS MODE
+
+The following default key bindings, which can be overriden by
+the Tecla configuration file, are designed to mimic most of
+the bindings of the unix \f3tcsh\f1 shell, when it is in
+emacs editing mode.
+.sp
+This is the default editing mode of the Tecla library.
+.sp
+Under UNIX the terminal driver sets a number of special keys for certain
+functions. The tecla library attempts to use the same keybindings to maintain
+consistency. The key sequences shown for the following 6 bindings are thus just
+examples of what they will probably be set to. If you have used the \f3stty\f1
+command to change these keys, then the default bindings should match.
+
+.nf
+ ^C -> user-interrupt
+ ^\\ -> abort
+ ^Z -> suspend
+ ^Q -> start-output
+ ^S -> stop-output
+ ^V -> literal-next
+.fi
+
+The cursor keys are refered to by name, as follows. This is necessary
+because different types of terminals generate different key sequences
+when their cursor keys are pressed.
+
+ right -> cursor-right
+ left -> cursor-left
+ up -> up-history
+ down -> down-history
+
+The remaining bindings don't depend on the terminal setttings.
+
+.nf
+ ^F -> cursor-right
+ ^B -> cursor-left
+ M-i -> insert-mode
+ ^A -> beginning-of-line
+ ^E -> end-of-line
+ ^U -> delete-line
+ ^K -> kill-line
+ M-f -> forward-word
+ M-b -> backward-word
+ ^D -> del-char-or-list-or-eof
+ ^H -> backward-delete-char
+ ^? -> backward-delete-char
+ M-d -> forward-delete-word
+ M-^H -> backward-delete-word
+ M-^? -> backward-delete-word
+ M-u -> upcase-word
+ M-l -> downcase-word
+ M-c -> capitalize-word
+ ^R -> redisplay
+ ^L -> clear-screen
+ ^T -> transpose-chars
+ ^@ -> set-mark
+ ^X^X -> exchange-point-and-mark
+ ^W -> kill-region
+ M-w -> copy-region-as-kill
+ ^Y -> yank
+ ^P -> up-history
+ ^N -> down-history
+ M-p -> history-search-backward
+ M-n -> history-search-forward
+ ^I -> complete-word
+ ^X* -> expand-filename
+ ^X^F -> read-from-file
+ ^X^R -> read-init-files
+ ^Xg -> list-glob
+ ^Xh -> list-history
+ M-< -> beginning-of-history
+ M-> -> end-of-history
+ \\n -> newline
+ \\r -> newline
+ M-o -> repeat-history
+ M-^V -> vi-mode
+
+ M-0, M-1, ... M-9 -> digit-argument (see below)
+.fi
+
+Note that \f3^I\f1 is what the TAB key generates, and that \f3^@\f1
+can be generated not only by pressing the control key and the \f3@\f1
+key simultaneously, but also by pressing the control key and the space
+bar at the same time.
+
+.SH DEFAULT KEY BINDINGS IN VI MODE
+
+The following default key bindings are designed to mimic the
+vi style of editing as closely as possible. This means that
+very few editing functions are provided in the initial
+character input mode, editing functions instead being
+provided by the vi command mode. Vi command mode is entered
+whenever the escape character is pressed, or whenever a
+key-sequence that starts with a meta character is entered. In
+addition to mimicing vi, libtecla provides bindings for tab
+completion, wild-card expansion of file names, and historical
+line recall.
+.sp
+To learn how to tell the Tecla library to use vi mode instead
+of the default emacs editing mode, see the earlier section entitled
+THE TECLA CONFIGURATION FILE.
+.sp
+Under UNIX the terminal driver sets a number of special keys
+for certain functions. The Tecla library attempts to use the
+same keybindings to maintain consistency, binding them both
+in input mode and in command mode. The key sequences shown
+for the following 6 bindings are thus just examples of what
+they will probably be set to. If you have used the \f3stty\f1
+command to change these keys, then the default bindings
+should match.
+
+.nf
+ ^C -> user-interrupt
+ ^\\ -> abort
+ ^Z -> suspend
+ ^Q -> start-output
+ ^S -> stop-output
+ ^V -> literal-next
+ M-^C -> user-interrupt
+ M-^\\ -> abort
+ M-^Z -> suspend
+ M-^Q -> start-output
+ M-^S -> stop-output
+.fi
+
+Note that above, most of the bindings are defined twice, once
+as a raw control code like \f3^C\f1 and then a second time as
+a meta character like \f3M-^C\f1. The former is the binding
+for vi input mode, whereas the latter is the binding for vi
+command mode. Once in command mode all key-sequences that the
+user types that they don't explicitly start with an escape or
+a meta key, have their first key secretly converted to a meta
+character before the key sequence is looked up in the key
+binding table. Thus, once in command mode, when you type the
+letter \f3i\f1, for example, the Tecla library actually looks
+up the binding for \f3M-i\f1.
+
+The cursor keys are refered to by name, as follows. This is necessary
+because different types of terminals generate different key sequences
+when their cursor keys are pressed.
+
+ right -> cursor-right
+ left -> cursor-left
+ up -> up-history
+ down -> down-history
+
+The cursor keys normally generate a keysequence that start
+with an escape character, so beware that using the arrow keys
+will put you into command mode (if you aren't already in
+command mode).
+.sp
+The following are the terminal-independent key bindings for vi input
+mode.
+
+.nf
+ ^D -> list-or-eof
+ ^G -> list-glob
+ ^H -> backward-delete-char
+ ^I -> complete-word
+ \\r -> newline
+ \\n -> newline
+ ^L -> clear-screen
+ ^N -> down-history
+ ^P -> up-history
+ ^R -> redisplay
+ ^U -> backward-kill-line
+ ^W -> backward-delete-word
+ ^X* -> expand-filename
+ ^X^F -> read-from-file
+ ^X^R -> read-init-files
+ ^? -> backward-delete-char
+.fi
+
+The following are the key bindings that are defined in vi
+command mode, this being specified by them all starting with
+a meta character. As mentioned above, once in command mode
+the initial meta character is optional. For example, you
+might enter command mode by typing Esc, and then press h
+twice to move the cursor two positions to the left. Both h
+characters get quietly converted to M-h before being compared
+to the key-binding table, the first one because Escape
+followed by a character is always converted to the equivalent
+meta character, and the second because command mode was
+already active.
+
+.nf
+ M-\\ -> cursor-right (Meta-space)
+ M-$ -> end-of-line
+ M-* -> expand-filename
+ M-+ -> down-history
+ M-- -> up-history
+ M-< -> beginning-of-history
+ M-> -> end-of-history
+ M-^ -> beginning-of-line
+ M-; -> repeat-find-char
+ M-, -> invert-refind-char
+ M-| -> goto-column
+ M-~ -> change-case
+ M-. -> vi-repeat-change
+ M-% -> find-parenthesis
+ M-a -> vi-append
+ M-A -> vi-append-at-eol
+ M-b -> backward-word
+ M-B -> backward-word
+ M-C -> vi-change-rest-of-line
+ M-cb -> vi-backward-change-word
+ M-cB -> vi-backward-change-word
+ M-cc -> vi-change-line
+ M-ce -> vi-forward-change-word
+ M-cE -> vi-forward-change-word
+ M-cw -> vi-forward-change-word
+ M-cW -> vi-forward-change-word
+ M-cF -> vi-backward-change-find
+ M-cf -> vi-forward-change-find
+ M-cT -> vi-backward-change-to
+ M-ct -> vi-forward-change-to
+ M-c; -> vi-change-refind
+ M-c, -> vi-change-invert-refind
+ M-ch -> vi-backward-change-char
+ M-c^H -> vi-backward-change-char
+ M-c^? -> vi-backward-change-char
+ M-cl -> vi-forward-change-char
+ M-c\\ -> vi-forward-change-char (Meta-c-space)
+ M-c^ -> vi-change-to-bol
+ M-c0 -> vi-change-to-bol
+ M-c$ -> vi-change-rest-of-line
+ M-c| -> vi-change-to-column
+ M-c% -> vi-change-to-parenthesis
+ M-dh -> backward-delete-char
+ M-d^H -> backward-delete-char
+ M-d^? -> backward-delete-char
+ M-dl -> forward-delete-char
+ M-d -> forward-delete-char (Meta-d-space)
+ M-dd -> delete-line
+ M-db -> backward-delete-word
+ M-dB -> backward-delete-word
+ M-de -> forward-delete-word
+ M-dE -> forward-delete-word
+ M-dw -> forward-delete-word
+ M-dW -> forward-delete-word
+ M-dF -> backward-delete-find
+ M-df -> forward-delete-find
+ M-dT -> backward-delete-to
+ M-dt -> forward-delete-to
+ M-d; -> delete-refind
+ M-d, -> delete-invert-refind
+ M-d^ -> backward-kill-line
+ M-d0 -> backward-kill-line
+ M-d$ -> kill-line
+ M-D -> kill-line
+ M-d| -> delete-to-column
+ M-d% -> delete-to-parenthesis
+ M-e -> forward-word
+ M-E -> forward-word
+ M-f -> forward-find-char
+ M-F -> backward-find-char
+ M-- -> up-history
+ M-h -> cursor-left
+ M-H -> beginning-of-history
+ M-i -> vi-insert
+ M-I -> vi-insert-at-bol
+ M-j -> down-history
+ M-J -> history-search-forward
+ M-k -> up-history
+ M-K -> history-search-backward
+ M-l -> cursor-right
+ M-L -> end-of-history
+ M-n -> history-re-search-forward
+ M-N -> history-re-search-backward
+ M-p -> append-yank
+ M-P -> yank
+ M-r -> vi-replace-char
+ M-R -> vi-overwrite
+ M-s -> vi-forward-change-char
+ M-S -> vi-change-line
+ M-t -> forward-to-char
+ M-T -> backward-to-char
+ M-u -> vi-undo
+ M-w -> forward-to-word
+ M-W -> forward-to-word
+ M-x -> forward-delete-char
+ M-X -> backward-delete-char
+ M-yh -> backward-copy-char
+ M-y^H -> backward-copy-char
+ M-y^? -> backward-copy-char
+ M-yl -> forward-copy-char
+ M-y\\ -> forward-copy-char (Meta-y-space)
+ M-ye -> forward-copy-word
+ M-yE -> forward-copy-word
+ M-yw -> forward-copy-word
+ M-yW -> forward-copy-word
+ M-yb -> backward-copy-word
+ M-yB -> backward-copy-word
+ M-yf -> forward-copy-find
+ M-yF -> backward-copy-find
+ M-yt -> forward-copy-to
+ M-yT -> backward-copy-to
+ M-y; -> copy-refind
+ M-y, -> copy-invert-refind
+ M-y^ -> copy-to-bol
+ M-y0 -> copy-to-bol
+ M-y$ -> copy-rest-of-line
+ M-yy -> copy-line
+ M-Y -> copy-line
+ M-y| -> copy-to-column
+ M-y% -> copy-to-parenthesis
+ M-^E -> emacs-mode
+ M-^H -> cursor-left
+ M-^? -> cursor-left
+ M-^L -> clear-screen
+ M-^N -> down-history
+ M-^P -> up-history
+ M-^R -> redisplay
+ M-^D -> list-or-eof
+ M-^I -> complete-word
+ M-\\r -> newline
+ M-\\n -> newline
+ M-^X^R -> read-init-files
+ M-^Xh -> list-history
+
+ M-0, M-1, ... M-9 -> digit-argument (see below)
+.fi
+
+Note that \f3^I\f1 is what the TAB key generates.
+
+.SH ENTERING REPEAT COUNTS
+
+Many of the key binding functions described previously, take an
+optional count, typed in before the target keysequence. This is
+interpreted as a repeat count by most bindings. A notable exception is
+the goto-column binding, which interprets the count as a column
+number.
+.sp
+By default you can specify this count argument by pressing the meta
+key while typing in the numeric count. This relies on the
+\f3digit-argument\f1 action being bound to Meta-0, Meta-1 etc. Once
+any one of these bindings has been activated, you can optionally take
+your finger off the meta key to type in the rest of the number, since
+every numeric digit thereafter is treated as part of the number,
+unless it is preceded by the \f3literal-next\f1 binding. As soon as a
+non-digit, or literal digit key is pressed the repeat count is
+terminated and either causes the just typed character to be added to
+the line that many times, or causes the next key-binding function to
+be given that argument.
+.sp
+For example, in emacs mode, typing:
+.sp
+.nf
+ M-12a
+.fi
+.sp
+causes the letter 'a' to be added to the line 12 times,
+whereas
+.sp
+.nf
+ M-4M-c
+.fi
+.sp
+Capitalizes the next 4 words.
+.sp
+In vi command mode the Meta modifier is automatically added to all
+characters typed in, so to enter a count in vi command-mode, just
+involves typing in the number, just as it does in the vi editor
+itself. So for example, in vi command mode, typing:
+.sp
+.nf
+ 4w2x
+.fi
+.sp
+moves the cursor four words to the right, then deletes two characters.
+.sp
+You can also bind \f3digit-argument\f1 to other key sequences. If
+these end in a numeric digit, that digit gets appended to the current
+repeat count. If it doesn't end in a numeric digit, a new repeat count
+is started with a value of zero, and can be completed by typing in the
+number, after letting go of the key which triggered the digit-argument
+action.
+
+.SH FILES
+.nf
+libtecla.a - The Tecla library
+libtecla.h - The Tecla header file.
+~/.teclarc - The personal Tecla customization file.
+.fi
+
+.SH SEE ALSO
+
+.nf
+libtecla(@LIBR_MANEXT@), gl_get_line(@LIBR_MANEXT@), gl_io_mode(@LIBR_MANEXT@), ef_expand_file(@LIBR_MANEXT@),
+cpl_complete_word(@LIBR_MANEXT@), pca_lookup_file(@LIBR_MANEXT@)
+.fi
+
+.SH AUTHOR
+Martin Shepherd (mcs@astro.caltech.edu)
diff --git a/libtecla-1.4.1/man3/enhance.3 b/libtecla-1.6.1/man/prog/enhance.in
index 648ef34..a5c51a6 100644
--- a/libtecla-1.4.1/man3/enhance.3
+++ b/libtecla-1.6.1/man/prog/enhance.in
@@ -1,4 +1,4 @@
-.\" Copyright (C) 2000, 2001 by Martin C. Shepherd
+.\" Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd
.\"
.\" All rights reserved.
.\"
@@ -26,7 +26,7 @@
.\" shall not be used in advertising or otherwise to promote the sale, use
.\" or other dealings in this Software without prior written authorization
.\" of the copyright holder.
-.TH libtecla 3
+.TH enhance @PROG_MANEXT@
.SH NAME
enhance - A program that adds command-line editing to third party programs.
.SH SYNOPSIS
@@ -52,6 +52,9 @@ that the user has typed after it. Note that the small delay, which is
imperceptible to the user, isn't necessary for correct operation of
the program. It is just an optimization, designed to stop the input
line from being redisplayed so often that it slows down output.
+.sp
+Note that the user-level command-line editing facilities provided by
+the Tecla library are documented in the \f3tecla(@MISC_MANEXT@)\f1 man page
.SH DEFICIENCIES
@@ -80,7 +83,7 @@ libtecla.a - The tecla library.
.fi
.SH SEE ALSO
-libtecla(3)
+tecla(@MISC_MANEXT@), libtecla(@LIBR_MANEXT@)
.SH AUTHOR
Martin Shepherd (mcs@astro.caltech.edu)
diff --git a/libtecla-1.4.1/pathutil.c b/libtecla-1.6.1/pathutil.c
index 015504b..7d3e95c 100644
--- a/libtecla-1.4.1/pathutil.c
+++ b/libtecla-1.6.1/pathutil.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2001 by Martin C. Shepherd.
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
*
* All rights reserved.
*
@@ -29,11 +29,18 @@
* of the copyright holder.
*/
+/*
+ * If file-system access is to be excluded, this module has no function,
+ * so all of its code should be excluded.
+ */
+#ifndef WITHOUT_FILE_SYSTEM
+
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>
+#include <limits.h>
#include <unistd.h>
#include <sys/types.h>
@@ -53,9 +60,9 @@ PathName *_new_PathName(void)
/*
* Allocate the container.
*/
- path = (PathName *)malloc(sizeof(PathName));
+ path = (PathName *) malloc(sizeof(PathName));
if(!path) {
- fprintf(stderr, "_new_PathName: Insufficient memory.\n");
+ errno = ENOMEM;
return NULL;
};
/*
@@ -76,8 +83,7 @@ PathName *_new_PathName(void)
*/
path->name = (char *)malloc(path->dim * sizeof(char));
if(!path->name) {
- fprintf(stderr,
- "_new_PathName: Insufficient memory to allocate pathname buffer.\n");
+ errno = ENOMEM;
return _del_PathName(path);
};
return path;
@@ -115,7 +121,7 @@ char *_pn_clear_path(PathName *path)
* Check the arguments.
*/
if(!path) {
- fprintf(stderr, "_pn_clear_path: NULL argument.\n");
+ errno = EINVAL;
return NULL;
};
path->name[0] = '\0';
@@ -150,7 +156,7 @@ char *_pn_append_to_path(PathName *path, const char *string, int slen,
* Check the arguments.
*/
if(!path || !string) {
- fprintf(stderr, "_pn_append_to_path: NULL argument(s).\n");
+ errno = EINVAL;
return NULL;
};
/*
@@ -221,7 +227,7 @@ char *_pn_prepend_to_path(PathName *path, const char *string, int slen,
* Check the arguments.
*/
if(!path || !string) {
- fprintf(stderr, "_pn_prepend_to_path: NULL argument(s).\n");
+ errno = EINVAL;
return NULL;
};
/*
@@ -285,8 +291,7 @@ char *_pn_prepend_to_path(PathName *path, const char *string, int slen,
* not including the terminating '\0'.
* Output:
* return char * The pathname buffer, or NULL if there was
- * insufficient memory (this isn't reported
- * to stderr).
+ * insufficient memory.
*/
char *_pn_resize_path(PathName *path, size_t length)
{
@@ -294,7 +299,7 @@ char *_pn_resize_path(PathName *path, size_t length)
* Check the arguments.
*/
if(!path) {
- fprintf(stderr, "_pn_resize_path: NULL argument(s).\n");
+ errno = EINVAL;
return NULL;
};
/*
@@ -443,7 +448,7 @@ char *_pu_start_of_path(const char *string, int back_from)
* Check the arguments.
*/
if(!string || back_from < 0) {
- fprintf(stderr, "_pu_start_path: Invalid argument(s).\n");
+ errno = EINVAL;
return NULL;
};
/*
@@ -498,7 +503,7 @@ char *_pu_end_of_path(const char *string, int start_from)
* Check the arguments.
*/
if(!string || start_from < 0) {
- fprintf(stderr, "_pu_end_path: Invalid argument(s).\n");
+ errno = EINVAL;
return NULL;
};
/*
@@ -530,3 +535,5 @@ int _pu_file_exists(const char *pathname)
struct stat statbuf;
return stat(pathname, &statbuf) == 0;
}
+
+#endif /* ifndef WITHOUT_FILE_SYSTEM */
diff --git a/libtecla-1.4.1/pathutil.h b/libtecla-1.6.1/pathutil.h
index 2f4ece5..5454d91 100644
--- a/libtecla-1.4.1/pathutil.h
+++ b/libtecla-1.6.1/pathutil.h
@@ -2,7 +2,7 @@
#define pathutil_h
/*
- * Copyright (c) 2000, 2001 by Martin C. Shepherd.
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
*
* All rights reserved.
*
diff --git a/libtecla-1.4.1/pcache.c b/libtecla-1.6.1/pcache.c
index bbea916..74e4ef5 100644
--- a/libtecla-1.4.1/pcache.c
+++ b/libtecla-1.6.1/pcache.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2001 by Martin C. Shepherd.
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
*
* All rights reserved.
*
@@ -29,9 +29,16 @@
* of the copyright holder.
*/
+/*
+ * If file-system access is to be excluded, this module has no function,
+ * so all of its code should be excluded.
+ */
+#ifndef WITHOUT_FILE_SYSTEM
+
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
+#include <errno.h>
#include "libtecla.h"
#include "pathutil.h"
@@ -39,6 +46,7 @@
#include "freelist.h"
#include "direader.h"
#include "stringrp.h"
+#include "errmsg.h"
/*
* The new_PcaPathConf() constructor sets the integer first member of
@@ -123,14 +131,6 @@ struct PathNode {
static int add_PathNode(PathCache *pc, const char *dirname);
/*
- * Set the max length of the error-reporting string. There is no point
- * in this being longer than the width of a typical terminal window.
- * In composing error messages, I have assumed that this number is
- * at least 80, so you don't decrease it below this number.
- */
-#define ERRLEN 200
-
-/*
* Set the maximum length allowed for usernames.
* names.
*/
@@ -141,6 +141,7 @@ static int add_PathNode(PathCache *pc, const char *dirname);
* files of interest from comma-separated lists of directories.
*/
struct PathCache {
+ ErrMsg *err; /* The error reporting buffer */
FreeList *node_mem; /* A free-list of PathNode objects */
CacheMem *abs_mem; /* Memory for the filenames of absolute paths */
CacheMem *rel_mem; /* Memory for the filenames of relative paths */
@@ -158,7 +159,6 @@ struct PathCache {
void *data; /* Annonymous data to be passed to pc->check_fn() */
char usrnam[USR_LEN+1];/* The buffer used when reading the names of */
/* users. */
- char errmsg[ERRLEN+1]; /* Error-report buffer */
};
/*
@@ -265,7 +265,7 @@ PathCache *new_PathCache(void)
*/
pc = (PathCache *)malloc(sizeof(PathCache));
if(!pc) {
- fprintf(stderr, "new_PathCache: Insufficient memory.\n");
+ errno = ENOMEM;
return NULL;
};
/*
@@ -273,6 +273,7 @@ PathCache *new_PathCache(void)
* container at least up to the point at which it can safely be passed
* to del_PathCache().
*/
+ pc->err = NULL;
pc->node_mem = NULL;
pc->abs_mem = NULL;
pc->rel_mem = NULL;
@@ -285,12 +286,16 @@ PathCache *new_PathCache(void)
pc->check_fn = 0;
pc->data = NULL;
pc->usrnam[0] = '\0';
- pc->errmsg[0] = '\0';
+/*
+ * Allocate a place to record error messages.
+ */
+ pc->err = _new_ErrMsg();
+ if(!pc->err)
+ return del_PathCache(pc);
/*
* Allocate the freelist of directory list nodes.
*/
- pc->node_mem = _new_FreeList("new_PathCache", sizeof(PathNode),
- PATH_NODE_BLK);
+ pc->node_mem = _new_FreeList(sizeof(PathNode), PATH_NODE_BLK);
if(!pc->node_mem)
return del_PathCache(pc);
/*
@@ -353,9 +358,13 @@ PathCache *del_PathCache(PathCache *pc)
{
if(pc) {
/*
+ * Delete the error message buffer.
+ */
+ pc->err = _del_ErrMsg(pc->err);
+/*
* Delete the memory of the list of path nodes.
*/
- pc->node_mem = _del_FreeList(NULL, pc->node_mem, 1);
+ pc->node_mem = _del_FreeList(pc->node_mem, 1);
/*
* Delete the memory used to record filenames.
*/
@@ -447,7 +456,7 @@ void pca_set_check_fn(PathCache *pc, CplCheckFn *check_fn, void *data)
*/
const char *pca_last_error(PathCache *pc)
{
- return pc ? pc->errmsg : "NULL PathCache argument";
+ return pc ? _err_get_msg(pc->err) : "NULL PathCache argument";
}
/*.......................................................................
@@ -562,7 +571,7 @@ int pca_scan_path(PathCache *pc, const char *path)
* Output:
* return int 0 - OK. The extracted path is in pc->path->name.
* 1 - Error. A description of the error will
- * have been left in pc->errmsg.
+ * have been left in pc->err.
*/
static int pca_extract_dir(PathCache *pc, const char *path, const char **nextp)
{
@@ -591,7 +600,8 @@ static int pca_extract_dir(PathCache *pc, const char *path, const char **nextp)
* Append the rest of the directory path to the pathname buffer.
*/
if(_pn_append_to_path(pc->path, sptr, pptr - sptr, 1) == NULL) {
- strcpy(pc->errmsg, "Insufficient memory to record directory name");
+ _err_record_msg(pc->err, "Insufficient memory to record directory name",
+ END_ERR_MSG);
return 1;
};
/*
@@ -605,7 +615,8 @@ static int pca_extract_dir(PathCache *pc, const char *path, const char **nextp)
strncmp(pc->path->name + dirlen - FS_DIR_SEP_LEN, FS_DIR_SEP,
FS_DIR_SEP_LEN) != 0) {
if(_pn_append_to_path(pc->path, FS_DIR_SEP, FS_DIR_SEP_LEN, 0) == NULL) {
- strcpy(pc->errmsg, "Insufficient memory to record directory name");
+ _err_record_msg(pc->err, "Insufficient memory to record directory name",
+ END_ERR_MSG);
return 1;
};
};
@@ -639,7 +650,7 @@ static int pca_extract_dir(PathCache *pc, const char *path, const char **nextp)
* Output:
* return int 0 - OK. The username can be found in pc->usrnam.
* 1 - Error. A description of the error message
- * can be found in pc->errmsg.
+ * can be found in pc->err.
*/
static int pca_read_username(PathCache *pc, const char *string, int slen,
int literal, const char **nextp)
@@ -672,7 +683,7 @@ static int pca_read_username(PathCache *pc, const char *string, int slen,
* Did the username overflow the buffer?
*/
if(usrlen >= USR_LEN) {
- strcpy(pc->errmsg, "Username too long");
+ _err_record_msg(pc->err, "Username too long", END_ERR_MSG);
return 1;
};
/*
@@ -701,7 +712,7 @@ static CacheMem *new_CacheMem(void)
*/
cm = (CacheMem *)malloc(sizeof(CacheMem));
if(!cm) {
- fprintf(stderr, "new_CacheMem: Insufficient memory.\n");
+ errno = ENOMEM;
return NULL;
};
/*
@@ -726,8 +737,7 @@ static CacheMem *new_CacheMem(void)
cm->files_dim = FILES_BLK_FACT;
cm->files = (char **) malloc(sizeof(*cm->files) * cm->files_dim);
if(!cm->files) {
- fprintf(stderr,
- "new_CacheMem: Insufficient memory to allocate array of files.\n");
+ errno = ENOMEM;
return del_CacheMem(cm);
};
return cm;
@@ -807,7 +817,8 @@ static int add_PathNode(PathCache *pc, const char *dirname)
*/
node = (PathNode *) _new_FreeListNode(pc->node_mem);
if(!node) {
- sprintf(pc->errmsg, "Insufficient memory to cache new directory.");
+ _err_record_msg(pc->err, "Insufficient memory to cache new directory.",
+ END_ERR_MSG);
return 1;
};
/*
@@ -824,7 +835,8 @@ static int add_PathNode(PathCache *pc, const char *dirname)
*/
node->dir = _sg_store_string(pc->abs_mem->sg, dirname, 0);
if(!node->dir) {
- strcpy(pc->errmsg, "Insufficient memory to store directory name.");
+ _err_record_msg(pc->err, "Insufficient memory to store directory name.",
+ END_ERR_MSG);
return 1;
};
/*
@@ -887,7 +899,8 @@ static int pca_scan_dir(PathCache *pc, const char *dirname, CacheMem *mem)
_pn_clear_path(pc->path);
if(_pn_append_to_path(pc->path, " ", 1, 0) == NULL ||
_pn_append_to_path(pc->path, filename, -1, 1) == NULL) {
- strcpy(pc->errmsg, "Insufficient memory to record filename");
+ _err_record_msg(pc->err, "Insufficient memory to record filename",
+ END_ERR_MSG);
return -1;
};
/*
@@ -895,7 +908,8 @@ static int pca_scan_dir(PathCache *pc, const char *dirname, CacheMem *mem)
*/
copy = _sg_store_string(mem->sg, pc->path->name, 0);
if(!copy) {
- strcpy(pc->errmsg, "Insufficient memory to cache file name.");
+ _err_record_msg(pc->err, "Insufficient memory to cache file name.",
+ END_ERR_MSG);
return -1;
};
/*
@@ -909,7 +923,9 @@ static int pca_scan_dir(PathCache *pc, const char *dirname, CacheMem *mem)
int needed = mem->files_dim + FILES_BLK_FACT;
char **files = (char **) realloc(mem->files, sizeof(*mem->files)*needed);
if(!files) {
- strcpy(pc->errmsg, "Insufficient memory to extend filename cache.");
+ _err_record_msg(pc->err,
+ "Insufficient memory to extend filename cache.",
+ END_ERR_MSG);
return 1;
};
mem->files = files;
@@ -1122,7 +1138,7 @@ PcaPathConf *new_PcaPathConf(PathCache *pc)
*/
ppc = (PcaPathConf *)malloc(sizeof(PcaPathConf));
if(!ppc) {
- strcpy(pc->errmsg, "Insufficient memory.");
+ _err_record_msg(pc->err, "Insufficient memory.", END_ERR_MSG);
return NULL;
};
/*
@@ -1329,7 +1345,8 @@ CPL_MATCH_FN(pca_path_completions)
_pn_clear_path(pc->path);
if(_pn_append_to_path(pc->path, node->dir, -1, 0) == NULL ||
_pn_append_to_path(pc->path, match+1, -1, 0) == NULL) {
- strcpy(pc->errmsg, "Insufficient memory to complete file name");
+ _err_record_msg(pc->err, "Insufficient memory to complete file name",
+ END_ERR_MSG);
return 1;
};
/*
@@ -1447,7 +1464,8 @@ static int pca_prepare_suffix(PathCache *pc, const char *suffix,
* both the suffix and any backslashes that have to be inserted.
*/
if(_pn_resize_path(pc->path, suffix_len + nbsl) == NULL) {
- strcpy(pc->errmsg, "Insufficient memory to complete file name");
+ _err_record_msg(pc->err, "Insufficient memory to complete file name",
+ END_ERR_MSG);
return 1;
};
/*
@@ -1531,7 +1549,7 @@ static int cpa_cmd_contains_path(const char *prefix, int prefix_len)
* Output:
* return const char * The prepared prefix, or NULL on error, in
* which case an error message will have been
- * left in pc->errmsg.
+ * left in pc->err.
*/
static const char *pca_prepare_prefix(PathCache *pc, const char *prefix,
size_t prefix_len, int escaped)
@@ -1542,7 +1560,8 @@ static const char *pca_prepare_prefix(PathCache *pc, const char *prefix,
if(escaped) {
_pn_clear_path(pc->path);
if(_pn_append_to_path(pc->path, prefix, prefix_len, 1) == NULL) {
- strcpy(pc->errmsg, "Insufficient memory to complete filename");
+ _err_record_msg(pc->err, "Insufficient memory to complete filename",
+ END_ERR_MSG);
return NULL;
};
return pc->path->name;
@@ -1605,7 +1624,7 @@ void ppc_file_start(PcaPathConf *ppc, int start_index)
* Output:
* return int 0 - OK
* 1 - Error (a description will have been placed
- * in pc->errmsg[]).
+ * in pc->err).
*/
static int pca_expand_tilde(PathCache *pc, const char *path, int pathlen,
int literal, const char **endp)
@@ -1632,15 +1651,16 @@ static int pca_expand_tilde(PathCache *pc, const char *path, int pathlen,
*/
homedir = _hd_lookup_home_dir(pc->home, pc->usrnam);
if(!homedir) {
- strncpy(pc->errmsg, _hd_last_home_dir_error(pc->home), ERRLEN);
- pc->errmsg[ERRLEN] = '\0';
+ _err_record_msg(pc->err, _hd_last_home_dir_error(pc->home), END_ERR_MSG);
return 1;
};
/*
* Append the home directory to the pathname string.
*/
if(_pn_append_to_path(pc->path, homedir, -1, 0) == NULL) {
- strcpy(pc->errmsg, "Insufficient memory for home directory expansion");
+ _err_record_msg(pc->err,
+ "Insufficient memory for home directory expansion",
+ END_ERR_MSG);
return 1;
};
};
@@ -1686,3 +1706,5 @@ static void pca_remove_marks(PathCache *pc)
};
return;
}
+
+#endif /* ifndef WITHOUT_FILE_SYSTEM */
diff --git a/libtecla-1.4.1/stringrp.c b/libtecla-1.6.1/stringrp.c
index fe7d875..2d84766 100644
--- a/libtecla-1.4.1/stringrp.c
+++ b/libtecla-1.6.1/stringrp.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2001 by Martin C. Shepherd.
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
*
* All rights reserved.
*
@@ -31,6 +31,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#include <errno.h>
#include "freelist.h"
#include "stringrp.h"
@@ -82,7 +83,7 @@ StringGroup *_new_StringGroup(int segment_size)
* Check the arguments.
*/
if(segment_size < 1) {
- fprintf(stderr, "_new_StringGroup: Invalid segment_size argument.\n");
+ errno = EINVAL;
return NULL;
};
/*
@@ -90,7 +91,7 @@ StringGroup *_new_StringGroup(int segment_size)
*/
sg = (StringGroup *) malloc(sizeof(StringGroup));
if(!sg) {
- fprintf(stderr, "_new_StringGroup: Insufficient memory.\n");
+ errno = ENOMEM;
return NULL;
};
/*
@@ -104,8 +105,7 @@ StringGroup *_new_StringGroup(int segment_size)
/*
* Allocate the free list that is used to allocate list nodes.
*/
- sg->node_mem = _new_FreeList("_new_StringGroup", sizeof(StringSegment),
- STR_SEG_BLK);
+ sg->node_mem = _new_FreeList(sizeof(StringSegment), STR_SEG_BLK);
if(!sg->node_mem)
return _del_StringGroup(sg);
return sg;
@@ -134,7 +134,7 @@ StringGroup *_del_StringGroup(StringGroup *sg)
/*
* Delete the list nodes that contained the string segments.
*/
- sg->node_mem = _del_FreeList("_del_StringGroup", sg->node_mem, 1);
+ sg->node_mem = _del_FreeList(sg->node_mem, 1);
sg->head = NULL; /* Already deleted by deleting sg->node_mem */
/*
* Delete the container.
@@ -226,7 +226,8 @@ char *_sg_alloc_string(StringGroup *sg, int length)
return NULL;
/*
* See if there is room to record the string in one of the existing
- * string segments.
+ * string segments. Do this by advancing the node pointer until we find
+ * a node with length+1 bytes unused, or we get to the end of the list.
*/
for(node=sg->head; node && node->unused <= length; node=node->next)
;
diff --git a/libtecla-1.4.1/stringrp.h b/libtecla-1.6.1/stringrp.h
index 8b15ce9..c5fdd3a 100644
--- a/libtecla-1.4.1/stringrp.h
+++ b/libtecla-1.6.1/stringrp.h
@@ -1,7 +1,7 @@
#ifndef stringrp_h
#define stringrp_h
/*
- * Copyright (c) 2000, 2001 by Martin C. Shepherd.
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
*
* All rights reserved.
*
diff --git a/libtecla-1.4.1/strngmem.c b/libtecla-1.6.1/strngmem.c
index fedf4ff..c2637ec 100644
--- a/libtecla-1.4.1/strngmem.c
+++ b/libtecla-1.6.1/strngmem.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2001 by Martin C. Shepherd.
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
*
* All rights reserved.
*
@@ -31,6 +31,7 @@
#include <stdlib.h>
#include <stdio.h>
+#include <errno.h>
#include "strngmem.h"
#include "freelist.h"
@@ -44,8 +45,6 @@ struct StringMem {
* Create a string free-list container and the first block of its free-list.
*
* Input:
- * caller const char * The name of the calling function, or NULL
- * to not report errors to stderr.
* blocking_factor int The blocking_factor argument specifies how
* many strings of length SM_STRLEN
* bytes (see stringmem.h) are allocated in each
@@ -57,17 +56,14 @@ struct StringMem {
* return StringMem * The new free-list container, or NULL on
* error.
*/
-StringMem *_new_StringMem(const char *caller, unsigned blocking_factor)
+StringMem *_new_StringMem(unsigned blocking_factor)
{
StringMem *sm; /* The container to be returned. */
/*
* Check arguments.
*/
if(blocking_factor < 1) {
- if(caller) {
- fprintf(stderr, "_new_StringMem (%s): Bad blocking factor (%d).\n",
- caller, blocking_factor);
- };
+ errno = EINVAL;
return NULL;
};
/*
@@ -75,8 +71,7 @@ StringMem *_new_StringMem(const char *caller, unsigned blocking_factor)
*/
sm = (StringMem *) malloc(sizeof(StringMem));
if(!sm) {
- if(caller)
- fprintf(stderr, "_new_StringMem (%s): Insufficient memory.\n", caller);
+ errno = ENOMEM;
return NULL;
};
/*
@@ -89,9 +84,9 @@ StringMem *_new_StringMem(const char *caller, unsigned blocking_factor)
/*
* Allocate the free-list.
*/
- sm->fl = _new_FreeList(caller, SM_STRLEN, blocking_factor);
+ sm->fl = _new_FreeList(SM_STRLEN, blocking_factor);
if(!sm->fl)
- return _del_StringMem(caller, sm, 1);
+ return _del_StringMem(sm, 1);
/*
* Return the free-list container.
*/
@@ -102,8 +97,6 @@ StringMem *_new_StringMem(const char *caller, unsigned blocking_factor)
* Delete a string free-list.
*
* Input:
- * caller const char * The name of the calling function, or NULL to
- * not report errors to stderr.
* sm StringMem * The string free-list to be deleted, or NULL.
* force int If force==0 then _del_StringMem() will complain
* and refuse to delete the free-list if any
@@ -115,21 +108,20 @@ StringMem *_new_StringMem(const char *caller, unsigned blocking_factor)
* return StringMem * Always NULL (even if the list couldn't be
* deleted).
*/
-StringMem *_del_StringMem(const char *caller, StringMem *sm, int force)
+StringMem *_del_StringMem(StringMem *sm, int force)
{
if(sm) {
/*
* Check whether any strings have not been returned to the free-list.
*/
if(!force && (sm->nmalloc > 0 || _busy_FreeListNodes(sm->fl) > 0)) {
- if(caller)
- fprintf(stderr, "_del_StringMem (%s): Free-list in use.\n", caller);
+ errno = EBUSY;
return NULL;
};
/*
* Delete the free-list.
*/
- sm->fl = _del_FreeList(caller, sm->fl, force);
+ sm->fl = _del_FreeList(sm->fl, force);
/*
* Delete the container.
*/
diff --git a/libtecla-1.4.1/strngmem.h b/libtecla-1.6.1/strngmem.h
index 5737ae0..9efef09 100644
--- a/libtecla-1.4.1/strngmem.h
+++ b/libtecla-1.6.1/strngmem.h
@@ -1,7 +1,7 @@
#ifndef stringmem_h
#define stringmem_h
/*
- * Copyright (c) 2000, 2001 by Martin C. Shepherd.
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
*
* All rights reserved.
*
@@ -60,12 +60,12 @@ typedef struct StringMem StringMem;
/*
* Create a string free-list container and the first block of its free-list.
*/
-StringMem *_new_StringMem(const char *caller, unsigned blocking_factor);
+StringMem *_new_StringMem(unsigned blocking_factor);
/*
* Delete a string free-list.
*/
-StringMem *_del_StringMem(const char *caller, StringMem *sm, int force);
+StringMem *_del_StringMem(StringMem *sm, int force);
/*
* Allocate an array of 'length' chars.
diff --git a/libtecla-1.6.1/update_html b/libtecla-1.6.1/update_html
new file mode 100755
index 0000000..70f189e
--- /dev/null
+++ b/libtecla-1.6.1/update_html
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+# Convert man pages to html files.
+
+for dir in man/prog man/libr man/func man/misc man/file; do
+ for template in $dir/*.in;do
+ page=`basename "$template" .in`
+ if [ `wc -l < $template` -gt 1 ]; then
+ html="html/$page.html"
+ man2html $template > $html
+ for ref in libtecla cpl_complete_word ef_expand_file gl_get_line pca_lookup_file enhance gl_io_mode tecla; do
+ link="$ref.html"
+ ed -s $html << EOF
+ %s|$ref[(][^)][^) ]*[)]|<a href="$link"><b>$ref</b></a>|g
+ w
+ q
+EOF
+ done
+ fi
+ done
+done
+
+# Convert the change log into a web page.
+
+cd html
+echo '<html><head><title>The tecla library change log</title></head>' > changes.html
+echo '<body bgcolor="#add8e6"><pre>' >> changes.html
+sed 's/&/&amp;/g; s/</\&lt;/g; s/>/\&gt;/g' ../CHANGES >> changes.html
+echo '</pre></body></html>' >> changes.html
+
+# Do the same to the release-notes file.
+
+cd ../html
+echo '<html><head><title>The tecla library release notes</title></head>' > release.html
+echo '<body bgcolor="#add8e6"><pre>' >> release.html
+sed 's/&/&amp;/g; s/</\&lt;/g' ../RELEASE.NOTES >> release.html
+echo '</pre></body></html>' >> release.html
diff --git a/libtecla-1.4.1/update_version b/libtecla-1.6.1/update_version
index c18f714..c18f714 100755
--- a/libtecla-1.4.1/update_version
+++ b/libtecla-1.6.1/update_version
diff --git a/libtecla-1.4.1/version.c b/libtecla-1.6.1/version.c
index 9e1275e..9e1275e 100644
--- a/libtecla-1.4.1/version.c
+++ b/libtecla-1.6.1/version.c