summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorp-gen <p.gen.progs@gmail.com>2015-08-09 23:00:59 +0200
committerp-gen <p.gen.progs@gmail.com>2015-08-09 23:00:59 +0200
commit3b1efafd57c5ff498463fc725c31cddcf1a01f57 (patch)
treed04c06843b83d3d13fbe2e48c9d3349f3a7fb053
First commit.v0.9
-rw-r--r--.indent.pro38
-rw-r--r--COPYRIGHT3
-rw-r--r--INTERNALS.rst56
-rw-r--r--LICENSE.md264
-rw-r--r--Makefile57
-rw-r--r--README.rst102
-rw-r--r--TODO4
-rw-r--r--smenu.1255
-rw-r--r--smenu.c3737
-rw-r--r--smenu.h84
-rw-r--r--version1
11 files changed, 4601 insertions, 0 deletions
diff --git a/.indent.pro b/.indent.pro
new file mode 100644
index 0000000..4632183
--- /dev/null
+++ b/.indent.pro
@@ -0,0 +1,38 @@
+--blank-lines-after-commas
+--declaration-comment-column 30
+--brace-indent 0
+--braces-after-if-line
+--braces-after-struct-decl-line
+--break-after-boolean-operator
+--case-brace-indentation 0
+--case-indentation 2
+--continue-at-parentheses
+--declaration-indentation 2
+--dont-break-procedure-type
+--dont-cuddle-do-while
+--dont-cuddle-else
+--dont-format-first-column-comments
+--dont-space-special-semicolon
+--honour-newlines
+--indent-level 2
+--leave-optional-blank-lines
+--line-length 80
+--no-blank-lines-before-block-comments
+--no-comment-delimiters-on-blank-lines
+--no-space-after-function-call-names
+--no-space-after-parentheses
+--no-tabs
+--no-blank-lines-after-commas
+--procnames-start-lines
+--space-after-cast
+--space-after-for
+--space-after-if
+--space-after-while
+--struct-brace-indentation 0
+--swallow-optional-blank-lines
+--blank-lines-after-procedures
+//--blank-lines-after-declarations
+--break-before-boolean-operator
+--comment-indentation 30
+--continue-at-parentheses
+--comment-line-length 80
diff --git a/COPYRIGHT b/COPYRIGHT
new file mode 100644
index 0000000..ee948bc
--- /dev/null
+++ b/COPYRIGHT
@@ -0,0 +1,3 @@
+(c) Pierre Gentile (p.gen.progs@gmail.com)
+
+License: GPLv2
diff --git a/INTERNALS.rst b/INTERNALS.rst
new file mode 100644
index 0000000..2178de1
--- /dev/null
+++ b/INTERNALS.rst
@@ -0,0 +1,56 @@
+Words are read into two datastructures:
+
+To illustrate these datastructures, we will suppose the following input text::
+
+ a b c d e f g h
+ a b a d
+ f g h
+
+ z
+
+The main datastructures are:
+
+- An array indexed by their order of appearance.
+
+ This is not purely a string array, words are structures which contain the
+ following informations:
+
+ - the display string which can be shorter than the original string;
+ - the original string;
+ - a flag indicating the this is the last word in a paragraph like
+ **h**, **d**, **h** and **z** if our example test;
+ - positional infomations: column start, column end end an number of
+ multibyes between the two.
+
+ The following text will be put in the word array::
+
+
+ last=1 last=1 last=1 last=1
+ | | | |
+ +---+---+---+---+---+---+---+-v-+---+---+---+-v-+---+---+-v-+-v-+
+ | a | b | c | d | e | f | g | h | a | b | a | d | f | g | h | z |
+ +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ 0 1 . . . 13 14 15
+
+- A Ternary Search Treee (TST) which store their position in the array
+ and all their furure positions if their appear multiple times.
+
+ In the TST tree, index lists are attached to the input words::
+
+ +---+---+----+
+ a | 0 | 8 | 10 |
+ +---+---+----+
+
+ +---+---+
+ b | 1 | 9 |
+ +---+---+
+
+ +---+
+ c | 2 |
+ +---+
+
+ and so on.
+
+ This TST is used when searching a word using the ``/`` command or when using
+ the ``-s`` commandline option.
+
diff --git a/LICENSE.md b/LICENSE.md
new file mode 100644
index 0000000..0671f06
--- /dev/null
+++ b/LICENSE.md
@@ -0,0 +1,264 @@
+The GNU General Public License, Version 2, June 1991 (GPLv2)
+============================================================
+
+> Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+> 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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.
+
+
+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.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..eca6a36
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,57 @@
+# Some variables
+CC = gcc
+RM = rm
+CURSES=ncurses
+
+TAG=`if git status >/dev/null 2>&1; then \
+ echo "git "; \
+else \
+ test -f version && cat version; \
+fi`
+
+VERSION=`if git status >/dev/null 2>&1; then \
+ git log -n 1 --pretty=format:"%h"; \
+else \
+ echo ""; \
+fi`
+
+DATE=`if git status >/dev/null 2>&1; then \
+ echo ", build: "\`date +%x_%Z\`; \
+else \
+ echo ", build: "\`date +%x_%H:%M_%Z\`; \
+fi`
+
+# Compilation and link phases options
+CFLAGS = -c -g -O2 -Wall -Wextra
+LFLAGS = -l$(CURSES)
+
+# The build target
+OBJS = smenu.o
+TARGET = smenu
+
+# The rules
+all: $(TARGET)
+
+.c.o :
+ @echo "CC " $<
+ @$(CC) $(CFLAGS) -DVERSION=\""$(TAG)$(VERSION)$(DATE)"\" $<
+
+$(TARGET): $(OBJS)
+ @echo CCLD $<
+ @$(CC) -o $@ $(OBJS) $(LFLAGS)
+
+clean:
+ $(RM) -f $(OBJS) $(TARGET) smenu-*.tar.gz core
+
+strip:
+ strip $(TARGET)
+
+archive:
+ @if git status >/dev/null 2>&1; then \
+ V=$(VERSION); \
+ if git archive --prefix=smenu-$${V}/ -o smenu-$${V}.tar.gz $${V}; then \
+ echo "smenu-$${V}.tar.gz written."; \
+ fi \
+ else \
+ echo "This is not a git repository."; \
+ fi
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..bdc841e
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,102 @@
+What is it?
+===========
+**smenu** is a selection filter just like ``sed`` is an editing filter.
+
+This simple tool reads words from the standard input, presents them in
+a cool interactive window after the current line on the terminal and writes
+the selected word, if any, on the standard output.
+
+After having unsuccessfully searched the NET for what I wanted, I
+decided to try to write my own.
+
+I have tried hard to made its usage as simple as possible. It should
+work, even when using an old ``vt100`` terminal and is ``UTF-8`` aware.
+
+How to build?
+=============
+**smenu** can be built on every system where a working ``terminfo``
+developpement platform is available. This includes every Unix and Unix
+like systems I am aware of.
+
+You may need to adjust the ``CURSES`` variable in the Makefile. On Linux,
+by example, you need ``ncurses``.
+
+After that, a simple ``make`` should be sufficient to build the program.
+
+There is no installation procedure as all that is required to do is to
+put the resulting binary and the man page in their traditional places.
+
+Some examples.
+==============
+
+Linux example.
+--------------
+This program should work on most Unix but if you are using Linux,
+try to type the following line at a shell prompt (here: ``"$ "`` ):
+
+::
+
+ $ R=$(grep Vm /proc/$$/status \
+ | IFS=$':\n' smenu -n20 -q -c -b -g -s /VmH)
+ $ echo $R
+
+Something like this should now be displayed with the program waiting
+for commands: (numbers are mine, yours will be different)
+
+::
+
+ VmPeak¦ 23840 kB¦
+ VmSize¦ 23836 kB¦
+ VmLck ¦ 0 kB¦
+ VmHWM ¦ 2936 kB¦
+ VmRSS ¦ 2936 kB¦
+ VmData¦ 1316 kB¦
+ VmStk ¦ 136 kB¦
+ VmExe ¦ 28 kB¦
+ VmLib ¦ 3956 kB¦
+ VmPTE ¦ 64 kB¦
+ VmSwap¦ 0 kB¦
+
+A cursor should be under ``"VmHWM "``.
+
+After having moved the cursor to ``" 136 kB"`` and ended the program
+with ``<Enter>``, the shell variable R should contain: ``" 136 kB"``.
+
+.. raw:: pdf
+
+ PageBreak
+
+Unix example.
+-------------
+The following command, which is Unix brand agnostic, should give you a
+scrolling window if you have more than 10 accounts on your Unix with a
+UID lower than 100:
+
+::
+
+ $ R=$(awk -F: '$3 < 100 {print $1,$3,$4,$NF}' /etc/passwd \
+ | smenu -n10 -c)
+ $ echo $R
+
+On mine (``LANG`` and ``LC_ALL`` set to ``POSIX``) it displays:
+
+::
+
+ at 25 25 /bin/bash \
+ sys 0 3 /usr/bin/ksh +
+ bin 1 1 /bin/bash |
+ daemon 2 2 /bin/bash |
+ ftp 40 49 /bin/bash |
+ games 12 100 /bin/bash |
+ lp 4 7 /bin/bash |
+ mail 8 12 /bin/false |
+ named 44 44 /bin/false |
+ ntp 74 108 /bin/false v
+
+Note the presence of a scrollbar.
+
+Interested?
+-----------
+Please read the included man page to learn more about this little program.
+
+On Linux, ``man ./smenu.1`` will do it.
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..67b9de2
--- /dev/null
+++ b/TODO
@@ -0,0 +1,4 @@
+# B: Bugs to fix, I: possible Improvements
+# ========================================.
+I improve the notion of input words (enable quotation).
+I enable multi-lines messages
diff --git a/smenu.1 b/smenu.1
new file mode 100644
index 0000000..3f66617
--- /dev/null
+++ b/smenu.1
@@ -0,0 +1,255 @@
+.TH smenu 1 "May 2015" "Version 0.9"
+.SH NAME
+smenu - filter that allows to interactively select a word from stdin
+and outputs the selection to stdout.
+.SH SYNOPSIS
+smenu [\fB-h\fP] [\fB-n\fP \fIlines\fP] [\fB-t\fP [\fIcols\fP]]
+[\fB-s\fP \fIpattern\fP] [\fB-m\fP \fImessage\fP] [\fB-w\fP] [\fB-d\fP]
+[\fB-c\fP] [\fB-e\fP] [\fB-b\fP] [\fB-g\fP] [\fB-q\fP]
+.SH DESCRIPTION
+This small utility acts as a filter (read from stdin and write to
+stdout). All the words taken from stdin are presented in a scrolling
+window on the terminal with a selection cursor initially positioned on
+the first word by default.
+.P
+If the \fBIFS\fP variable is set, each of its character (or multibyte
+sequence) will be used to delimit the words when reading them. Default
+delimiters are: \fISPACE\fP, \fI\\t\fP and \fI\\n\fP.
+.P
+Non printable characters in words that are not a delimiter are
+converted to their traditional form (\fI\\n\fP for end-of-line,
+\fI\\t\fP for tabulation...) by default. A single dot (\fI.\fP) is also
+used as a placeholder otherwise.
+.P
+\fBWarning\fP, \fBUTF-8\fP encoded codepoints are quietly converted
+into a dot (\fI.\fP) when the user locale is not \fBUTF-8\fP aware like
+\fBPOSIX\fP or \fBC\fP by example.
+.P
+If a word is only containing spaces, then all of them are
+converted into underscores (\fI_\fP) so that we can see them.
+.P
+.SS "Moving among words"
+The cursor can then be moved in every directions by using the
+traditional arrow keys or the \fIvi\fP direction keys (\fBh\fP,
+\fBj\fP, \fBk\fP and \fBl\fP). \fBHOME\fP, \fBEND\fP, \fBPgDn\fP and
+\fBPGUp\fP can also be used if available and have their traditional
+meanings.
+.SS "Searching for a word"
+The \fB/\fP or \fB^F\fP (\fBCtrl-f\fP) can be used to initiate a
+research by prefix among the words after the cursor.
+.P
+After that the cursor attribute is modified and all the characters
+entered 7s after this change goes in a search buffer with the cursor
+moving immediately to the next word matching this prefix. Any character
+entered within 5s after that completes that buffer and resets the 5s
+timer and possibly moves the cursor again.
+.P
+As soon as the timer expiates, the search mode is ended and the
+cursor regains its initial appearance.
+.P
+The search buffer if persistent as long as the cursor is on a matching
+word when a new research is initialized.
+.br
+If the beginning of the word under the cursor does not match the
+previous search buffer, then the search buffer if erased.
+.P
+At any time in this mode you can move the cursor with the keys
+described above. \fBESC\fP ends this mode immediately.
+.P
+The \fBSPACE\fP or \fBn\fP keys repeats the last research if the search
+buffer is not empty. As in search mode, nothing happens if there is no
+matching word after the cursor.
+.P
+Note that only the \fBSPACE\fP key can be used when the search mode is
+active because the \fBn\fP character must be available if you want to
+search a word containing this character.
+.SS "Selection and Exit"
+Hitting \fBq\fP exits without outputting anything, nothing is selected.
+.P
+By default, hitting \fBENTER\fP writes the selected word to stdout when
+not in search mode. In search mode \fBENTER\fP ends this mode and do
+nothing more. If you want to be able to select a word \fIeven\fP in
+search mode, use the \fB-e\fP option to change this behavior.
+.SS Help
+A small help message can be displayed when hitting \fB?\fP. This display
+will last for 10s or until a valid key or \fBESC\fP is pressed.
+.SS Scrollbar
+A scroll bar is displayed at the left of the scrolling window. Its
+appearance is meant to be classical but it has some particularities:
+.IP * 2
+The scroll bar is displayed only if all the words could not be
+displayed on the terminal .
+.IP * 2
+When the scrolling window has only one line, the scroll bar has only 3
+states:
+.RS 2
+.IP - 2
+"\fBv\fP" when on all but the last line, indicating that you can go down
+to see more.
+.IP - 2
+"\fB^\fP" when on the last line.
+.IP - 2
+"\fB|\fP" otherwise.
+.RE
+.IP * 2
+When there is more than 1 line to display, "\fB/\fP" means that the window
+displays the first line, "\fB\\\fP" the last line. "\fB|\fP" is used to fill
+the gap, see below the different possibles configurations.
+.TS
+l l l l l
+l l l l l
+l l l l.
+\\ \\ ^ ^ \\
+| | | | /
+/ v / v
+.TE
+.P
+A "\fB+\fP" can also appear in the scroll bar in lieu of a "\fB|\fP",
+giving the relative position of the cursor line in the bunch of input
+words.
+.SS "Terminal resizing"
+The windows is redrawn is the terminal is resized. The redrawing is
+actually done only 1s after the end of the resizing to avoid artefacts
+on screen. The cursor will remain on the current selected word but may
+be displayed on another place in the window.
+.SS Unicode support
+This utility is Unicode aware and should be able to display correctly
+any Unicode character (even double-width ones) as long as the current
+encoding is \fBUTF-8\fP (\fBUTF-8\fP in the output of the \fIlocale\fP
+command).
+.SH OPTIONS
+.IP \fB-h\fP
+Display a shot help message and exists.
+.IP "\fB-n\fP \fIlines\fB"
+Gives the maximum number of lines in the scrolling selection window. By
+default five lines at most are displayed and the other ones, if
+any, need you to scroll the window.
+.IP "\fB-t\fP [\fIcolumns\fP]"
+This option sets the tabulation mode and, if a number is specified,
+limits the number of displayed columns to that number.
+.IP "\fB-s\fP \fIpattern\fP"
+Pre-Position the cursor to the specified pattern. \fIpattern\fP" can be:
+.RS
+.IP * 2
+A \fBnumber\fP giving the initial position of the cursor (counting from
+0). If this number if greater than the number of words, the cursor will
+be set on la last position.
+.IP * 2
+The string \fBlast\fP meaning that we want the initial position to be
+on the last word.
+.IP * 2
+A string starting with a "\fB/\fP" indicating that we want the cursor
+to be set on the first word matching the \fBprefix\fP string following
+the "\fB/\fP" (\fB/Ca\fP will match \fBCancel\fP by example).
+.PP
+Every failure will no nothing resulting with the cursor set on the
+first word.
+.RE
+.IP "\fB-m\fP \fImessage\fP"
+Permits to display a message above the window. Beware, it will be
+truncated to only being displayed on \fIone\fP line.
+.IP "\fB-w\fP"
+When \fB-t\fP is used, the default is to compact the columns so that
+they use the less terminal width as possible. This option enlarges the
+columns in order to cover the whole terminal width when a number of
+columns is specified.
+.P
+Notice that the column's size is only calculated once when the
+words are displayed for the first time. A terminal resize will not
+alter this value. This choice permits a faster display.
+.P
+.RS
+Note that if this mode each column has the same width.
+.RE
+.IP \fB-d\fP
+Tells the program to clean up the display before quitting by removing
+the selection window after use as if it were never displayed. The
+terminal may have been scrolled up anyway if the previous window
+display needed it.
+.IP \fB-c\fP
+Sets the column mode. In this mode the lines of words do not wrap when
+the right border of the terminal is reached but only when a special
+character is read. Some words will not be displayed without an
+horizontal scrolling.
+.RS
+.P
+If such a scrolling is needed, an horizontal scroll bar will be
+displayed at the top of the window.
+.P
+In this mode, the width of each column is minimal to keep the maximum
+information visible on the terminal.
+.P
+The line terminator is "\fI\\n\fR" by default is the shell variable
+\fBIRS\fP is undefined. Otherwise its characters (or multibyte sequence)
+will be used as a line terminator. Characters (or multibyte sequences)
+in \fBIRS\fP are automatically added to the list of word delimiters.
+.RE
+.IP \fB-e\fP
+Enables \fBENTER\fP to validate the selection even in search mode.
+.IP \fB-b\fP
+Replace all non-printable characters by a blank.
+.IP \fB-g\fP
+Replaces the blank after each words in normal tabular mode by a vertical
+bar "\fB|\fP". Some users may find the output more readable like that.
+.IP \fB-q\fP
+Prevents the scrollbar display. Useful when all the input words can be
+displayed without the need of scrolling. by default the scrollbar is
+always displayed when there is more than one line. An absence of cursor
+in it gives a visual indication that all the input words are there.
+.SH NOTES
+If tabulations (\fI\\t\fP) are embedded in the input, there is no way
+to replace them with the original number of spaces. In this case use
+an other filter (like \fIexpand\fR) to pre-process the data.
+.SH EXAMPLES
+.SS 1
+Simple Yes/No/Cancel request with "No" as default choice:
+.P
+.nf
+In \fBbash\fP: \fBread R <<< $(echo "Yes No Cancel" \\
+ | smenu -d -m "Please choose:" -s /N)\fP
+
+ or \fBR=$(echo "Yes No Cancel" \\
+ | smenu -d -m "Please choose:" -s /N)\fP
+
+In \fBksh\fP: \fBprint "Yes No Cancel" \\
+ | smenu -d -m "Please choose:" -s /N \\
+ | read R\fP
+.fi
+.SS 2
+Get a 3 columns report about VM statistics for the current process in
+\fBbash\fP/\fBksh\fP on Linux:
+.P
+.nf
+\fBR=$(grep Vm /proc/$$/status | expand | IFS=$'\\n' smenu -b -t3 -g -d)\fB
+.P
+.fi
+.SS 3
+Create a one column selection window containing the list of the first
+20 LVM physical volumes. At end, the selection window will be erased.
+This example is written in \fBksh\fP).
+.P
+.nf
+\fBpvs -a -o pv_name --noheadings \\
+| smenu -m "PV list" -n20 -t1 -d -s //dev/root \\
+| read R\fP
+.fi
+.P
+The display will have a look similar to the following with the cursor
+set on the word \fI/dev/root\fP:
+.P
+.nf
+PV list
+/ /dev/md126
+| /dev/md127
+| /dev/root <- cursor here
+| /dev/sda2
+| /dev/sdb2
+| /dev/sdc1
+| /dev/sdc2
+\\ /dev/system/homevol
+.fi
+.SH BUGS
+None that I am aware of. If you found one, please tell me.
+.SH AUTHOR
+\(co 2015 Pierre Gentile (p.gen.progs@gmail.com)
+.SH SEE ALSO
diff --git a/smenu.c b/smenu.c
new file mode 100644
index 0000000..dcad3d2
--- /dev/null
+++ b/smenu.c
@@ -0,0 +1,3737 @@
+/* ################################################################### */
+/* Copyright 2015 - Pierre Gentile */
+/* */
+/* This Software is licensed under the GPL licensed Version 2, */
+/* please read http://www.gnu.org/copyleft/gpl.html */
+/* */
+/* 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. */
+/* */
+/* This software 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. */
+/* ################################################################### */
+
+#define CHARSCHUNK 8
+#define WORDSCHUNK 8
+#define COLSCHUNK 16
+
+#define _XOPEN_SOURCE 600
+#include <termios.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <ctype.h>
+#include <string.h>
+#include <unistd.h>
+#include <locale.h>
+#include <langinfo.h>
+#include <term.h>
+#include <errno.h>
+#include <wchar.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include "smenu.h"
+
+int bar_color; /* scrollbar color */
+int count = 0; /* number of words read from stdin */
+int current; /* index the current selection *
+ * (under the cursor) */
+int new_current; /* final current position, (used in *
+ * search function) */
+int *line_nb_of_word_a; /* array containig the line number *
+ * (from 0) of each word read */
+int *first_word_in_line_a; /* array containing the index of *
+ * the first word of each lines */
+int search_mode = 0; /* 1 if in search mode else 0 */
+int help_mode = 0; /* 1 if help is display else 0 */
+
+int (*my_isprint) (int);
+
+static int delims_cmp(const void *a, const void *b);
+
+/* UTF-8 usefull symbols */
+/* """"""""""""""""""""" */
+char *sbar_broken_line = "\xc2\xa6"; /* broken_bar */
+char *sbar_arr_left = "\xe2\x86\x90"; /* leftwards_arrow */
+char