pax_global_header00006660000000000000000000000064147164323640014524gustar00rootroot0000000000000052 comment=74faea1656a74bdf489f1143bc859e6e2d226548 ossp-iselect-ISELECT_1_4_2/000077500000000000000000000000001471643236400154545ustar00rootroot00000000000000ossp-iselect-ISELECT_1_4_2/.builds/000077500000000000000000000000001471643236400170145ustar00rootroot00000000000000ossp-iselect-ISELECT_1_4_2/.builds/freebsd-latest.yml000066400000000000000000000003531471643236400224440ustar00rootroot00000000000000# SPDX-License-Identifier: 0BSD image: freebsd/latest packages: - gmake - autoconf - automake tasks: - build: | cd ossp-iselect autoreconf -fi ./configure make # make check sudo make install ossp-iselect-ISELECT_1_4_2/.builds/openbsd-latest.yml000066400000000000000000000014231471643236400224630ustar00rootroot00000000000000# SPDX-License-Identifier: 0BSD image: openbsd/latest packages: - gmake tasks: - prep-autohell: | doas pkg_add $(doas pkg_add autoconf 2>&1 | grep -o 'autoconf-[0-9a-z.]*' | sort -rV | { read -r pkg; echo $pkg; }) \ $(doas pkg_add automake 2>&1 | grep -o 'automake-[0-9a-z.]*' | sort -rV | { read -r pkg; echo $pkg; }) printf 'export %s_VERSION=%s\n' AUTOCONF "$(printf '%s\n' /usr/local/bin/autoreconf-* | sort -rV | { IFS=- read -r _ v; echo $v; })" \ AUTOMAKE "$(printf '%s\n' /usr/local/bin/automake-* | sort -rV | { IFS=- read -r _ v; echo $v; })" >> .buildenv - build: | cd ossp-iselect autoreconf-$AUTOCONF_VERSION -fi ./configure make # make check doas make install ossp-iselect-ISELECT_1_4_2/.builds/sid.yml000066400000000000000000000042761471643236400203270ustar00rootroot00000000000000# SPDX-License-Identifier: 0BSD image: debian/sid secrets: - f3299a6b-f359-4843-a150-9bd838f82255 # ossp-iselect SSH key packages: - clang - lld - libncurses-dev - autoconf - automake - groff - ghostscript tasks: - autoreconf: | autoreconf -fi ossp-iselect mkdir -p ossp-iselect/gcc ossp-iselect/clang - build-gcc: | cd ossp-iselect/gcc ../configure make # make check make distclean - build-clang: | cd ossp-iselect/clang ../configure CC=clang CXX=clang++ LDFLAGS=-fuse-ld=lld make # make check - install: | sudo make -C ossp-iselect/clang install - manual: | sudo sh -c 'curl https://git.sr.ht/~nabijaczleweli/groff-1.23-unfucking/blob/trunk/mdoc.local >> /etc/groff/mdoc.local' git -C ossp-iselect/ worktree add ../ossp-iselect-man man cd ossp-iselect-man git ls-tree -z --name-only HEAD | xargs -0 rm -r cp ../ossp-iselect/clang/*.[1-8] . sed -e 's/…/.../g' $(printf '%s\n' *.[0-8] | awk -F. '{print $2 "\t" $0}' | sort | cut -f2) | groff -K utf8 -tpe -mdoc -Tps -dpaper=a4 -P-pa4 > ossp-iselect.ps ps2pdf ossp-iselect.ps ossp-iselect.pdf git add . git config user.email "nabijaczleweli/autouploader@nabijaczleweli.xyz" git config user.name "наб autouploader" git commit -m "Manpage update by job $JOB_ID" || exit 0 git remote set-url origin 'git@git.sr.ht:~nabijaczleweli/ossp-iselect' ssh-keyscan git.sr.ht > ~/.ssh/known_hosts git push - void: | curl https://repo-default.voidlinux.org/live/current/sha256sum.txt | grep -w tar | grep -w x86_64 | grep -m1 musl > sha256sum.txt curl -SL https://repo-default.voidlinux.org/live/current/"$(awk -F'[( )]' '{print $3}' < sha256sum.txt)" | tar -xJ cp /etc/resolv.conf etc printf '%s\n' 'xbps-install -yS' \ 'xbps-install -yu xbps' \ 'xbps-install -yu' \ 'xbps-install -y make gcc ncurses-devel' \ 'cd ossp-iselect' \ './configure' \ 'make VERSION=sid.yml SOURCE_DATE_EPOCH=0 all # check' \ 'make install' | sudo chroot . sh -ex ossp-iselect-ISELECT_1_4_2/.gitignore000066400000000000000000000002251471643236400174430ustar00rootroot00000000000000Makefile configure config.* iselect iselect.1 example/screen-ir/screen-ir.1 *.o *~ autom4te.cache iselect_help.c iselect_readme.c iselect_readme.txt ossp-iselect-ISELECT_1_4_2/LICENSES/000077500000000000000000000000001471643236400166615ustar00rootroot00000000000000ossp-iselect-ISELECT_1_4_2/LICENSES/0BSD.txt000066400000000000000000000011371471643236400201140ustar00rootroot00000000000000Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 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. ossp-iselect-ISELECT_1_4_2/LICENSES/GPL-2.0-only.txt000066400000000000000000000431271471643236400213270ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program 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 (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. ossp-iselect-ISELECT_1_4_2/LICENSES/GPL-2.0-or-later.txt000077700000000000000000000000001471643236400245162GPL-2.0-only.txtustar00rootroot00000000000000ossp-iselect-ISELECT_1_4_2/Makefile.in000066400000000000000000000025001471643236400175160ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-2.0-only VPATH = @srcdir@ CC = @CC@ CXX = @CXX@ CPPFLAGS= @CPPFLAGS@ -I@srcdir@ -I. -D_GNU_SOURCE CFLAGS = @CFLAGS@ -Wall -Wextra -Wwrite-strings -Wcast-qual -Wno-switch -pedantic CXXFLAGS= @CXXFLAGS@ -Wall -Wextra -std=c++2b LDFLAGS = @LDFLAGS@ LDLIBS = @LIBS@ prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ mandir = ${exec_prefix}/man all: iselect iselect: iselect_main.o iselect_browse.o iselect_keys.o iselect_help.o iselect_readme.o enter.o dokey.o $(CC) $(LDFLAGS) -o $@ iselect_main.o iselect_browse.o iselect_keys.o iselect_help.o iselect_readme.o enter.o dokey.o $(LDLIBS) iselect_main.o iselect_browse.o iselect_keys.o iselect_help.o iselect_readme.o: *.h iselect_help.c: iselect_help.txt @srcdir@/asc2c <@srcdir@/iselect_help.txt >iselect_help.c iSelect_Help iselect_readme.c: iselect_readme.txt @srcdir@/asc2c iselect_readme.c iSelect_README install: all mkdir -p $(bindir) $(mandir)/man1 install -c -m 755 iselect $(bindir)/iselect install -c -m 644 iselect.1 $(mandir)/man1/iselect.1 clean: -rm -f iselect_help.c iselect_readme.c -rm -f *.o -rm -f iselect -rm -f core *.core distclean: clean -rm -f config.* *~ -rm -f Makefile iselect_readme.txt iselect.1 example/screen-ir/screen-ir.1 ossp-iselect-ISELECT_1_4_2/README000066400000000000000000000043151471643236400163370ustar00rootroot00000000000000 _ ____ _ _ (_) ___| ___| | ___ ___| |_ / /\___ \ / _ \ |/ _ \/ __| __| / / ___) | __/ | __/ (__| |_ (_( |____/ \___|_|\___|\___|\__| iSelect -- Interactive Selection Tool iSelect is an interactive line selection tool, operating via a full-screen Curses-based terminal session. It can be used either as a user interface frontend controlled by a shell/Perl/Tcl backend as its control script, or in batch mode as a pipe filter (usually between grep and the final executing command). Version 1.4.2 (2024-11-17) This is a thawed OSSP project; for git repository/bug tracker/mailing list see https://sr.ht/~nabijaczleweli/ossp The manual is available on-line and at https://srhtcdn.githack.com/~nabijaczleweli/ossp-iselect/blob/man/ossp-iselect.pdf Release tarballs are signed with nabijaczleweli@nabijaczleweli.xyz (pull with WKD, but 7D69 474E 8402 8C5C C0C4 4163 BCFD 0B01 8D26 58F1). аnd stored in git notes as-if via the example program provided at https://man.sr.ht/git.sr.ht/#signing-tags-tarballs and are thus available on the refs listing/tag page as .tar.gz{,.asc}: https://git.sr.ht/~nabijaczleweli/ossp-uuid/refs Wants wide-character curses, a recent C/C++ compiler, and autoconf/automake: $ autoreconf -fi $ ./configure [--with-examples-at=.Pa /usr/share/...] [autoconf variables]... # the default is .Lk to upstream examples $ make ... The latest release can be found on http://www.ossp.org/pkg/tool/iselect/ Copyright (c) 1997-2007 Ralf S. Engelschall This program is free software; it may be redistributed and/or modified only under the terms of the GNU General Public License, which may be found in the iSelect source distribution. Look at the file LICENSES/GPL-2.0-only.txt for details. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the the GNU General Public License for more details. Ralf S. Engelschall rse@engelschall.com www.engelschall.com ossp-iselect-ISELECT_1_4_2/asc2c000077500000000000000000000004171471643236400163770ustar00rootroot00000000000000#!/bin/sh # SPDX-License-Identifier: 0BSD printf '#include "iselect.h"\n' printf '#pragma GCC diagnostic ignored "-Wcast-qual"\n' printf 'const Line %s[] = {\n' "$1" sed '1d;s/\\/&&/g;s/^/"/;s/$/"/;s/.*/{.cpLine = (char *)&, .nLine = sizeof(&) - 1},/' printf '{0} };\n' ossp-iselect-ISELECT_1_4_2/configure.ac000066400000000000000000000036311471643236400177450ustar00rootroot00000000000000dnl ## SPDX-License-Identifier: GPL-2.0-only dnl ## Copyright (c) Ralf S. Engelschall AC_PREREQ([2.71]) AC_INIT ISELECT_VERSION_RAW="1.4.2" ISELECT_VERSION_DATE="2024-11-17" ISELECT_VERSION_MDOC_DATE="November 17, 2024" ISELECT_VERSION_LONG="$ISELECT_VERSION_RAW ($ISELECT_VERSION_DATE)" ISELECT_VERSION_STR="This is iSelect, Version $ISELECT_VERSION_LONG" AC_DEFINE_UNQUOTED(ISELECT_VERSION_STR, "$ISELECT_VERSION_STR", [TeX-style iSelect version]) AC_SUBST(ISELECT_VERSION_RAW) AC_SUBST(ISELECT_VERSION_MDOC_DATE) AC_SUBST(ISELECT_VERSION_LONG) echo "$ISELECT_VERSION_STR" echo "Copyright (c) 1997-2007 Ralf S. Engelschall " AC_CONFIG_HEADERS([config.h]) AC_PROG_CC AC_PROG_CXX AC_MSG_CHECKING([which Curses to use]) if curs="$(ncursesw6-config --cflags || ncurses6-config --cflags)" 2>/dev/null; then LIBS="$LIBS $(ncursesw6-config --libs || ncurses6-config --libs)" AC_MSG_RESULT([GNU NCurses]) else curs=" -D_XOPEN_SOURCE_EXTENDED" # wide characters LIBS="$LIBS -lcurses" AC_MSG_RESULT([Vendor Curses]) fi CFLAGS="$CFLAGS $curs" CXXFLAGS="$CXXFLAGS $curs" ISELECT_1_EXAMPLE_LOCATION=".Lk https://git.sr.ht/~nabijaczleweli/ossp-iselect/tree/trunk/item/example" AC_ARG_WITH(examples-at, AS_HELP_STRING(--with-examples-at, [where iselect(1) says examples are as a mdoc(7) macro]), [ISELECT_1_EXAMPLE_LOCATION="$withval"]) echo "iselect(1) says examples at $ISELECT_1_EXAMPLE_LOCATION" AC_SUBST(ISELECT_1_EXAMPLE_LOCATION) AC_CONFIG_FILES([Makefile iselect_readme.txt iselect.1 example/screen-ir/screen-ir.1]) AC_CONFIG_COMMANDS([embed-example], [ awk '/# database scan/,(/}/ && n++) {gsub(/\\/, "&&"); print}' "$ac_abs_srcdir/example/chdir/.bashrc" > iselect.hunk1 sed '/chdir\/.bashrc inserted here/r iselect.hunk1' iselect.1 > iselect.hunk_ sed -e 's/\^/\\(ha/g' -e 's/~/\\(ti/g' iselect.hunk_ > iselect.1 rm iselect.hunk? ]) AC_OUTPUT ossp-iselect-ISELECT_1_4_2/dokey.c000066400000000000000000000041021471643236400167300ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-2.0-or-later // Copyright (C) 1997 Michael R. Elkins #include #include #include #include "enter.h" static cc_t Kill = CKILL; static cc_t Werase = CWERASE; static cc_t Erase = CERASE; static cc_t Eol = CEOL; static cc_t Eol2 = #ifdef CEOL2 CEOL2; #else _POSIX_VDISABLE; #endif void km_dokey_load_termios(void) { struct termios termios; if(!tcgetattr(0, &termios)) { Kill = termios.c_cc[VKILL]; Werase = termios.c_cc[VWERASE]; Erase = termios.c_cc[VERASE]; } } int km_dokey(WINDOW * win, wint_t * LastKey) { switch(wget_wch(win, LastKey)) { case ERR: default: return -1; case OK: switch(*LastKey) { case L'\r': case L'\n': return OP_EDITOR_DONE; case CTRL(L'B'): return OP_EDITOR_BACKWARD_CHAR; case CTRL(L'F'): return OP_EDITOR_FORWARD_CHAR; case CTRL(L'H'): return OP_EDITOR_BACKSPACE; case CTRL(L'D'): return OP_EDITOR_DELETE_CHAR; case CTRL(L'A'): return OP_EDITOR_BOL; case CTRL(L'E'): return OP_EDITOR_EOL; case KEY_DL: return OP_EDITOR_KILL_LINE; case CTRL(L'I'): return OP_EDITOR_KILL_EOL; case CTRL(L'G'): case '\x1b': // escape return -1; } #define MAP(stty, op) \ if(*LastKey == stty && *LastKey != _POSIX_VDISABLE) \ return op MAP(Kill, OP_EDITOR_KILL_LINE); MAP(Werase, OP_EDITOR_KILL_WORD); MAP(Erase, OP_EDITOR_DELETE_CHAR); MAP(Eol, OP_EDITOR_DONE); MAP(Eol2, OP_EDITOR_DONE); return OP_EDITOR_CHAR; case KEY_CODE_YES: switch(*LastKey) { case KEY_LEFT: return OP_EDITOR_BACKWARD_CHAR; case KEY_RIGHT: return OP_EDITOR_FORWARD_CHAR; case KEY_BACKSPACE: return OP_EDITOR_BACKSPACE; case KEY_DC: return OP_EDITOR_DELETE_CHAR; case KEY_HOME: return OP_EDITOR_BOL; case KEY_END: return OP_EDITOR_EOL; case KEY_DL: return OP_EDITOR_KILL_LINE; case KEY_RESIZE: return OP_EDITOR_RESIZE; default: return OP_EDITOR_IDK; } } } ossp-iselect-ISELECT_1_4_2/enter.cpp000066400000000000000000000153161471643236400173030ustar00rootroot00000000000000// SPDX-License-Identifier: 0BSD extern "C" { #include "enter.h" } #include #include #include #include #include #include #include #include #include struct character { wchar_t c; char seg[MB_LEN_MAX]; unsigned seglen : std::bit_width(static_cast(MB_LEN_MAX)); unsigned width : 2; bool space : 1; bool word : 1; }; static_assert(MB_LEN_MAX <= ((1 << std::bit_width(static_cast(MB_LEN_MAX))) - 1)); extern "C" bool enter_string(WINDOW * win, FILE * out, bool emptyok) { int y, x; getyx(win, y, x); km_dokey_load_termios(); #define MEASURE(character) \ mvwaddnwstr(win, y, x, &character.c, 1); \ character.width = getcurx(win) - x; \ character.space = iswspace(character.c); \ character.word = iswalnum(character.c) struct character * characters{}; size_t characters_len{}, characters_cap{}; #define BUMPCHAR() \ do { \ if(characters_len == characters_cap) { \ characters_cap = characters_cap ? characters_cap * 2 : 16; \ if(!(characters = reinterpret_cast(reallocarray(characters, characters_cap, sizeof(*characters))))) \ return false; \ } \ } while(false) size_t characters_cursor = characters_len; #define LEFTBY(howmuch) \ do { \ int moveleft = howmuch; \ while(first_on_screen && moveleft > 0) \ moveleft -= characters[--first_on_screen].width; \ } while(false) #define RIGHTBY(howmuch) \ do { \ int moveright = howmuch; \ while(first_on_screen != characters_len && moveright > 0) \ moveright -= characters[++first_on_screen].width; \ } while(false) // Write out from first_on_screen, so long as the cursor fits on the screen, else move by a half-screen to find it. // Start off with as much text as possible and cursor on the right margin; you can't return to this state; this mimicks how ≤1b did it size_t first_on_screen = characters_cursor; LEFTBY((getmaxx(win) - x) - 1); for(wint_t input;;) { { auto screen_width = getmaxx(win) - x; auto all_characters_width = std::accumulate(characters, characters + characters_len, 0z, [](auto acc, auto && c) { return acc + c.width; }); if(all_characters_width < screen_width) first_on_screen = 0; else { if(first_on_screen >= characters_len) { first_on_screen = characters_cursor - 1; LEFTBY(screen_width / 2); } else if(characters_cursor < first_on_screen) while(characters_cursor < first_on_screen) LEFTBY(screen_width / 2); else for(;;) { auto last = std::find_if(characters + first_on_screen, characters + characters_len, [&, acc = 0z](auto && c) mutable { acc += c.width; return acc > screen_width; }); auto characters_on_screen = last - (characters + first_on_screen); if(first_on_screen + characters_on_screen < characters_cursor) RIGHTBY(screen_width / 2); else break; } } wmove(win, y, x); auto cursor_x = x; for(auto itr = characters + first_on_screen; itr != characters + characters_len; ++itr) { if(itr->width <= screen_width) screen_width -= itr->width; else break; waddnwstr(win, &itr->c, 1); if(itr < characters + characters_cursor) cursor_x += itr->width; } wclrtoeol(win); wmove(win, y, cursor_x); } switch(km_dokey(win, &input)) { case -1: return free(characters), false; case OP_EDITOR_CHAR: if(iswprint(input)) { struct character character = {}; character.c = input; int newlen = wctomb(character.seg, input); if(newlen == -1) goto err; character.seglen = newlen; MEASURE(character); BUMPCHAR(); memmove(characters + characters_cursor + 1, characters + characters_cursor, (characters_len - characters_cursor) * sizeof(*characters)); ++characters_len; characters[characters_cursor++] = character; } else { err: flushinp(); beep(); } break; case OP_EDITOR_DONE: { if(!characters_len && !emptyok) { wmove(win, y, x); break; } for(auto itr = characters; itr != characters + characters_len; ++itr) fwrite(itr->seg, 1, itr->seglen, out); return free(characters), true; } break; case OP_EDITOR_RESIZE: break; case OP_EDITOR_IDK: beep(); break; case OP_EDITOR_BACKSPACE: if(!characters_cursor) beep(); else { memmove(characters + characters_cursor - 1, characters + characters_cursor, (characters_len - characters_cursor) * sizeof(*characters)); --characters_len; --characters_cursor; } break; case OP_EDITOR_DELETE_CHAR: if(characters_cursor == characters_len) beep(); else { memmove(characters + characters_cursor, characters + characters_cursor + 1, (characters_len - (characters_cursor + 1)) * sizeof(*characters)); --characters_len; } break; case OP_EDITOR_KILL_LINE: characters_len = characters_cursor = 0; break; case OP_EDITOR_KILL_EOL: characters_len = characters_cursor; break; case OP_EDITOR_KILL_WORD: { if(!characters_cursor) break; auto end = characters_cursor; --characters_cursor; while(characters_cursor && characters[characters_cursor - 1].space) --characters_cursor; while(characters_cursor && characters[characters_cursor - 1].word) --characters_cursor; memmove(characters + characters_cursor, characters + end, (characters_len - end) * sizeof(*characters)); characters_len -= end - characters_cursor; } break; case OP_EDITOR_BOL: characters_cursor = 0; break; case OP_EDITOR_EOL: characters_cursor = characters_len; break; case OP_EDITOR_BACKWARD_CHAR: if(!characters_cursor) beep(); else --characters_cursor; break; case OP_EDITOR_FORWARD_CHAR: if(characters_cursor == characters_len) beep(); else ++characters_cursor; break; } } } ossp-iselect-ISELECT_1_4_2/enter.h000066400000000000000000000011101471643236400167330ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-2.0-or-later // Copyright (C) 1997 Michael R. Elkins #include #include enum { OP_EDITOR_CHAR, OP_EDITOR_DONE, OP_EDITOR_RESIZE, OP_EDITOR_IDK, OP_EDITOR_BACKSPACE, OP_EDITOR_DELETE_CHAR, OP_EDITOR_KILL_LINE, OP_EDITOR_KILL_EOL, OP_EDITOR_KILL_WORD, OP_EDITOR_BOL, OP_EDITOR_EOL, OP_EDITOR_BACKWARD_CHAR, OP_EDITOR_FORWARD_CHAR, }; extern bool enter_string(WINDOW * win, FILE * out, bool emptyok); extern void km_dokey_load_termios(void); extern int km_dokey(WINDOW * win, wint_t * LastKey); ossp-iselect-ISELECT_1_4_2/example/000077500000000000000000000000001471643236400171075ustar00rootroot00000000000000ossp-iselect-ISELECT_1_4_2/example/README000066400000000000000000000005541471643236400177730ustar00rootroot00000000000000 Here you can find some tools which are based on iSelect. chdir ........ Interactive cd fallback for bash melm ......... MetaELM, an ELM frontend mtin ......... MetaTIN, a TIN frontend scvs ......... Switch CVS Repository ilogin ....... Interactive Login gotourl ...... Goto URL for VIM screen-ir .... Interactively Reattach to GNU Screen sessions ossp-iselect-ISELECT_1_4_2/example/chdir/000077500000000000000000000000001471643236400202005ustar00rootroot00000000000000ossp-iselect-ISELECT_1_4_2/example/chdir/.bashrc000066400000000000000000000010441471643236400214420ustar00rootroot00000000000000## ## .bashrc snippet for iSelect-based 'cd' command ## Copyright (c) 1997 Ralf S. Engelschall, All Rights Reserved. ## # database scan cds () { find "$HOME" -type d | sort > ~/.dirs & } # enhanced cd command cd () { if [ -d "$1" ]; then builtin cd "$1" else builtin cd "$(grep -E "/$1[^/]*$" ~/.dirs | iselect -a -Q "$1" -n "chdir" \ -t "Change Directory to...")" fi } # change to parent dir alias -- -='cd ..' # change to last dir alias .='cd "$OLDPWD"' ossp-iselect-ISELECT_1_4_2/example/chdir/README000066400000000000000000000001471471643236400210620ustar00rootroot00000000000000This is a snippet for Bash's .bashrc file which provides an iSelect-based fallback to the cd function. ossp-iselect-ISELECT_1_4_2/example/gotourl/000077500000000000000000000000001471643236400206025ustar00rootroot00000000000000ossp-iselect-ISELECT_1_4_2/example/gotourl/.gotourlrc000066400000000000000000000004031471643236400226200ustar00rootroot00000000000000## ## ~/.gotourlrc -- GotoURL RC File ## ^ftp://.+/$ cftp %U ^ftp://.+[^/]$ lftp %U ^((http(s?))|ftp)://.+ www-browser %U ^((http(s?))|ftp)://.+ x-www-browser -remote 'openURL(%U)' ^((http(s?))|ftp)://.+[^/]$ fetch %U ossp-iselect-ISELECT_1_4_2/example/gotourl/.vimrc000066400000000000000000000000661471643236400217250ustar00rootroot00000000000000" Goto URL under Cursor map u yE:!gotourl """ ossp-iselect-ISELECT_1_4_2/example/gotourl/gotourl000077500000000000000000000021701471643236400222230ustar00rootroot00000000000000#!/usr/bin/perl ## ## GotoURL -- go to a particular URL ## Copyright (c) 1997 Ralf S. Engelschall, All Rights Reserved. ## $url = $ARGV[0]; @RC = (); open(RC, "<", "$ENV{HOME}/.gotourlrc"); while () { next if (m|^\s*#.*|); next if (m|^\s*$|); if (m|^(\S+)\s+(.+)$|) { push(@RC, { PAT => $1, CMD => $2 }); } } close(RC); use IPC::Open2; open2(my $isel_out, my $isel_in, 'iselect', '-n', 'GotoURL 1.0', '-t', 'Select Client...', '-p6'); print $isel_in "\n"; print $isel_in "URL: $url\n"; print $isel_in "\n"; print $isel_in "Available clients for this URL type:\n"; print $isel_in "\n"; foreach $rc (@RC) { if ($url =~ m|$rc->{PAT}|) { $cmd = $rc->{CMD}; $cmd =~ s|%U|$url|g; $txt = $rc->{CMD}; $txt =~ s|%U|...|g; print $isel_in sprintf("%s \n", $txt, $cmd); } } print $isel_in <<'EOT'; _____________________________________________________ Help: , .......... browse client list , ..... select client q, ............. quit EOT close($isel_in); $client = <$isel_out>; if ($client ne '') { system("$client"); } ossp-iselect-ISELECT_1_4_2/example/ilogin/000077500000000000000000000000001471643236400203705ustar00rootroot00000000000000ossp-iselect-ISELECT_1_4_2/example/ilogin/.ilogin000066400000000000000000000012671471643236400216600ustar00rootroot00000000000000## ## ~/.ilogin -- iLogin configuratiion ## Copyright (c) 1997 Ralf S. Engelschall, All Rights Reserved. ## @CFG = ( { AREA => "FOO", HOSTS => [ { NAME => 'bar@baz.quux.com', INFO => 'Quux', TYPE => 'ssh', OPT => '-l bar baz.quux.com' }, { NAME => 'root@baz.quux.com', INFO => 'Quux', TYPE => 'rlogin', OPT => '-K -l root baz.quux.com' }, { NAME => 'rse@baz.quux.com', INFO => 'Quux', TYPE => 'expect', OPT => [ 'eval spawn telnet baz.quux.com', 'expect ogin:', 'send "rse\r"', 'expect sword:', 'send XXXXXXX\r"', 'interact' ] }, ] } ); ossp-iselect-ISELECT_1_4_2/example/ilogin/.profile000066400000000000000000000002341471643236400220300ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-2.0-only l () { cmd="$(ilogin)"; if [ -n "$cmd" ]; then printf '$ %s\n' "$cmd" eval "$cmd" fi } ossp-iselect-ISELECT_1_4_2/example/ilogin/README000066400000000000000000000000651471643236400212510ustar00rootroot00000000000000This is iLogin, an interactive login selection tool. ossp-iselect-ISELECT_1_4_2/example/ilogin/ilogin000077500000000000000000000033321471643236400216000ustar00rootroot00000000000000#!/usr/bin/perl ## ## iLogin -- interactive login ## Copyright (c) 1997 Ralf S. Engelschall, All Rights Reserved. ## require "$ENV{HOME}/.ilogin"; use IPC::Open2; open2(my $isel_out, my $isel_in, 'iselect', '-n', 'iLogin', '-t', 'Select Remote Host...', '-p3', '-K', '-kf'); %LOGINCMD = (); %FTPCMD = (); foreach $l (@CFG) { $area = $l->{AREA}; $hosts = $l->{HOSTS}; print $isel_in "\n"; print $isel_in "$area:\n"; foreach $h (@{$hosts}) { $name = $h->{NAME}; $info = $h->{INFO}; $os = $h->{OS}; $type = $h->{TYPE}; $opt = $h->{OPT}; $passwd = $h->{PASSWD} || "$ENV{LOGIN}"; $home = $h->{HOME} || "/"; if ($type eq 'ssh') { $cmd = "ssh $opt"; } elsif ($type eq 'rlogin') { $cmd = "rlogin $opt"; } elsif ($type eq 'expect') { $cmd = "expect -c 'set timeout 30'"; foreach $c (@{$opt}) { $cmd .= " -c '".$c."'"; } } $LOGINCMD{$name} = $cmd; ($login, $host) = ($name =~ m|^(.+)@(.+)$|); if ($login eq 'ftp' or $login eq 'anonymous') { $user = ''; } else { $user = "$login:$passwd\@"; } $FTPCMD{$name} = "cftp ftp://$user$host$home"; print $isel_in sprintf("%-33s %-15s %-20s %6s \n", $name, $info, $os, $type, $name); } } close($isel_in); $rc = <$isel_out>; if ($rc ne '') { $rc =~ m|^(.+?):(.*)\n|; ($key, $name) = ($1, $2); if ($key eq 'RETURN' or $key eq 'KEY_RIGHT') { # Terminal Session print $LOGINCMD{$name}."\n"; } elsif ($key eq 'f') { # FTP Session print $FTPCMD{$name}."\n"; } } ossp-iselect-ISELECT_1_4_2/example/melm/000077500000000000000000000000001471643236400200415ustar00rootroot00000000000000ossp-iselect-ISELECT_1_4_2/example/melm/README000066400000000000000000000002151471643236400207170ustar00rootroot00000000000000This is MetaELM, an ELM frontend which lets one choose between different mail folders. When selecting a folder, ELM itself is started on it. ossp-iselect-ISELECT_1_4_2/example/melm/melm000077500000000000000000000040301471643236400207160ustar00rootroot00000000000000#!/usr/bin/perl ## ## MetaELM -- ELM frontend ## Copyright (c) 1997 Ralf S. Engelschall, All Rights Reserved. ## require 5.003; use Date::Parse; use Date::Format; # # configuration # $melmrc = "$ENV{'HOME'}/.melmrc"; # # read rc-file # @MAILFOLDER = (); open(RC, "<", "$melmrc") || die "** mElm:Error: no \"$melmrc\" found. Please create one first.\n"; while () { next if (m|^\s*$|); next if (m|^\s*#.*$|); if (m|^\s*(/\S+)\s+(.+?)\s*$|) { push(@MAILFOLDER, { FOLDER => $1, NAME => $2 }); } else { print STDERR "** mElm:Error: bad RC-file entry:\n"; print STDERR "** mElm:Error: $_"; exit(1); } } close(RC); sub update_entry { ($entry) = @_; ($name, $folder) = ($entry->{NAME}, $entry->{FOLDER}); @F = `from -f $folder`; $time = $F[$#F]; $time =~ s|^From\s+\S+\s+(.+)\s*|$1|; $time = str2time($time); $entry->{TIME} = $time; $entry->{MAILS} = $#F+1; } foreach $entry (@MAILFOLDER) { update_entry($entry); } # # processing loop # $pos = 4; while (1) { $L = '"" ' . '"Available Folders: '. sprintf("%d", $#MAILFOLDER + 1) .'" ' . '"" '; $n = 1; foreach $entry (@MAILFOLDER) { ($name, $folder, $time, $mails) = ($entry->{NAME}, $entry->{FOLDER}, $entry->{TIME}, $entry->{MAILS}); $arg .= sprintf("%2d %-20s (%3d) %s %2d ", $n++, $name, $mails, time2str("%a", $time), time2str("%d", $time)); $arg =~ s|'|\'\\\'\'|g; $L .= "'$arg' " } $L .= "'' "; $L .= "'_____________________________________________________' "; $L .= "'' "; $L .= "'Help: , .......... browse folder list' "; $L .= "' , ..... select folder (run ELM)' "; $L .= "' q, ............. quit' "; $rc=`exec iselect -n "MetaELM 1.0.0" -t "Electronic Mail Folders" -p$pos -P $L`; if ($rc eq '') { exit(0); } $rc =~ m|^(\d+):(.*)|; ($pos, $cmd) = ($1, $2); system($cmd); update_entry($MAILFOLDER[$pos-4]); } ossp-iselect-ISELECT_1_4_2/example/mtin/000077500000000000000000000000001471643236400200565ustar00rootroot00000000000000ossp-iselect-ISELECT_1_4_2/example/mtin/README000066400000000000000000000002231471643236400207330ustar00rootroot00000000000000This is MetaTIN, a TIN frontend which lets one choose between different newsgroup clusters. When selecting a cluster, TIN itself is started on it. ossp-iselect-ISELECT_1_4_2/example/mtin/mtin000077500000000000000000000120051471643236400207510ustar00rootroot00000000000000#!/usr/bin/perl ## ## MetaTIN -- a TIN frontend for better USENET NetNews reading ## Copyright (c) 1996-1997 Ralf S. Engelschall, All Rights Reserved. ## use IO::Socket; sub existsgroup { local ($host, $group) = @_; local ($NNTP); $NNTP = new IO::Socket::INET( 'PeerAddr' => $host, 'PeerPort' => 'nntp', 'Proto' => 'tcp', 'Timeout' => 120 ); $NNTP->autoflush(1); $NNTP->getline(); # greating $NNTP->print("mode reader\r\n"); $NNTP->getline(); # greating $NNTP->print("group $group\r\n"); $rc = $NNTP->getline(); # greating $rc =~ m|^(\d+) .+|; $rc = $1; $NNTP->print("quit\r\n"); $NNTP->close(); return ($rc == 211 ? 1 : 0); } # the files we operate on $newsrc = "$ENV{'HOME'}/.mtinrc"; $newsrcwork = "$ENV{'HOME'}/.newsrc"; # function to get the topics out of the annotated newsrc sub NEWSRC_GetTopics { local (%NewsgroupTopic) = (); $cnt = 1; open(FP, "<", "$newsrc"); while () { next if m|^[ \t]*#.*$|; next if m|^[ \t]*$|; if (m|^%%T[ \t]+(.*)$|) { $topic_tag = $1; $topic_name = ""; $newsgroups_sub = 0; $newsgroups_unsub = 0; next; } if (m|^%%N[ \t]+(.*)$|) { $topic_name = $1; next; } if (m|^[a-zA-Z0-9-.]+!.*$|) { $newsgroups_unsub++; next; } if (m|^[a-zA-Z0-9-.]+:.*$|) { $newsgroups_sub++; next; } if (m|^%%E[ \t]*$|) { $key = sprintf("%02d-%s", $cnt, $topic_tag); $NewsgroupTopic{$key} = "$topic_name%%$newsgroups_sub%%$newsgroups_unsub"; $cnt++; } } close(FP); return (%NewsgroupTopic); } sub NEWSRC_GetTopicPart { local($tag) = @_[0]; local($buffer); local($save); open(FP, "<", "$newsrc"); $save = 0; while () { next if m|^[ \t]*#.*$|; next if m|^[ \t]*$|; if (m|^%%T[ \t]+(.+)[ \t]*$|) { if ("$1" eq "$tag") { $save = 1; } } if (m|^%%E.*$|) { $save = 0; } if ($save) { next if m|^%%.*|; $buffer .= $_; } } close(FP); return($buffer); } sub NEWSRC_SetTopicPart { local($tag, $buffer) = @_; local($save); rename("$newsrc", "$newsrc.bak"); open(FPI, "<", "$newsrc.bak"); open(FPO, ">", "$newsrc"); $set = 0; $ignore = 0; while () { if (m|^%%N.*$|) { print FPO $_; next; } if (m|^%%T[ \t]+(.+)[ \t]*$|) { if ("$1" eq "$tag") { $set = 1; $ignore = 0; print FPO $_; next; } } if (m|^%%E.*$|) { $set = 0; $ignore = 0; print FPO $_; next; } if ($set) { if ($ignore == 0) { print FPO "$buffer"; $ignore = 1; } } else { print FPO $_; } } close(FPI); close(FPO); } %NewsgroupTopic = NEWSRC_GetTopics(); $clusters = 0; foreach $key (sort(keys(%NewsgroupTopic))) { $clusters++; } $itemlist = "'' "; $itemlist .= "'Available Clusters: $clusters. News server: $ENV{NNTPSERVER}' "; $itemlist .= "'' "; $n = 1; foreach $key (sort(keys(%NewsgroupTopic))) { $NewsgroupTopic{$key} =~ m|^(.+)%%(.+)%%(.+)$|; ($name, $countsub, $countunsub) = ($1, $2, $3); $key =~ s|^\d+-||; $arg = sprintf("%2d %3d %-15s %-50s ", $n, $countsub, $key, $name, $key); $arg =~ s|'|\'\\\'\'|g; $itemlist .= "'$arg' "; $n++; } $itemlist .= "'' "; $itemlist .= "'_____________________________________________________' "; $itemlist .= "'' "; $itemlist .= "'Help: , .......... browse cluster list' "; $itemlist .= "' , ..... select cluster (run TIN)' "; $itemlist .= "' q, ............. quit' "; $quit = 0; $pos = 4; while ($quit ne 1) { # run the fullscreen menu via iSelect $tag = `iselect -p$pos -P -n 'MetaTIN 1.0.0' -t 'USENET Newsgroup Clusters' $itemlist`; if ($tag eq '') { $quit = 1; next; } $tag =~ s|\n$||; $tag =~ m|^(\d+):(.*)|; ($pos, $tag) = ($1, $2); # copy topic from .mtinrc to newsrc $buffer = NEWSRC_GetTopicPart($tag); open(FP, ">", "$newsrcwork"); print FP $buffer; close(FP); # run TIN on the newsrc system("clear"); system("tin -r -q -f $newsrcwork"); # copy changed topic back to .mtinrc $buffer = ""; open(FP, "<", "$newsrcwork"); while () { #if (m|^([^ \t:!\n]+)|) { # if (not existsgroup("$ENV{'NNTPSERVER'}", "$1")) { # print STDERR "WARNING! group $1 not exists - REMOVED\n"; # next; # } #} $buffer .= $_; } close(FP); NEWSRC_SetTopicPart($tag, $buffer); } ossp-iselect-ISELECT_1_4_2/example/screen-ir/000077500000000000000000000000001471643236400207765ustar00rootroot00000000000000ossp-iselect-ISELECT_1_4_2/example/screen-ir/screen-ir000077500000000000000000000010511471643236400226100ustar00rootroot00000000000000#!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (C) 2011, Axel Beckert # Reattaches to screen sessions interactively if ! command -v screen > /dev/null; then echo "screen not found in" "$PATH" exit 1 fi SCREEN_OPTIONS="-r" ISELECT_OPTIONS="" [ -f ~/.screen-irrc ] && . ~/.screen-irrc SELECTION=$( screen -ls | sed -n 's/^[ \t][ \t]*\([0-9]\)/\1/p' | iselect -t "Select screen session to reattach" $ISELECT_OPTIONS ) [ -n "$SELECTION" ] && exec screen $SCREEN_OPTIONS "$@" "${SELECTION%%.*}" ossp-iselect-ISELECT_1_4_2/example/screen-ir/screen-ir.1.in000066400000000000000000000023121471643236400233520ustar00rootroot00000000000000.\" SPDX-License-Identifier: GPL-2.0-or-later .\" .Dd @ISELECT_VERSION_MDOC_DATE@ .Dt ISELECT 1 .ds doc-volume Axel Beckert .Os ossp-iselect @ISELECT_VERSION_RAW@ . .Sh NAME .Nm screen-ir .Nd Interactively Reattach to GNU Screen sessions .Sh SYNOPSIS .Nm .Op Ar additional screen options No … . .Sh DESCRIPTION .Nm uses .Xr iselect 1 to interactively reattach to running .Nm screen sessions. .Pp Use the .Nm screen option .Fl d or .Fl D if you want to reattach to attached screen sessions. .Pp Use the screen option .Fl x if you want to attach to screen sessions without detaching them. . .Sh FILES .Nm sources .Pa \(ti/.screen-irrc if it exists. It recognizes two variables: .Pp The contents of .Ev SCREEN_OPTIONS is given to .Xr screen 1 as command-line options. The default is .Fl r . Use e.g.\& .Fl rd , if you always want to reattach to already attached screen sessions. .Pp The contents of .Ev ISELECT_OPTIONS is given to .Xr iselect 1 as command-line options. Default is empty. Use e.g.\& .Fl f if you always want to see the interactive selection, even if there's only one screen session running, i.e.\& you have no choice. . .Sh AUTHORS .An Axel Beckert Aq abe@debian.org . .Sh SEE ALSO .Xr screen 1 , .Xr iselect 1 ossp-iselect-ISELECT_1_4_2/example/scvs/000077500000000000000000000000001471643236400200655ustar00rootroot00000000000000ossp-iselect-ISELECT_1_4_2/example/scvs/.scvsrc000066400000000000000000000003521471643236400213710ustar00rootroot00000000000000## ## .scvsrc -- SCVS config for Apache CVS trees ## Copyright (c) 1997 Ralf S. Engelschall, All Rights Reserved. ## dev.apache.org:/export/home/cvs (Apache Original, USA) /e/apache/REPOS (Apache CVSup Copy, LOCAL) ossp-iselect-ISELECT_1_4_2/example/scvs/README000066400000000000000000000002071471643236400207440ustar00rootroot00000000000000This is sCVS, a tool to switch the CVS repository for a checked out CVS tree. The selection of the new repository is done via iSelect. ossp-iselect-ISELECT_1_4_2/example/scvs/scvs000077500000000000000000000071241471643236400207750ustar00rootroot00000000000000#!/usr/bin/perl ## ## sCVS -- Switch CVS Repository ## Copyright (c) 1997 Ralf S. Engelschall, All Rights Reserved. ## require 5.004; use Term::ANSIColor; use File::Spec; use IPC::Open2; use Cwd; ## ## 1. Find .scvsrc files and read contents into %CVSROOTS hash ## %CVSROOTS = (); # create list of dirs back to root ($cwd = Cwd::cwd) =~ s|/$||; $cwdT = $cwd; while ($cwdT) { push(@DIR, $cwdT); $cwdT =~ s|/[^/]+$||; } # search for .scvsrc files foreach $dir (reverse(@DIR)) { if (-f "$dir/.scvsrc") { $reldir = File::Spec->abs2rel($dir); $reldir = '.' if $reldir eq ''; $subdir = File::Spec->abs2rel($cwd, $dir); $rcfile = "$reldir/.scvsrc"; process_rcfile($rcfile, $cwd, $reldir, $subdir); } } # process a particular .scvsrc file sub process_rcfile { my ($rcfile, $cwd, $reldir, $subdir) = @_; my ($rc, @E, $e); open($rc, "<", $rcfile); while (<$rc>) { next if (m|^\s*#|); next if (m|^\s*$|); if (m|^\s*(\S+)\s*$|) { $CVSROOTS{$1} = ''; } elsif (m|^\s*(\S+)\s+\(\s*(.+?)\s*\)\s*$|) { $CVSROOTS{$1} = $2; } else { print STDERR "sCVS:Error: $rcfile, invalid line: '$_'\n"; exit(1); } } close($rc); } ## ## 2. Check for correct location to be called and ## determine current configured CVS repository location ## if (not -d "./CVS") { print STDERR "sCVS:Error: must stay inside a checked-out CVS tree.\n"; exit(1); } open($root, "<", "CVS/Root"); $locC = <$root>; $locC =~ s|\n$||; close($root); ## ## 3. Create iSelect page with list of available CVS repositories ## and fire up iSelect with it ## $pos = 0; $list = ''; $n = 1; foreach $loc (keys(%CVSROOTS)) { $name = $CVSROOTS{$loc}; if ($loc eq $locC) { $pos = $n; $act = '*'; } else { $act = ''; } $arg = sprintf("%1s %-30s %s", $act, $name, $loc, $loc); $arg =~ s|'|\'\\\'\'|g; $list .= " '$arg'"; $n++; } if ($pos == 0) { $arg = sprintf("%1s %-30s %s", '*', 'UNKNOWN', $locC, $locC); $arg =~ s|'|\'\\\'\'|g; $list .= " '$arg'"; $pos = $n; } $pos += 3; $cmd = "iselect -n 'sCVS' -t 'Switch CVS Repository'" . " -p$pos -P" . " ''" . " 'Available Repositories:'" . " ''" . " $list" . " ''" . " 'Use CURSOR keys and RETURN to select or \'q\' to quit.'"; $rc = `exec $cmd`; ($pos, $locN) = ($rc =~ m|^(\d+):(.*)|); if ($locN eq '') { print STDERR "sCVS: Aborted\n"; exit(1); } elsif ($locN eq $locC) { print STDERR "Repository unchanged\n"; exit(0); } ## ## 4. Time to switch! ## $prefixN = $locN; $prefixN =~ s|^[^/]+||; open2(my $find, "<&0", 'find', '.', '-noleaf', '-depth', '-type', 'd', '-name', 'CVS', '-print'); while (<$find>) { $dir = $_; $dir =~ s|^\./||; $dir =~ s|\n$||; $dirname = $dir; if (length($dirname) > 60) { $dirname = '..'.substr($dirname, length($dirname)-60, 60); } $dirname = sprintf("%-60s", $dirname); print STDERR "Processing: ".colored("$dirname", 'bold')."\r"; open(FP, "<", "$dir/Root"); $locO = ; $locO =~ s|\n$||; close(FP); open(FP, ">", "$dir/Root"); print FP "$locN\n"; close(FP); $prefixO = $locO; $prefixO =~ s|^[^/]+||; open(FP, "<", "$dir/Repository"); $subdir = ; $subdir =~ s|\n$||; close(FP); $subdir =~ s|^$prefixO|$prefixN|; open(FP, ">", "$dir/Repository"); print FP "$subdir\n"; close(FP); } printf STDERR "%-78s\n", "Repository switched to $locN"; ossp-iselect-ISELECT_1_4_2/iselect.1.in000066400000000000000000000161371471643236400176030ustar00rootroot00000000000000.\" SPDX-License-Identifier: GPL-2.0-only .\" Copyright (c) 1997-2007 Ralf S. Engelschall. .\" .Dd @ISELECT_VERSION_MDOC_DATE@ .Dt ISELECT 1 .ds doc-volume Ralf S. Engelschall .Os ossp-iselect @ISELECT_VERSION_RAW@ . .Sh NAME .Nm iSelect .Nd Interactive Selection Tool .Sh SYNOPSIS .Nm iselect .Op Fl d Ar beg Ns Cm ,\& Ns Ar end .Op Fl cfae .Op Fl p Ar linenum .Op Fl k Ar key Ns Op Cm :\& Ns Ar okey .Op Fl m .Op Fl n Ar name .Op Fl t Ar title .Op Fl SKP .Op Fl Q Ar fallback .Ar line Ns … . .Nm iselect .Op Fl d Ar beg Ns Cm ,\& Ns Ar end .Op Fl cfae .Op Fl p Ar linenum .Op Fl k Ar key Ns Op Cm :\& Ns Ar okey .Op Fl m .Op Fl n Ar name .Op Fl t Ar title .Op Fl SKP .Op Fl Q Ar fallback .Li < .Pa lines . .Nm iselect .Fl V Ns \&| Ns Fl h . .Sh DESCRIPTION .Ss Intent .Nm is an interactive line selection tool, operating via a full-screen Curses-based terminal session. It can be used either as a user interface frontend controlled by the shell, Perl, or another type of script backend as its wrapper, or in batch as a pipe filter .Pq usually between Nm grep Ns \& and the final executing command . In other words: .Nm was designed to be used for any type of interactive line-based selection. . .Ss Input Data If no arguments are given, lines are read from the standard input stream. Otherwise, .Ar line Ns s are used directly. .Pp Each selectable line is fully bold; parts of other lines may be set in bold by wrapping them in .Ql ... . . .Ss Selections By default, a single line may be chosen; with .Fl m multiple lines can be selected. By default, only lines containing the tag .Ql .Pq or with different delimiters set with Fl d may be selected. .Fl a allows selecting all lines, but the tag is always removed. Selected lines are written to the standard output stream .Pp The tag has a variant that looks like .Ql , which, instead of writing the line itself, writes .Ar result\ text . Every format specifier in the form .Ql %[prompt\ string]s or .Ql %[prompt\ string]S in the output is replaced by a line entered in an interactive prompt. The .Sy s variant allows empty responses; .Sy S doesn't. . .Sh OPTIONS .Ss Input Options .Bl -tag -width 2n .It Fl d Ar beg Ns Cm ,\& Ns Ar end , Fl -delimiter Ns = Ns Ar beg Ns Cm ,\& Ns Ar end Sets the delimiters for the selection tags. The default is .Sy < and .Sy > \(em the selection tags have to read .Ql and .Ql . . .It Fl c , -strip-comments Discard input lines starting with .Ql # . . .It Fl f , -force-browse Open the full-screen browser even if input contains less than .Pf < Em 2 lines. This may happen anyway if a .Ql %[prompt]s needs to be substituted. . .It Fl a , -all-select Force all lines to be selectable. .Ql tags are still removed. . .It Fl e , -exit-no-select Exit immediately if no lines are selectable. .El . .Ss Display Options .Bl -tag -width 2n .It Fl p , -position Ns = Ns Ar linenum Sets the cursor position to .Sy 1 Ns -based .Ar linenum Ns ber . . .It Fl k , -key Ns = Ns Ar key Ns Cm :\& Ns Ar okey Maps .Ar key to .Ar okey . Both may be either a printable character or one of .Sy SPACE , .Sy RETURN , .Sy KEY_UP (\(ua), .Sy KEY_DOWN (\(da), .Sy KEY_LEFT (\(<-), .Sy KEY_RIGHT (\(->), .Sy KEY_PPAGE (PgUp), .Sy KEY_NPAGE (PgDn). This can be given any number of times, and is applied in order. . .It Fl k , -key Ns = Ns Ar key Same as .Fl k Ar key Ns Cm :\& Ns Li RETURN . For example, .Fl k Ar f allows using .Ql f to confirm the selection. . .It Fl m , -multi-line Allow selecting more than one line with Space. . .It Fl n , -name Ns = Ns Ar name Changes the string displayed flush left at the bottom of the browser window from "iSelect". . .It Fl t , -title Ns = Ns Ar title Sets the .Ar , displayed centered at the bottom of the browser window. .El . .Ss Output Options .Bl -tag -width 2n .It Fl S , -strip-result Strip all leading and trailing whitespace from the result string. . .It Fl K , -key-result Prefix each result with the key used to confirm the selection. This is usually .Qq Sy RETURN or .Qq Sy KEY_RIGHT , but in the presence of .Fl k , this is the (unmapped) .Ar key ; thus, with .Fl k Ar f , selecting line .Li Foo Bar by pressing .Ql f yields .Ql f:Foo\ Bar . A Space is rendered as a literal space, not as .Qq Sy SPACE . . .It Fl P , -position-result Prefix each result with its .Sy 1 Ns -based line number in the buffer. . .It Fl Q , -quit-result Ns Li = Ns Ar fallback Write .Ar fallback to the standard output stream when quitting. .El . .Ss Giving Feedback .Bl -tag -width 2n .It Fl V , -version Write the version and licence information to the standard output stream, exit .Sy 0 . . .It Fl h , -help Write the usage string information to the standard error stream, exit .Sy 0 . .El . .Sh KEYSTROKES .Ss Cursor Movement Use these to browse through the selection list: .Bd -literal -compact CURSOR-UP ..... Move cursor one line up CURSOR-DOWN ... Move cursor one line down PAGE-UP ....... Move cursor one page up PAGE-DOWN ..... Move cursor one page down g ............. Goto first line G ............. Goto last line .Ed . .Ss Line Selection Use these to select one line and exit in standard mode, or one or more lines in multi-line mode: .Bd -literal -compact RETURN ........ Select line and exit CURSOR-RIGHT .. Select line and exit SPACE ......... Select line and stay (multi-line mode only) C ............. Clear current marks (multi-line mode only) .Ed . .Ss Others Use these to quit .Nm or to show the help or version pages: .Bd -literal -compact q ............. Quit (exit without selection) CURSOR-LEFT ... Quit (exit without selection) h ............. Help Page v ............. Version Page .Ed . .Sh FILES The Curses session is always opened on .Pa /dev/tty , because the standard I/O streams are usually tied to pipes. . .Sh EXIT STATUS .Bl -tag -compact -width ".Sy 0" .It Sy 0 if a selection was made, a selection wasn't made, or succumbed to .Dv SIGINT or .Dv SIGTERM . . .It Sy 1 if an unknown .Oo Ar o Oc Ns Ar key was given or an I/O error occurred. .El . .Sh EXAMPLES As an example we present a real-life situation where .Nm can enhance existing functionality. We define two shell functions .Pq for your Pa $HOME/.bashrc Ns \& file which enhance the shell's .Ic cd built-in. . .Bd -literal -compact -offset 2n .\" chdir/.bashrc inserted here .Ed .Pp This .Fn cd is compatible with the built-in in the case where the specified directory actually exists. When it doesn't, the original .Ic cd would immediately give an error .Pq assuming Ev CDPATH Ns \& is not set . This version tries harder by searching for such a directory in a previously-built .Pq via Fn cds .Pq $HOME/.dirs file. When no match is found, .Nm just returns the given directory as the default result and .Ic cd fails as usual. When only one directory was found, .Nm gives it to .Ic cd silently. Only when more then one directory was found, .Nm shows a menu to pick between matches interactively. The chosen directory is then given to .Ic cd . .Pp For more useful examples on how to use .Nm , see @ISELECT_1_EXAMPLE_LOCATION@ . . .Sh AUTHORS .An Ralf S. Engelschall Aq rse@engelschall.com .Pq Lk http://www.engelschall.com . .Sh SEE ALSO .Lk https://sr.ht/~nabijaczleweli/ossp New iSelect Home ossp-iselect-ISELECT_1_4_2/iselect.h000066400000000000000000000032761471643236400172650ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-2.0-only // Copyright (c) 1997-2007 Ralf S. Engelschall. #include #include #include enum iSelect_key { iSelect_DontKnow = 0xD800, // surrogate, not a valid character iSelect_NextLine, iSelect_PrevLine, iSelect_NextPage, iSelect_PrevPage, iSelect_Left, // these are for display only, we force-map them to q and enter internally iSelect_Right, }; _Static_assert(sizeof(enum iSelect_key) >= sizeof(wint_t), "enum iSelect_key : wint_t"); extern void configure_custom_key(char *config); extern enum iSelect_key mapped_key(WINDOW *win, enum iSelect_key *unmapped_key); extern void name_key(enum iSelect_key key, FILE *into); /* * The Structure of our screen lines */ typedef struct Line { char *cpLine; /* the input line */ size_t nLine; /* input line length */ char *cpResult; /* the result string */ size_t nResult; /* result string length */ char *cpFmtResult; /* the formatted result string (use instead of cpResult if set) */ size_t nFmtResult; /* formatted result string length */ bool fSelectable : 1; /* whether selectable or not */ bool fSelected : 1; /* whether already selected or not */ } Line; extern Line *spaLines; extern size_t nLines; extern ssize_t iSelect(size_t pos, const char *title, const char *name, const char *tagbegin, const char *tagend, bool stripws, bool browsealways, bool allselectable, bool multiselect, bool exitnoselect, enum iSelect_key *unmapped_key); extern const Line iSelect_Help[]; extern const Line iSelect_README[]; ossp-iselect-ISELECT_1_4_2/iselect_browse.c000066400000000000000000000626561471643236400206500ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-2.0-only // Copyright (c) 1997-2007 Ralf S. Engelschall. #include "config.h" #include "iselect.h" #include "enter.h" #include #include #include #include #include #include #include #define max(a, b) ((a) > (b) ? (a) : (b)) Line *spaLines; /* filled by main(), corrected by iSelect() */ size_t nLines; /* * Strip leading and trailing blanks * from a string buffer in ln->cpResult and ln->nResult */ static void strip(Line *ln) { mbstate_t state = {0}; wchar_t c; size_t r = 0; while (ln->nResult) switch (r = mbrtowc(&c, ln->cpResult, ln->nResult, &state)) { case (size_t)-2: // too short return; case (size_t)-1: // EILSEQ state = (mbstate_t){0}; // FALLTHROUGH case 0: r = 1; c = -1; // FALLTHROUGH default: if (c == (wchar_t)-1 || !iswspace(c)) goto break2; ln->cpResult += r; ln->nResult -= r; } break2:; size_t oklen = r, spacelen = 0; while (oklen + spacelen != ln->nResult) switch (r = mbrtowc(&c, ln->cpResult + oklen + spacelen, ln->nResult - (oklen + spacelen), &state)) { case (size_t)-2: // too short return; case (size_t)-1: // EILSEQ state = (mbstate_t){0}; // FALLTHROUGH case 0: r = 1; c = -1; // FALLTHROUGH default: if (c == (wchar_t)-1 || !iswspace(c)) { oklen += spacelen + r; spacelen = 0; } else spacelen += r; } ln->nResult -= spacelen; } /* * Die gracefully... */ static void diehard(int sig) { (void) sig; endwin(); exit(0); } char *boldbegin, *boldend; size_t boldbegin_len, boldend_len; static void iSelect_PrepTagStrs(const char *tagbegin, const char *tagend) { boldbegin_len = asprintf(&boldbegin, "%sb%s", tagbegin, tagend); boldend_len = asprintf(&boldend, "%s/b%s", tagbegin, tagend); } /* * Function to draw a complete screen */ static void iSelect_Draw(const Line *spaLines, WINDOW *wField, int wXSize, int nAbsFirstLine, size_t nRelMarked, bool bRelMarked, size_t nRelFirstDraw, size_t nRelLastDraw, size_t nLines, WINDOW *sField, const char *title, const char *name, WINDOW *mField, const char *msg) { /* * draw browser window */ for (size_t i = nRelFirstDraw; i <= nRelLastDraw && nAbsFirstLine+nRelFirstDraw+i < nLines; ++i) { const Line *l = &spaLines[nAbsFirstLine+nRelFirstDraw+i]; wmove(wField, i, 0); wclrtoeol(wField); int mode = A_NORMAL; if (l->fSelectable) mode |= A_BOLD; if (bRelMarked && i == nRelMarked) mode |= A_REVERSE; wattrset(wField, mode); waddch(wField, l->fSelected ? '*' : ' '); // cursor pos == first blank int curx = 0; size_t collectbeg = 0, collectend = 0, boldlen; for (size_t j = 0; curx <= wXSize-1 && j < l->nLine;) { if (l->nLine - j >= boldbegin_len && !strncasecmp(&l->cpLine[j], boldbegin, boldlen = boldbegin_len)) { mode |= A_BOLD; goto flush; } if (l->nLine - j >= boldend_len && !strncasecmp(&l->cpLine[j], boldend, boldlen = boldend_len)) { mode &= ~A_BOLD; goto flush; } if (!l->cpLine[j] && (boldlen = 1)) { flush: waddnstr(wField, l->cpLine + collectbeg, collectend - collectbeg); curx = getcurx(wField); wattrset(wField, mode); j += boldlen; collectbeg = collectend = j; continue; } ++j; ++collectend; } waddnstr(wField, l->cpLine + collectbeg, collectend - collectbeg); curx = getcurx(wField); while (curx <= (wXSize-1)-1) waddch(wField, ' '), ++curx; wattrset(wField, A_NORMAL); } if (wmove(wField, nRelLastDraw + 1, 0) != ERR) wclrtobot(wField); wmove(wField, nRelMarked, wXSize-1); /* * draw status bar */ werase(sField); mvwaddstr(sField, 0, 0, title); int title_width = getcurx(sField); wmove(sField, 0, 0); while (waddch(sField, '\t') != ERR) ; mvwaddstr(sField, 0, 1, name); int percent = nLines ? (int)(((nAbsFirstLine+nRelMarked+1)*100)/nLines) : 100; char ca[80]; int ca_width = snprintf(ca, sizeof(ca), "%4zu,%3d%%", 1+nAbsFirstLine+nRelMarked, percent > 100 ? 100 : percent); mvwaddnstr(sField, 0, COLS - ca_width - 1, ca, ca_width); mvwaddstr(sField, 0, (COLS-1)/2-(title_width/2), title); wrefresh(sField); /* * draw message field */ mvwaddstr(mField, 0, 0, msg); wclrtoeol(mField); wrefresh(mField); } /* * Function to do a complete selection screen */ static ssize_t iSelect_Browser(size_t wYSize, size_t wXSize, int wYPos, int wXPos, size_t selectpos, bool multiselect, int sYSize, int sXSize, int sYPos, int sXPos, const char *title, const char *name, int mYSize, int mXSize, int mYPos, int mXPos, enum iSelect_key *unmapped_key) { size_t nAbsFirstLine, nAbsLastLine; /* first & last line of output buffer */ size_t nRelMarked; /* relative line inside output buffer of marked line */ size_t nRelFirstDraw, nRelLastDraw; /* relative first & last line inside output buffer */ enum iSelect_key c; bool bEOI = false; bool bQuit = false; const char *msg = ""; /* * Browser field */ WINDOW *wField = newwin(wYSize, wXSize, wYPos, wXPos); werase(wField); cbreak(); noecho(); keypad(wField, true); /* * Status field */ WINDOW *sField = newwin(sYSize, sXSize, sYPos, sXPos); werase(sField); wattrset(sField, A_REVERSE); /* * Message field */ WINDOW *mField = newwin(mYSize, mXSize, mYPos, mXPos); werase(mField); keypad(mField, true); /* first & last line in buffer */ const size_t nFirstLine = 0; const size_t nLastLine = nLines ? nLines-1 : 0; /* determine curses select position */ selectpos = max(selectpos, 1) - 1; if (selectpos > nLastLine) selectpos = nLastLine; /* calculate browser view borders */ if (nLastLine < (wYSize-1)) { /* buffer has fewer lines then our browser window */ nAbsFirstLine = nFirstLine; nAbsLastLine = nLastLine; nRelFirstDraw = 0; nRelLastDraw = nLastLine-nFirstLine; nRelMarked = selectpos; } else { /* browser window is smaller then file */ /* find top view position, so adjust the cursor into the middle of the browser window */ ssize_t y = selectpos - (int)((wYSize-1)/2); if (y <= 0) y = 0; if (y+(wYSize-1) > nLastLine) y = nLastLine-(wYSize-1); nAbsFirstLine = y; nAbsLastLine = y+(wYSize-1); nRelFirstDraw = 0; nRelLastDraw = (wYSize-1); nRelMarked = selectpos-y; } bool ok = false; for (size_t i = nFirstLine; i < nLines; ++i) { if (spaLines[i].fSelectable) { ok = true; break; } } if (!ok) msg = "WARNING! No lines selectable."; while (!bEOI) { iSelect_Draw(spaLines, wField, wXSize, nAbsFirstLine, nRelMarked, true, nRelFirstDraw, nRelLastDraw, nLines, sField, title, name, mField, msg); msg = ""; switch (c = mapped_key(wField, unmapped_key)) { case iSelect_NextLine: if (nAbsFirstLine+nRelMarked < nAbsLastLine) { nRelMarked++; /* nRelFirstDraw=nRelMarked-1; !!OPTIMIZE!! */ /* nRelLastDraw=nRelMarked; !!OPTIMIZE!! */ } else { if (nAbsLastLine < nLastLine) { wscrl(wField, 1); nAbsFirstLine++; nAbsLastLine++; /* nRelFirstDraw=(wYSize-1); !!OPTIMIZE!! */ /* nRelLastDraw=(wYSize-1); !!OPTIMIZE!!*/ } else { msg = "Already at End."; } } break; case iSelect_PrevLine: if (nRelMarked > 0) { nRelMarked--; /* nRelLastDraw=nRelMarked; !!OPTIMIZE!! */ /* nRelFirstDraw=nRelMarked+1; !!OPTIMIZE!! */ } else { if (nAbsFirstLine > nFirstLine) { wscrl(wField, -1); nAbsFirstLine--; nAbsLastLine--; /* nRelFirstDraw=0 !!OPTIMIZE!! */ /* nRelLastDraw=0; !!OPTIMIZE!! */ } else { msg = "Already at Begin."; } } break; case iSelect_NextPage: if (nAbsFirstLine+nRelMarked == nLastLine) { msg = "Already at End."; } else { for (size_t i = 0; i < (wYSize-1); ++i) { if (nAbsFirstLine+nRelMarked < nAbsLastLine) nRelMarked++; else { if (nAbsLastLine < nLastLine) { wscrl(wField, 1); nAbsFirstLine++; nAbsLastLine++; } } } } break; case iSelect_PrevPage: if (nAbsFirstLine+nRelMarked == nFirstLine) { msg = "Already at Begin."; } else { for (size_t i = 0; i < (wYSize-1); ++i) { if (nRelMarked > 0) nRelMarked--; else { if (nAbsFirstLine > nFirstLine) { wscrl(wField, -1); nAbsFirstLine--; nAbsLastLine--; } } } } break; case L'\n': // RETURN if (spaLines[nAbsFirstLine+nRelMarked].fSelectable) { spaLines[nAbsFirstLine+nRelMarked].fSelected = true; bEOI = true; } else { if (multiselect) { for (size_t i = 0; i < nLines; ++i) { if (spaLines[i].fSelected) { bEOI = true; break; } } if (!bEOI) msg = "Line not selectable and still no others selected."; } else { msg = "Line not selectable."; } } /* additionally ask for query strings */ size_t first_visible = nAbsFirstLine; for (size_t i = 0; bEOI && i < nLines; ++i) { if (!spaLines[i].fSelected) continue; Line *l = &spaLines[i]; char *sub_start = memmem(l->cpResult, l->nResult, "%[", 2); if (sub_start) { if (i < first_visible || i >= first_visible + wYSize) first_visible = i; if (first_visible + wYSize > nLines) first_visible = nLines - wYSize; iSelect_Draw(spaLines, wField, wXSize, first_visible, i - first_visible, true, nRelFirstDraw, nRelLastDraw, nLines, sField, title, name, mField, msg); wrefresh(wField); free(l->cpFmtResult); FILE *res = open_memstream(&l->cpFmtResult, &l->nFmtResult); fwrite(l->cpResult, 1, sub_start - l->cpResult, res); char *window = l->cpResult + (sub_start - l->cpResult); size_t winlen = l->nResult - (sub_start - l->cpResult); for (;;) { char *sub_end = memchr(window + 2, ']', winlen - 2); if (sub_end && !(sub_end[1] == 's' || sub_end[1] == 'S')) sub_end = NULL; if (!sub_end) { nosubs: fwrite(window, 1, winlen, res); break; } window += 2, winlen -= 2; size_t sublen = sub_end - window; wmove(mField, 0, 0); while(sublen) { waddnstr(mField, window, sublen); size_t bit = strnlen(window, sublen); window += bit, winlen -= bit, sublen -= bit; while(sublen && !*window) ++window, --winlen, --sublen; } waddstr(mField, ": "); window += 2, winlen -= 2; if (!enter_string(mField, res, sub_end[1] == 's')) { bEOI = false; l->fSelected = false; msg = "Selection cancelled."; break; } msg = ""; sub_start = memmem(window, winlen, "%[", 2); if(!sub_start) goto nosubs; size_t constlen = sub_start - window; fwrite(window, 1, constlen, res); window += constlen, winlen -= constlen; } fclose(res); } } break; case L' ': if (multiselect) { if (spaLines[nAbsFirstLine+nRelMarked].fSelectable) { spaLines[nAbsFirstLine+nRelMarked].fSelected ^= 1; } else { msg = "Line not selectable."; } } else nomultiselect: msg = "No multi-line selection allowed."; break; case L'C': if (multiselect) { for (size_t i = 0; i < nLines; ++i) spaLines[i].fSelected = false; } else goto nomultiselect; break; case L'q': bEOI = true; bQuit = true; break; case L'g': if (nAbsFirstLine+nRelMarked == nFirstLine) msg = "Already at Begin."; else { if (nLastLine < (wYSize-1)) { nAbsFirstLine = nFirstLine; nAbsLastLine = nLastLine; nRelFirstDraw = 0; nRelLastDraw = nLastLine-nFirstLine; nRelMarked = 0; } else { nAbsFirstLine = nFirstLine; nAbsLastLine = nFirstLine+(wYSize-1); nRelFirstDraw = 0; nRelLastDraw = (wYSize-1); nRelMarked = 0; } } break; case L'G': if (nAbsFirstLine+nRelMarked == nLastLine) msg = "Already at End."; else { if (nLastLine < (wYSize-1)) { nAbsFirstLine = nFirstLine; nAbsLastLine = nLastLine; nRelFirstDraw = 0; nRelLastDraw = nLastLine-nFirstLine; nRelMarked = nLastLine-nFirstLine; } else { nAbsFirstLine = nLastLine-(wYSize-1); nAbsLastLine = nLastLine; nRelFirstDraw = 0; nRelLastDraw = (wYSize-1); nRelMarked = (wYSize-1); } } break; case L'h': case L'v': help_version: if (c == 'h') msg = "Help Page: Press 'q' to exit"; else msg = "Version Page: Press 'q' to exit"; const Line *cpp = (c == 'h') ? iSelect_Help : iSelect_README; size_t cpp_len = 0; for (const Line *c = cpp; c->cpLine; ++c) ++cpp_len; size_t first = 0; curs_set(0); while (c != 'q') { iSelect_Draw(cpp, wField, wXSize, first, wYSize - 1, false, 0, wYSize - 1, cpp_len, sField, title, name, mField, msg); switch (c = mapped_key(wField, unmapped_key)) { case iSelect_NextLine: if (first + wYSize < cpp_len) ++first; break; case iSelect_PrevLine: if (first > 0) --first; break; case iSelect_NextPage: if (first + wYSize + wYSize - 1 < cpp_len) first += wYSize; else first = cpp_len - wYSize; break; case iSelect_PrevPage: first = max(first, wYSize) - wYSize; break; case L'\n': // ignored case L' ': // ignored case L'C': // ignored case L'q': // loop condition break; case L'g': first = 0; break; case L'G': first = max(cpp_len - 1, wYSize) - wYSize; break; case L'h': case L'v': goto help_version; } } curs_set(1); nRelFirstDraw = 0; nRelLastDraw = nAbsLastLine-nAbsFirstLine; msg = ""; iSelect_Draw(spaLines, wField, wXSize, nAbsFirstLine, nRelMarked, true, nRelFirstDraw, nRelLastDraw, nLines, sField, title, name, mField, msg); wrefresh(wField); break; default: msg = "Invalid key. Press 'h' for Help Page!"; break; } } echo(); nocbreak(); delwin(wField); if (bQuit) return(-1); else return(nAbsFirstLine+nRelMarked); } /* * The iSelect function... */ ssize_t iSelect(size_t pos, const char *title, const char *name, const char *tagbegin, const char *tagend, bool stripws, bool browsealways, bool allselectable, bool multiselect, bool exitnoselect, enum iSelect_key *unmapped_key) { size_t tagbegin_len = strlen(tagbegin); size_t tagend_len = strlen(tagend); // parse input lines in spaLines into an array of browsable strings: // only cpLine and nLine start filled in for (size_t i = 0; i < nLines; ++i) { size_t tagbeg_off = 0; for (;;) { char *found = memmem(spaLines[i].cpLine + tagbeg_off, spaLines[i].nLine - tagbeg_off, tagbegin, tagbegin_len); if (!found) { tagbeg_off = -1; break; } tagbeg_off = found - spaLines[i].cpLine; if (found[tagbegin_len] == 's' || found[tagbegin_len] == 'S') break; tagbeg_off += tagbegin_len; } if (tagbeg_off != (size_t)-1) { spaLines[i].fSelectable = true; char *itr = spaLines[i].cpLine + tagbeg_off + tagbegin_len + 1; bool have_name = *itr == ':'; // if(have_name) ++itr; char *end = memmem(itr, spaLines[i].cpLine + spaLines[i].nLine - itr, tagend, tagend_len); if(!end || (itr != end && !have_name)) // reject "" goto normal; if(have_name) { spaLines[i].nResult = end - itr; spaLines[i].cpResult = malloc(spaLines[i].nResult); if (!spaLines[i].cpResult) fprintf(stderr, "iSelect: %s\n", strerror(errno)), exit(1); memcpy(spaLines[i].cpResult, itr, spaLines[i].nResult); } // delete the entire tag, which occupies [spaLines[i].cpLine + tagbeg_off, end + tagend_len) size_t delete_len = (end + tagend_len) - (spaLines[i].cpLine + tagbeg_off); if (tagbeg_off == 0) // common case: tag at start of string spaLines[i].cpLine += delete_len; else memmove(spaLines[i].cpLine + tagbeg_off, end + tagend_len, (spaLines[i].cpLine + spaLines[i].nLine) - (end + tagend_len)); spaLines[i].nLine -= delete_len; } else { normal: spaLines[i].fSelectable = allselectable; } if (!spaLines[i].cpResult) { spaLines[i].cpResult = spaLines[i].cpLine; spaLines[i].nResult = spaLines[i].nLine; } if (stripws) strip(&spaLines[i]); } #if 0 for (size_t i = 0; i < nLines; ++i) { fprintf(stderr, "spaLines[%zu] = {\n", i); fprintf(stderr, " cpLine = \""); fwrite(spaLines[i].cpLine, 1, spaLines[i].nLine, stderr); fprintf(stderr, "\"\n"); fprintf(stderr, " nLine = %zu\n", spaLines[i].nLine); fprintf(stderr, " fSelectable = %d\n", spaLines[i].fSelectable); fprintf(stderr, " cpResult = \""); fwrite(spaLines[i].cpResult, 1, spaLines[i].nResult, stderr); fprintf(stderr, "\"\n"); fprintf(stderr, " nResult = %zu\n", spaLines[i].nResult); fprintf(stderr, "}\n"); } #endif wchar_t unget = -1; if (!browsealways && nLines == 0) return -1; if (!browsealways && nLines == 1) { char *sub_start; spaLines[0].fSelected = true; if (spaLines[0].fSelectable && (sub_start = memmem(spaLines[0].cpResult, spaLines[0].nResult, "%[", 2)) && (memmem(sub_start + 2, spaLines[0].nResult - (sub_start + 2 - spaLines[0].cpResult), "]s", 2) || memmem(sub_start + 2, spaLines[0].nResult - (sub_start + 2 - spaLines[0].cpResult), "]S", 2))) { unget = L'\n'; goto show; } return -!spaLines[0].fSelectable; } if (exitnoselect) { for (size_t i = 0; i < nLines; ++i) if (spaLines[i].fSelectable) goto show; return -1; } show: /* * setup Curses package and * open our own first window which holds the complete screen */ signal(SIGINT, diehard); /* die gracefully on interrupt signal */ signal(SIGTERM, diehard); /* die gracefully on terminate signal */ initscr(); /* initialize Curses package */ if(unget != (wchar_t)-1) unget_wch(unget); /* * Now run the browser... */ iSelect_PrepTagStrs(tagbegin, tagend); ssize_t rc = iSelect_Browser(/* Browser: */ LINES-2, COLS-3, 0, 1, pos, multiselect, /* Status: */ 1, COLS, LINES-2, 0, title, name, /* Message: */ 1, COLS-1, LINES-1, 0, /* Result: */ unmapped_key); endwin(); return rc; } ossp-iselect-ISELECT_1_4_2/iselect_help.txt000066400000000000000000000020761471643236400206620ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-2.0-only _ ____ _ _ (_) ___| ___| | ___ ___| |_ / /\___ \ / _ \ |/ _ \/ __| __| / / ___) | __/ | __/ (__| |_ (_( |____/ \___|_|\___|\___|\__| iSelect -- Interactive Selection Tool Cursor Movement: CURSOR-UP ..... Move cursor one line up CURSOR-DOWN ... Move cursor one line down PAGE-UP ....... Move cursor one page up PAGE-DOWN ..... Move cursor one page down g ............. Goto first line G ............. Goto last line Line Selection: RETURN ........ Select line and exit CURSOR-RIGHT .. Select line and exit SPACE ......... Select line and stay (multi-line mode only) C ............. Clear current marks (multi-line mode only) Others: q ............. Quit (exit without selection) CURSOR-LEFT ... Quit (exit without selection) h ............. Help Page (this page) v ............. Version Page ossp-iselect-ISELECT_1_4_2/iselect_keys.c000066400000000000000000000061761471643236400203150ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-2.0-only // Copyright (c) 1997-2007 Ralf S. Engelschall. #include "config.h" #include "iselect.h" #include #include #include #include #include #include #include #include typedef struct CustomKey { enum iSelect_key in; enum iSelect_key out; } CustomKey; static CustomKey*KeyList; static size_t nKeyList; typedef struct keydef { const char *str; enum iSelect_key key; } keydef; static const keydef KeyDef[] = { { "SPACE", L' ' }, { "RETURN", L'\n' }, { "KEY_DOWN", iSelect_NextLine }, { "KEY_UP", iSelect_PrevLine }, { "KEY_NPAGE", iSelect_NextPage }, { "KEY_PPAGE", iSelect_PrevPage }, { "KEY_LEFT", iSelect_Left }, { "KEY_RIGHT", iSelect_Right }, }; void name_key(enum iSelect_key key, FILE *into) { if (key == iSelect_DontKnow){ fputs("UNKNOWN", into); return; } for (size_t i = 1 /* skip SPACE! */; i < sizeof(KeyDef) / sizeof(*KeyDef); ++i) if (KeyDef[i].key == key) { fputs(KeyDef[i].str, into); return; } fprintf(into, "%lc", (wchar_t)key); } static enum iSelect_key asc2key(const char *str) { for (size_t i = 0; i < sizeof(KeyDef) / sizeof(*KeyDef); ++i) if (!strcmp(KeyDef[i].str, str)) return KeyDef[i].key; wchar_t k; int parsed = mbtowc(&k, str, strlen(str)); if (parsed <= 0 || (size_t)parsed != strlen(str) || !iswprint(k)) fprintf(stderr, "iSelect: unknown key %s\n", str), exit(1); return k; } void configure_custom_key(char *config) { const char *in, *out; char *cp; if ((cp = strchr(config, ':')) != NULL) { *cp = '\0'; in = config; out = cp + 1; } else { in = config; out = "RETURN"; } if (!(KeyList = reallocarray(KeyList, ++nKeyList, sizeof(*KeyList)))) fprintf(stderr, "iSelect: %s\n", strerror(errno)), exit(1); KeyList[nKeyList - 1].in = asc2key(in); KeyList[nKeyList - 1].out = asc2key(out); } enum iSelect_key mapped_key(WINDOW *win, enum iSelect_key *unmapped_key) { wint_t ret; switch (wget_wch(win, &ret)) { case ERR: default: return *unmapped_key = iSelect_DontKnow; case OK: // no mapping needed break; case KEY_CODE_YES: switch (ret) { case KEY_DOWN: ret = iSelect_NextLine; break; case KEY_UP: ret = iSelect_PrevLine; break; case KEY_NPAGE: ret = iSelect_NextPage; break; case KEY_PPAGE: ret = iSelect_PrevPage; break; case KEY_LEFT: ret = iSelect_Left; break; case KEY_RIGHT: ret = iSelect_Right; break; default: ret = iSelect_DontKnow; break; } } *unmapped_key = ret; for (size_t i = 0; i < nKeyList; ++i) if ((wint_t)KeyList[i].in == ret) ret = KeyList[i].out; if (ret == iSelect_Left) ret = L'q'; if (ret == iSelect_Right || ret == L'\r') ret = L'\n'; return ret; } ossp-iselect-ISELECT_1_4_2/iselect_main.c000066400000000000000000000222401471643236400202540ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-2.0-only // Copyright (c) 1997-2007 Ralf S. Engelschall. #include "config.h" #include "iselect.h" #include #include #include #include #include #include #include #include #define VERSION \ ISELECT_VERSION_STR "\n" \ "Copyright (c) 1997-2000 Ralf S. Engelschall \n" \ "\n" \ "This program is distributed in the hope that it will be useful,\n" \ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" \ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" \ "GNU General Public License for more details.\n" #define USAGE(self) \ "Usage: %s [options] line...\n" \ " %s [options] < lines\n" \ "\n" \ "Input Options:\n" \ " -d, --delimiter=beg,end selection tag delimiters\n" \ " -c, --strip-comments strip sharp-comments in input buffer\n" \ " -f, --force-browse browse even if input has 0 or only 1 line\n" \ " -a, --all-select force all lines to be selectable\n" \ " -e, --exit-no-select exit immediately if no lines are selectable\n" \ "\n" \ "Display Options:\n" \ " -p, --position=linenum initial line position of cursor\n" \ " -k, --key=key[:okey] enable an additional input key\n" \ " -m, --multi-line allow multiple lines to be selected\n" \ " -n, --name=name program name shown flush-left on status bar\n" \ " -t, --title=title title string shown centered on status bar\n" \ "\n" \ "Output Options:\n" \ " -S, --strip-result strip whitespaces in result string\n" \ " -P, --position-result prefix result string with `N:' (N=line number)\n" \ " -K, --key-result prefix result string with `K:' (K=select key)\n" \ " -Q, --quit-result=fallb result string on quit\n" \ "\n" \ "Giving Feedback:\n" \ " -V, --version display version string\n" \ " -h, --help display this page\n", self, self static const struct option options[] = { { "delimiter", required_argument, NULL, 'd' }, { "strip-comments", no_argument, NULL, 'c' }, { "force-browse", no_argument, NULL, 'f' }, { "all-select", no_argument, NULL, 'a' }, { "exit-no-select", no_argument, NULL, 'e' }, { "position", required_argument, NULL, 'p' }, { "key", required_argument, NULL, 'k' }, { "multi-line", no_argument, NULL, 'm' }, { "name", required_argument, NULL, 'n' }, { "title", required_argument, NULL, 't' }, { "strip-result", no_argument, NULL, 'S' }, { "position-result", no_argument, NULL, 'P' }, { "key-result", no_argument, NULL, 'K' }, { "quit-result", required_argument, NULL, 'Q' }, { "version", no_argument, NULL, 'V' }, { "help", no_argument, NULL, 'h' }, { NULL, no_argument, NULL, '\0' }, }; int main(int argc, char **argv) { setlocale(LC_ALL, ""); size_t pos = 0; const char *title = ""; const char *name = "iSelect"; bool stripco = false; bool stripws = false; bool resultline = false; bool keyresultline = false; bool browsealways = false; bool allselectable = false; bool multiselect = false; bool exitnoselect = false; const char *abortstr = NULL; const char *tagbegin = "<"; const char *tagend = ">"; for (int c; (c = getopt_long(argc, argv, "d:cfaep:k:mn:t:SPKQ:Vh", options, NULL)) != -1;) { char *cp; switch (c) { case 'd': tagbegin = optarg; if ((cp = strchr(tagbegin, ',')) == NULL) return fprintf(stderr, "%s: -d missing ,\n", argv[0]), 1; *cp++ = '\0'; tagend = cp; break; case 'c': stripco = true; break; case 'f': browsealways = true; break; case 'a': allselectable = true; break; case 'e': exitnoselect = true; break; case 'p': { char *pend; pos = strtoull(optarg, &pend, 0); if (*pend) return fprintf(stderr, "%s: -p %s: %s\n", argv[0], optarg, strerror(errno ? errno : EINVAL)), 1; } break; case 'k': configure_custom_key(optarg); break; case 'm': multiselect = true; break; case 'n': name = optarg; break; case 't': title = optarg; break; case 'S': stripws = true; break; case 'P': resultline = true; break; case 'K': keyresultline = true; break; case 'Q': abortstr = optarg; break; case 'V': fputs(VERSION, stdout); return 0; case 'h': fprintf(stderr, USAGE(argv[0])); return 0; } } /* * read input */ if (optind < argc) { /* browsing text is given as arguments */ spaLines = reallocarray(spaLines, argc - optind, sizeof(*spaLines)); if (!spaLines) return fprintf(stderr, "iSelect: %s\n", strerror(errno)), 1; for (int i = 0; i + optind < argc; ++i) { if(stripco && argv[i + optind][0] == '#') continue; spaLines[nLines++] = (Line){.cpLine = argv[i + optind], .nLine = strlen(argv[i + optind])}; } } else { /* browsing text is given on stdin */ char *line = NULL; size_t linecap = 0; for(ssize_t len; (len = getline(&line, &linecap, stdin)) != -1;) { if(stripco && line[0] == '#') continue; if(line[len - 1] == '\n') --len; char *dupline = malloc(len); spaLines = reallocarray(spaLines, ++nLines, sizeof(*spaLines)); if (!spaLines || !dupline) return fprintf(stderr, "iSelect: %s\n", strerror(errno)), 1; memcpy(dupline, line, len); spaLines[nLines - 1] = (Line){.cpLine = dupline, .nLine = len}; } if (ferror(stdin)) return fprintf(stderr, "iSelect: /dev/tty: %s\n", strerror(errno)), 1; free(line); /* reconnect stdin filehandle to tty */ close(0); if (open("/dev/tty", O_RDONLY) == -1) return fprintf(stderr, "iSelect: /dev/tty: %s\n", strerror(errno)), 1; } /* * preserve stdout filehandle for result string, i.e. * use the terminal directly for output */ int fpStdout = dup(1); close(1); if (open("/dev/tty", O_RDWR) == -1) return fprintf(stderr, "iSelect: /dev/tty: %s\n", strerror(errno)), 1; enum iSelect_key unmapped_key = L'\n'; ssize_t p = iSelect(pos, title, name, tagbegin, tagend, stripws, browsealways, allselectable, multiselect, exitnoselect, &unmapped_key); /* * give back the result string to the user via * the stdout file handle */ if (p != -1) { FILE *out = fdopen(fpStdout, "w"); for (size_t i = 0; i < nLines; ++i) { if (spaLines[i].fSelected) { if (resultline) fprintf(out, "%zu:", i+1); if (keyresultline) name_key(unmapped_key, out), fputc(':', out); if (spaLines[i].cpFmtResult) { spaLines[i].cpResult = spaLines[i].cpFmtResult; spaLines[i].nResult = spaLines[i].nFmtResult; } fwrite(spaLines[i].cpResult, 1, spaLines[i].nResult, out); fputc('\n', out); } } } else { if (abortstr != NULL) write(fpStdout, abortstr, strlen(abortstr)); } } ossp-iselect-ISELECT_1_4_2/iselect_readme.txt.in000066400000000000000000000032051471643236400215670ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-2.0-only _ ____ _ _ (_) ___| ___| | ___ ___| |_ / /\___ \ / _ \ |/ _ \/ __| __| / / ___) | __/ | __/ (__| |_ (_( |____/ \___|_|\___|\___|\__| iSelect -- Interactive Selection Tool iSelect is an interactive line selection tool, operating via a full-screen Curses-based terminal session. It can be used either as a user interface frontend controlled by a shell/Perl/Tcl backend as its control script, or in batch mode as a pipe filter (usually between grep and the final executing command). Version @ISELECT_VERSION_LONG@ This is a thawed OSSP project; for git repository/bug tracker/mailing list see https://sr.ht/~nabijaczleweli/ossp The manual is available on-line and at https://srhtcdn.githack.com/~nabijaczleweli/ossp-iselect/blob/man/ossp-iselect.pdf The latest release can be found on http://www.ossp.org/pkg/tool/iselect/ Copyright (c) 1997-2007 Ralf S. Engelschall This program is free software; it may be redistributed and/or modified only under the terms of the GNU General Public License, which may be found in the iSelect source distribution. Look at the file LICENSES/GPL-2.0-only.txt for details. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the the GNU General Public License for more details. Ralf S. Engelschall rse@engelschall.com www.engelschall.com