diff --git a/gnu/usr.bin/dialog/COPYING b/gnu/usr.bin/dialog/COPYING new file mode 100644 index 000000000000..a43ea2126fb6 --- /dev/null +++ b/gnu/usr.bin/dialog/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, 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 + + Appendix: 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., 675 Mass Ave, Cambridge, MA 02139, 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. diff --git a/gnu/usr.bin/dialog/Makefile b/gnu/usr.bin/dialog/Makefile new file mode 100644 index 000000000000..47e7a38eb53b --- /dev/null +++ b/gnu/usr.bin/dialog/Makefile @@ -0,0 +1,11 @@ +PROG= dialog +MAN1= dialog.1 + +CFLAGS+= -Wall -Wstrict-prototypes -DHAVE_NCURSES -DLOCALE +DPADD= $(LIBNCURSES) $(LIBMYTINFO) +LDADD= -lncurses -lmytinfo + +SRCS = dialog.c rc.c checklist.c inputbox.c menubox.c msgbox.c \ +radiolist.c textbox.c yesno.c + +.include "bsd.prog.mk" diff --git a/gnu/usr.bin/dialog/README b/gnu/usr.bin/dialog/README new file mode 100644 index 000000000000..975bdac54b43 --- /dev/null +++ b/gnu/usr.bin/dialog/README @@ -0,0 +1,161 @@ + + dialog - Display dialog boxes in shell script (version 0.3) + =========================================================== + +This is a program that will enable you to present a variety of questions or +display messages using dialog boxes from a shell script. Currently, these +types of dialog boxes are implemented: yes/no box, menu box, input box, +message box, text box, info box, checklist box. The idea of writing this +program came from the fact that most questions asked in a shell script (and +many interactive programs as well) can be classified into these few types: + + + 1) One that requires the user to answer either yes or no. + + 2) One that presents a number of options for the user to choose. + + 3) One that requires the user to input a string. + + 4) One that displays a message and optionally wait for a key press + before continuing. + + 5) One that presents a list of options that can be turned on or off. + + +The program 'dialog' can, say for example, be called in a shell script to +present the first type of questions like this: + + + if dialog --yesno + then + ... + fi + + + e.g. if dialog --yesno "Do you want to continue?" 7 51 + then + echo "Continuing..." + else + echo "Aborting..." + fi + + +I've included a sample shell script for each type of boxes in the directory +samples. The program requires ncurses to compile. Running 'dialog' without +arguments will display the usage. + + + +FEATURES +-------- + + * Friendly dialog box interface with buttons, etc. + + * Auto wrap around of question text if it's too long to fit on + one line. + + * "\n" can be inserted in question text to control line breaking + explicitly. The real newline character '\n' can also be used. + + * run-time configruation of color settings and other options using + a configuration file. + + + +WHAT'S NEW SINCE VERSION 0.21? +------------------------------ + + * some changes for faster screen update. + + * much more flexible color settings. Can use all 16 colors + (8 normal, 8 highlight) of the Linux console. + + * added run-time configuration using configuration file. + + * some minor bug fixes and cleanups for menubox, checklist and + textbox. + + * added a man page. + + * some changes for easier porting to other Unix systems (tested + on Ultrix, SunOS and HPUX) + + + +INSTALLATION +------------ + + 1. cd ./src + + 2. Go to step 3 if your system has ncurses (e.g. Linux). + Edit Makefile and remove -DHAVE_NCURSES from DEFS. Also + remove rc.c from SRCS and rc.o from OBJS. Change LIBS as + appropriate (Usually, it should be '-lcurses -ltermcap'). + Go to step 6. + + 3. Edit Makefile and remove -DBROKEN_WSCRL from DEFS if you + are using ncurses 1.8.3 or newer. Menu scrolling should + be faster. DON'T REMOVE IT IF YOU ARE NOT USING AT LEAST + VERSION 1.8.3 OF NCURSES. + + 4. Edit dialog.h and change USE_SHADOW to FALSE if you don't + want shadowed dialog boxes. Also change USE_COLORS to + FALSE if you don't want colors. Note that 'dialog' will + check if the terminal supports colors, and will use mono + settings if it doesn't, so USE_COLORS won't do any harm + even if you have a mono display. Also note that USE_SHADOW + implies USE_COLORS. These two options can be changed at + run-time using the run-time configuration file (see below). + + 5. Edit colors.h to change default color definitions if you + don't like the defaults. These are only compiled in defaults, + you can change them at run-time using the run-time + configuration file. + + 6. 'make depend; make install' will compile and install the + binaries in /usr/local/bin (change BINDIR in Makefile if + you want to install elsewhere). + + 7. 'make install.man' will install the man page to + /usr/local/man (change MANDIR in Makefile if you want to + install elsewhere). + + 8. You can then try the sample shell scripts in the samples + directory (make sure the environment variable DIALOG is + not set, the scripts use it to find the dialog binary, if + it's not set, "../src/dialog" will be used). + + 9. Don't forget to mail me (mail address at end of this file) + if you find any bugs, have some good color settings to + contribute or just want to tell me that you like it, Don't + mail me if you don't like it :-) + + + +RUN-TIME CONFIGURATION +---------------------- + + 1. Create a sample configuration file by typing: + + "dialog --create-rc " + + 2. At start, 'dialog' determines the settings to use as follows: + + a) if environment variable DIALOGRC is set, it's value + determines the name of the configuration file. + + b) if the file in (a) can't be found, use the file + $HOME/.dialogrc as the configuration file. + + c) if the file in (b) can't be found, use compiled in + defaults. + + 3. Edit the sample configuration file and copy it to some place + that 'dialog' can find, as stated in step 2 above. + + + + +Comments and bug reports welcome. + +- Savio Lam (lam836@cs.cuhk.hk) diff --git a/gnu/usr.bin/dialog/TESTS/checklist b/gnu/usr.bin/dialog/TESTS/checklist new file mode 100755 index 000000000000..38fdc3510dc5 --- /dev/null +++ b/gnu/usr.bin/dialog/TESTS/checklist @@ -0,0 +1,32 @@ +#!/bin/sh +DIALOG=${DIALOG=/usr/bin/dialog} + +$DIALOG --title "CHECKLIST BOX" --clear \ + --checklist "Hi, this is a checklist box. You can use this to \n\ +present a list of choices which can be turned on or \n\ +off. If there are more items than can fit on the \n\ +screen, the list will be scrolled. You can use the \n\ +UP/DOWN arrow keys, the first letter of the choice as a \n\ +hot key, or the number keys 1-9 to choose an option. \n\ +Press SPACE to toggle an option on/off. \n\n\ + Which of the following are fruits?" 20 61 5 \ + "Apple" "It's an apple." off \ + "Dog" "No, that's not my dog." ON \ + "Orange" "Yeah, that's juicy." off \ + "Cat" "No, never put a dog and a cat together!" oN \ + "Fish" "Cats like fish." On \ + "Lemon" "You know how it tastes." on 2> /tmp/checklist.tmp.$$ + +retval=$? + +choice=`cat /tmp/checklist.tmp.$$` +rm -f /tmp/checklist.tmp.$$ + +case $retval in + 0) + echo "'$choice' chosen.";; + 1) + echo "Cancel pressed.";; + 255) + echo "ESC pressed.";; +esac diff --git a/gnu/usr.bin/dialog/TESTS/infobox b/gnu/usr.bin/dialog/TESTS/infobox new file mode 100755 index 000000000000..764dc0811a56 --- /dev/null +++ b/gnu/usr.bin/dialog/TESTS/infobox @@ -0,0 +1,15 @@ +#!/bin/sh +DIALOG=${DIALOG=/usr/bin/dialog} + +$DIALOG --title "INFO BOX" \ + --infobox "Hi, this is an information box. It is +different from a message box in that it will +not pause waiting for input after displaying +the message. The pause here is only introduced +by the sleep command, not by dialog. + +You have 10 seconds to read this..." 10 52 + +stty -echo +sleep 10 +stty echo diff --git a/gnu/usr.bin/dialog/TESTS/inputbox b/gnu/usr.bin/dialog/TESTS/inputbox new file mode 100755 index 000000000000..e04756a51285 --- /dev/null +++ b/gnu/usr.bin/dialog/TESTS/inputbox @@ -0,0 +1,26 @@ +#!/bin/sh +DIALOG=${DIALOG=/usr/bin/dialog} + +$DIALOG --title "INPUT BOX" --clear \ + --inputbox "Hi, this is an input dialog box. You can use \n\ +this to ask questions that require the user \n\ +to input a string as the answer. You can \n\ +input strings of length longer than the \n\ +width of the input box, in that case, the \n\ +input field will be automatically scrolled. \n\ +You can use BACKSPACE to correct errors. \n\n\ +Try inputing your name below:" 16 51 2> /tmp/inputbox.tmp.$$ + +retval=$? + +input=`cat /tmp/inputbox.tmp.$$` +rm -f /tmp/inputbox.tmp.$$ + +case $retval in + 0) + echo "Input string is '$input'";; + 1) + echo "Cancel pressed.";; + 255) + echo "ESC pressed.";; +esac diff --git a/gnu/usr.bin/dialog/TESTS/menubox b/gnu/usr.bin/dialog/TESTS/menubox new file mode 100755 index 000000000000..4883c7c53a04 --- /dev/null +++ b/gnu/usr.bin/dialog/TESTS/menubox @@ -0,0 +1,33 @@ +#!/bin/sh +DIALOG=${DIALOG=/usr/bin/dialog} + +$DIALOG --clear --title "MENU BOX" \ + --menu "Hi, this is a menu box. You can use this to \n\ +present a list of choices for the user to \n\ +choose. If there are more items than can fit \n\ +on the screen, the menu will be scrolled. \n\ +You can use the UP/DOWN arrow keys, the first \n\ +letter of the choice as a hot key, or the \n\ +number keys 1-9 to choose an option.\n\ +Try it now!\n\n\ + Choose the OS you like:" 20 59 4 \ + "FreeBSD 2.0" "A Real Operating System for Real Users" \ + "Linux" "Another free Unix Clone for 386/486" \ + "OS/2" "IBM OS/2" \ + "WIN NT" "Microsoft Windows NT" \ + "PCDOS" "IBM PC DOS" \ + "MSDOS" "Microsoft DOS" 2> /tmp/menu.tmp.$$ + +retval=$? + +choice=`cat /tmp/menu.tmp.$$` +rm -f /tmp/menu.tmp.$$ + +case $retval in + 0) + echo "'$choice' chosen.";; + 1) + echo "Cancel pressed.";; + 255) + echo "ESC pressed.";; +esac diff --git a/gnu/usr.bin/dialog/TESTS/msgbox b/gnu/usr.bin/dialog/TESTS/msgbox new file mode 100755 index 000000000000..58dae1581af1 --- /dev/null +++ b/gnu/usr.bin/dialog/TESTS/msgbox @@ -0,0 +1,14 @@ +#!/bin/sh +DIALOG=${DIALOG=/usr/bin/dialog} + +$DIALOG --title "MESSAGE BOX" --clear \ + --msgbox "Hi, this is a simple message box. You can use this to \ + display any message you like. The box will remain until \ + you press the ENTER key." 10 41 + +case $? in + 0) + echo "OK";; + 255) + echo "ESC pressed.";; +esac diff --git a/gnu/usr.bin/dialog/TESTS/textbox b/gnu/usr.bin/dialog/TESTS/textbox new file mode 100755 index 000000000000..ed7c2d977139 --- /dev/null +++ b/gnu/usr.bin/dialog/TESTS/textbox @@ -0,0 +1,42 @@ +#!/bin/sh +DIALOG=${DIALOG=/usr/bin/dialog} + +cat << EOF > /tmp/textbox.tmp.$$ +Hi, this is a text dialog box. It can be used to display text from a file. +The file should not contain any 'tab' characters, so you should 'expand' +the file first if it contains 'tab' characters. + +It's like a simple text file viewer, with these keys implemented: + +PGDN/SPACE - Move down one page +PGUP/'b' - Move up one page +DOWN/'j' - Move down one line +UP/'k' - Move up one line +LEFT/'h' - Scroll left +RIGHT/'l' - Scroll right +'0' - Move to beginning of line +HOME/'g' - Move to beginning of file +END/'G' - Move to end of file +'/' - Forward search +'?' - Backward search +'n' - Repeat last search (forward) +'N' - Repeat last search (backward) + + +The following is a sample text file: + + +EOF + +cat ../COPYING | expand >> /tmp/textbox.tmp.$$ + +$DIALOG --clear --title "TEXT BOX" --textbox "/tmp/textbox.tmp.$$" 22 77 + +case $? in + 0) + echo "OK";; + 255) + echo "EXIT choosed.";; +esac + +rm -f /tmp/textbox.tmp.$$ diff --git a/gnu/usr.bin/dialog/TESTS/yesno b/gnu/usr.bin/dialog/TESTS/yesno new file mode 100755 index 000000000000..22828938f7de --- /dev/null +++ b/gnu/usr.bin/dialog/TESTS/yesno @@ -0,0 +1,21 @@ +#!/bin/sh +DIALOG=${DIALOG=/usr/bin/dialog} + +$DIALOG --title "YES/NO BOX" --clear \ + --yesno "Hi, this is a yes/no dialog box. You can use this to ask \ + questions that have an answer of either yes or no. \ + BTW, do you notice that long lines will be automatically \ + wrapped around so that they can fit in the box? You can \ + also control line breaking explicitly by inserting \ + 'backslash n' at any place you like, but in this case, \ + auto wrap around will be disabled and you will have to \ + control line breaking yourself." 15 61 + +case $? in + 0) + echo "Yes chosen.";; + 1) + echo "No chosen.";; + 255) + echo "ESC pressed.";; +esac diff --git a/gnu/usr.bin/dialog/checklist.c b/gnu/usr.bin/dialog/checklist.c new file mode 100644 index 000000000000..f522ae14db0d --- /dev/null +++ b/gnu/usr.bin/dialog/checklist.c @@ -0,0 +1,349 @@ +/* + * checklist.c -- implements the checklist box + * + * AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include "dialog.h" + + +static void print_item(WINDOW *win, unsigned char *tag, unsigned char *item, int status, int choice, int selected); + + +static int list_width, check_x, item_x; + + +/* + * Display a dialog box with a list of options that can be turned on or off + */ +int dialog_checklist(unsigned char *title, unsigned char *prompt, int height, int width, int list_height, int item_no, unsigned char **items) +{ + int i, x, y, cur_x, cur_y, box_x, box_y, key = 0, button = 0, choice = 0, + scroll = 0, max_choice, *status; + WINDOW *dialog, *list; + + /* Allocate space for storing item on/off status */ + if ((status = malloc(sizeof(int)*item_no)) == NULL) { + endwin(); + fprintf(stderr, "\nCan't allocate memory in dialog_checklist().\n"); + exit(-1); + } + /* Initializes status */ + for (i = 0; i < item_no; i++) + status[i] = !strcasecmp(items[i*3 + 2], "on"); + + max_choice = MIN(list_height, item_no); + + /* center dialog box on screen */ + x = (COLS - width)/2; + y = (LINES - height)/2; + +#ifdef HAVE_NCURSES + if (use_shadow) + draw_shadow(stdscr, y, x, height, width); +#endif + dialog = newwin(height, width, y, x); + keypad(dialog, TRUE); + + draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr); + wattrset(dialog, border_attr); + wmove(dialog, height-3, 0); + waddch(dialog, ACS_LTEE); + for (i = 0; i < width-2; i++) + waddch(dialog, ACS_HLINE); + wattrset(dialog, dialog_attr); + waddch(dialog, ACS_RTEE); + wmove(dialog, height-2, 1); + for (i = 0; i < width-2; i++) + waddch(dialog, ' '); + + if (title != NULL) { + wattrset(dialog, title_attr); + wmove(dialog, 0, (width - strlen(title))/2 - 1); + waddch(dialog, ' '); + waddstr(dialog, title); + waddch(dialog, ' '); + } + wattrset(dialog, dialog_attr); + print_autowrap(dialog, prompt, width, 1, 3); + + list_width = width-6; + getyx(dialog, cur_y, cur_x); + box_y = cur_y + 1; + box_x = (width - list_width)/2 - 1; + + /* create new window for the list */ + list = subwin(dialog, list_height, list_width, y + box_y + 1, x + box_x + 1); + keypad(list, TRUE); + + /* draw a box around the list items */ + draw_box(dialog, box_y, box_x, list_height+2, list_width+2, menubox_border_attr, menubox_attr); + + check_x = 0; + item_x = 0; + /* Find length of longest item in order to center checklist */ + for (i = 0; i < item_no; i++) { + check_x = MAX(check_x, strlen(items[i*3]) + strlen(items[i*3 + 1]) + 6); + item_x = MAX(item_x, strlen(items[i*3])); + } + check_x = (list_width - check_x) / 2; + item_x = check_x + item_x + 6; + + /* Print the list */ + for (i = 0; i < max_choice; i++) + print_item(list, items[i*3], items[i*3 + 1], status[i], i, i == choice); + wnoutrefresh(list); + + if (list_height < item_no) { + wattrset(dialog, darrow_attr); + wmove(dialog, box_y + list_height + 1, box_x + check_x + 5); + waddch(dialog, ACS_DARROW); + wmove(dialog, box_y + list_height + 1, box_x + check_x + 6); + waddstr(dialog, "(+)"); + } + + x = width/2-11; + y = height-2; + print_button(dialog, "Cancel", y, x+14, FALSE); + print_button(dialog, " OK ", y, x, TRUE); + wrefresh(dialog); + + while (key != ESC) { + key = wgetch(dialog); + /* Check if key pressed matches first character of any item tag in list */ + for (i = 0; i < max_choice; i++) + if (key < 0x100 && toupper(key) == toupper(items[(scroll+i)*3][0])) + break; + + if (i < max_choice || (key >= '1' && key <= MIN('9', '0'+max_choice)) || + key == KEY_UP || key == KEY_DOWN || key == ' ' || + key == '+' || key == '-' ) { + if (key >= '1' && key <= MIN('9', '0'+max_choice)) + i = key - '1'; + else if (key == KEY_UP || key == '-') { + if (!choice) { + if (scroll) { +#ifdef BROKEN_WSCRL + /* wscrl() in ncurses 1.8.1 seems to be broken, causing a segmentation + violation when scrolling windows of height = 4, so scrolling is not + used for now */ + scroll--; + getyx(dialog, cur_y, cur_x); /* Save cursor position */ + /* Reprint list to scroll down */ + for (i = 0; i < max_choice; i++) + print_item(list, items[(scroll+i)*3], items[(scroll+i)*3 + 1], status[scroll+i], i, i == choice); + +#else + + /* Scroll list down */ + getyx(dialog, cur_y, cur_x); /* Save cursor position */ + if (list_height > 1) { + /* De-highlight current first item before scrolling down */ + print_item(list, items[scroll*3], items[scroll*3 + 1], status[scroll], 0, FALSE); + scrollok(list, TRUE); + wscrl(list, -1); + scrollok(list, FALSE); + } + scroll--; + print_item(list, items[scroll*3], items[scroll*3 + 1], status[scroll], 0, TRUE); +#endif + wnoutrefresh(list); + + /* print the up/down arrows */ + wmove(dialog, box_y, box_x + check_x + 5); + wattrset(dialog, scroll ? uarrow_attr : menubox_attr); + waddch(dialog, scroll ? ACS_UARROW : ACS_HLINE); + wmove(dialog, box_y, box_x + check_x + 6); + waddch(dialog, scroll ? '(' : ACS_HLINE); + wmove(dialog, box_y, box_x + check_x + 7); + waddch(dialog, scroll ? '-' : ACS_HLINE); + wmove(dialog, box_y, box_x + check_x + 8); + waddch(dialog, scroll ? ')' : ACS_HLINE); + wattrset(dialog, darrow_attr); + wmove(dialog, box_y + list_height + 1, box_x + check_x + 5); + waddch(dialog, ACS_DARROW); + wmove(dialog, box_y + list_height + 1, box_x + check_x + 6); + waddch(dialog, '('); + wmove(dialog, box_y + list_height + 1, box_x + check_x + 7); + waddch(dialog, '+'); + wmove(dialog, box_y + list_height + 1, box_x + check_x + 8); + waddch(dialog, ')'); + wmove(dialog, cur_y, cur_x); /* Restore cursor position */ + wrefresh(dialog); + } + continue; /* wait for another key press */ + } + else + i = choice - 1; + } + else if (key == KEY_DOWN || key == '+') { + if (choice == max_choice - 1) { + if (scroll+choice < item_no-1) { +#ifdef BROKEN_WSCRL + /* wscrl() in ncurses 1.8.1 seems to be broken, causing a segmentation + violation when scrolling windows of height = 4, so scrolling is not + used for now */ + scroll++; + getyx(dialog, cur_y, cur_x); /* Save cursor position */ + /* Reprint list to scroll up */ + for (i = 0; i < max_choice; i++) + print_item(list, items[(scroll+i)*3], items[(scroll+i)*3 + 1], status[scroll+i], i, i == choice); + +#else + + /* Scroll list up */ + getyx(dialog, cur_y, cur_x); /* Save cursor position */ + if (list_height > 1) { + /* De-highlight current last item before scrolling up */ + print_item(list, items[(scroll+max_choice-1)*3], items[(scroll+max_choice-1)*3 + 1], status[scroll+max_choice-1], max_choice-1, FALSE); + scrollok(list, TRUE); + scroll(list); + scrollok(list, FALSE); + } + scroll++; + print_item(list, items[(scroll+max_choice-1)*3], items[(scroll+max_choice-1)*3 + 1], status[scroll+max_choice-1], max_choice-1, TRUE); +#endif + wnoutrefresh(list); + + /* print the up/down arrows */ + wattrset(dialog, uarrow_attr); + wmove(dialog, box_y, box_x + check_x + 5); + waddch(dialog, ACS_UARROW); + wmove(dialog, box_y, box_x + check_x + 6); + waddstr(dialog, "(-)"); + wmove(dialog, box_y + list_height + 1, box_x + check_x + 5); + wattrset(dialog, scroll+choice < item_no-1 ? darrow_attr : menubox_border_attr); + waddch(dialog, scroll+choice < item_no-1 ? ACS_DARROW : ACS_HLINE); + wmove(dialog, box_y + list_height + 1, box_x + check_x + 6); + waddch(dialog, scroll+choice < item_no-1 ? '(' : ACS_HLINE); + wmove(dialog, box_y + list_height + 1, box_x + check_x + 7); + waddch(dialog, scroll+choice < item_no-1 ? '+' : ACS_HLINE); + wmove(dialog, box_y + list_height + 1, box_x + check_x + 8); + waddch(dialog, scroll+choice < item_no-1 ? ')' : ACS_HLINE); + wmove(dialog, cur_y, cur_x); /* Restore cursor position */ + wrefresh(dialog); + } + continue; /* wait for another key press */ + } + else + i = choice + 1; + } + else if (key == ' ') { /* Toggle item status */ + status[scroll+choice] = !status[scroll+choice]; + getyx(dialog, cur_y, cur_x); /* Save cursor position */ + wmove(list, choice, check_x); + wattrset(list, check_selected_attr); + wprintw(list, "[%c]", status[scroll+choice] ? 'X' : ' '); + wnoutrefresh(list); + wmove(dialog, cur_y, cur_x); /* Restore cursor to previous position */ + wrefresh(dialog); + continue; /* wait for another key press */ + } + + if (i != choice) { + /* De-highlight current item */ + getyx(dialog, cur_y, cur_x); /* Save cursor position */ + print_item(list, items[(scroll+choice)*3], items[(scroll+choice)*3 + 1], status[scroll+choice], choice, FALSE); + + /* Highlight new item */ + choice = i; + print_item(list, items[(scroll+choice)*3], items[(scroll+choice)*3 + 1], status[scroll+choice], choice, TRUE); + wnoutrefresh(list); + wmove(dialog, cur_y, cur_x); /* Restore cursor to previous position */ + wrefresh(dialog); + } + continue; /* wait for another key press */ + } + + switch (key) { + case 'O': + case 'o': + delwin(dialog); + for (i = 0; i < item_no; i++) + if (status[i]) + fprintf(stderr, "\"%s\" ", items[i*3]); + free(status); + return 0; + case 'C': + case 'c': + delwin(dialog); + free(status); + return 1; + case TAB: + case KEY_BTAB: + case KEY_LEFT: + case KEY_RIGHT: + if (!button) { + button = 1; /* Indicates "Cancel" button is selected */ + print_button(dialog, " OK ", y, x, FALSE); + print_button(dialog, "Cancel", y, x+14, TRUE); + } + else { + button = 0; /* Indicates "OK" button is selected */ + print_button(dialog, "Cancel", y, x+14, FALSE); + print_button(dialog, " OK ", y, x, TRUE); + } + wrefresh(dialog); + break; + case ' ': + case '\n': + delwin(dialog); + if (!button) + for (i = 0; i < item_no; i++) + if (status[i]) + fprintf(stderr, "\"%s\" ", items[i*3]); + free(status); + return button; + case ESC: + break; + } + } + + delwin(dialog); + free(status); + return -1; /* ESC pressed */ +} +/* End of dialog_checklist() */ + + +/* + * Print list item + */ +static void print_item(WINDOW *win, unsigned char *tag, unsigned char *item, int status, int choice, int selected) +{ + int i; + + /* Clear 'residue' of last item */ + wattrset(win, menubox_attr); + wmove(win, choice, 0); + for (i = 0; i < list_width; i++) + waddch(win, ' '); + wmove(win, choice, check_x); + wattrset(win, selected ? check_selected_attr : check_attr); + wprintw(win, "[%c]", status ? 'X' : ' '); + wattrset(win, menubox_attr); + waddch(win, ' '); + wattrset(win, selected ? tag_key_selected_attr : tag_key_attr); + waddch(win, tag[0]); + wattrset(win, selected ? tag_selected_attr : tag_attr); + waddstr(win, tag + 1); + wmove(win, choice, item_x); + wattrset(win, selected ? item_selected_attr : item_attr); + waddstr(win, item); +} +/* End of print_item() */ diff --git a/gnu/usr.bin/dialog/colors.h b/gnu/usr.bin/dialog/colors.h new file mode 100644 index 000000000000..7cea0a01cc2e --- /dev/null +++ b/gnu/usr.bin/dialog/colors.h @@ -0,0 +1,219 @@ +/* + * colors.h -- color attribute definitions + * + * AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +/* + * Default color definitions + * + * *_FG = foreground + * *_BG = background + * *_HL = highlight? + */ +#define SCREEN_FG COLOR_CYAN +#define SCREEN_BG COLOR_BLUE +#define SCREEN_HL TRUE + +#define SHADOW_FG COLOR_BLACK +#define SHADOW_BG COLOR_BLACK +#define SHADOW_HL TRUE + +#define DIALOG_FG COLOR_BLACK +#define DIALOG_BG COLOR_WHITE +#define DIALOG_HL FALSE + +#define TITLE_FG COLOR_YELLOW +#define TITLE_BG COLOR_WHITE +#define TITLE_HL TRUE + +#define BORDER_FG COLOR_WHITE +#define BORDER_BG COLOR_WHITE +#define BORDER_HL TRUE + +#define BUTTON_ACTIVE_FG COLOR_WHITE +#define BUTTON_ACTIVE_BG COLOR_BLUE +#define BUTTON_ACTIVE_HL TRUE + +#define BUTTON_INACTIVE_FG COLOR_BLACK +#define BUTTON_INACTIVE_BG COLOR_WHITE +#define BUTTON_INACTIVE_HL FALSE + +#define BUTTON_KEY_ACTIVE_FG COLOR_WHITE +#define BUTTON_KEY_ACTIVE_BG COLOR_BLUE +#define BUTTON_KEY_ACTIVE_HL TRUE + +#define BUTTON_KEY_INACTIVE_FG COLOR_RED +#define BUTTON_KEY_INACTIVE_BG COLOR_WHITE +#define BUTTON_KEY_INACTIVE_HL FALSE + +#define BUTTON_LABEL_ACTIVE_FG COLOR_YELLOW +#define BUTTON_LABEL_ACTIVE_BG COLOR_BLUE +#define BUTTON_LABEL_ACTIVE_HL TRUE + +#define BUTTON_LABEL_INACTIVE_FG COLOR_BLACK +#define BUTTON_LABEL_INACTIVE_BG COLOR_WHITE +#define BUTTON_LABEL_INACTIVE_HL TRUE + +#define INPUTBOX_FG COLOR_BLACK +#define INPUTBOX_BG COLOR_WHITE +#define INPUTBOX_HL FALSE + +#define INPUTBOX_BORDER_FG COLOR_BLACK +#define INPUTBOX_BORDER_BG COLOR_WHITE +#define INPUTBOX_BORDER_HL FALSE + +#define SEARCHBOX_FG COLOR_BLACK +#define SEARCHBOX_BG COLOR_WHITE +#define SEARCHBOX_HL FALSE + +#define SEARCHBOX_TITLE_FG COLOR_YELLOW +#define SEARCHBOX_TITLE_BG COLOR_WHITE +#define SEARCHBOX_TITLE_HL TRUE + +#define SEARCHBOX_BORDER_FG COLOR_WHITE +#define SEARCHBOX_BORDER_BG COLOR_WHITE +#define SEARCHBOX_BORDER_HL TRUE + +#define POSITION_INDICATOR_FG COLOR_YELLOW +#define POSITION_INDICATOR_BG COLOR_WHITE +#define POSITION_INDICATOR_HL TRUE + +#define MENUBOX_FG COLOR_BLACK +#define MENUBOX_BG COLOR_WHITE +#define MENUBOX_HL FALSE + +#define MENUBOX_BORDER_FG COLOR_WHITE +#define MENUBOX_BORDER_BG COLOR_WHITE +#define MENUBOX_BORDER_HL TRUE + +#define ITEM_FG COLOR_BLACK +#define ITEM_BG COLOR_WHITE +#define ITEM_HL FALSE + +#define ITEM_SELECTED_FG COLOR_WHITE +#define ITEM_SELECTED_BG COLOR_BLUE +#define ITEM_SELECTED_HL TRUE + +#define TAG_FG COLOR_YELLOW +#define TAG_BG COLOR_WHITE +#define TAG_HL TRUE + +#define TAG_SELECTED_FG COLOR_YELLOW +#define TAG_SELECTED_BG COLOR_BLUE +#define TAG_SELECTED_HL TRUE + +#define TAG_KEY_FG COLOR_RED +#define TAG_KEY_BG COLOR_WHITE +#define TAG_KEY_HL TRUE + +#define TAG_KEY_SELECTED_FG COLOR_RED +#define TAG_KEY_SELECTED_BG COLOR_BLUE +#define TAG_KEY_SELECTED_HL TRUE + +#define CHECK_FG COLOR_BLACK +#define CHECK_BG COLOR_WHITE +#define CHECK_HL FALSE + +#define CHECK_SELECTED_FG COLOR_WHITE +#define CHECK_SELECTED_BG COLOR_BLUE +#define CHECK_SELECTED_HL TRUE + +#define UARROW_FG COLOR_GREEN +#define UARROW_BG COLOR_WHITE +#define UARROW_HL TRUE + +#define DARROW_FG COLOR_GREEN +#define DARROW_BG COLOR_WHITE +#define DARROW_HL TRUE + +/* End of default color definitions */ + +#define C_ATTR(x,y) ((x ? A_BOLD : 0) | COLOR_PAIR((y))) +#define COLOR_NAME_LEN 10 +#define COLOR_COUNT 8 + + +/* + * Global variables + */ + +typedef struct { + unsigned char name[COLOR_NAME_LEN]; + int value; +} color_names_st; + + +#ifdef __DIALOG_MAIN__ + +/* + * For matching color names with color values + */ +color_names_st color_names[] = { + {"BLACK", COLOR_BLACK}, + {"RED", COLOR_RED}, + {"GREEN", COLOR_GREEN}, + {"YELLOW", COLOR_YELLOW}, + {"BLUE", COLOR_BLUE}, + {"MAGENTA", COLOR_MAGENTA}, + {"CYAN", COLOR_CYAN}, + {"WHITE", COLOR_WHITE}, +}; /* color names */ + + +/* + * Table of color values + */ +int color_table[][3] = { + {SCREEN_FG, SCREEN_BG, SCREEN_HL }, + {SHADOW_FG, SHADOW_BG, SHADOW_HL }, + {DIALOG_FG, DIALOG_BG, DIALOG_HL }, + {TITLE_FG, TITLE_BG, TITLE_HL }, + {BORDER_FG, BORDER_BG, BORDER_HL }, + {BUTTON_ACTIVE_FG, BUTTON_ACTIVE_BG, BUTTON_ACTIVE_HL }, + {BUTTON_INACTIVE_FG, BUTTON_INACTIVE_BG, BUTTON_INACTIVE_HL }, + {BUTTON_KEY_ACTIVE_FG, BUTTON_KEY_ACTIVE_BG, BUTTON_KEY_ACTIVE_HL }, + {BUTTON_KEY_INACTIVE_FG, BUTTON_KEY_INACTIVE_BG, BUTTON_KEY_INACTIVE_HL }, + {BUTTON_LABEL_ACTIVE_FG, BUTTON_LABEL_ACTIVE_BG, BUTTON_LABEL_ACTIVE_HL }, + {BUTTON_LABEL_INACTIVE_FG,BUTTON_LABEL_INACTIVE_BG,BUTTON_LABEL_INACTIVE_HL}, + {INPUTBOX_FG, INPUTBOX_BG, INPUTBOX_HL }, + {INPUTBOX_BORDER_FG, INPUTBOX_BORDER_BG, INPUTBOX_BORDER_HL }, + {SEARCHBOX_FG, SEARCHBOX_BG, SEARCHBOX_HL }, + {SEARCHBOX_TITLE_FG, SEARCHBOX_TITLE_BG, SEARCHBOX_TITLE_HL }, + {SEARCHBOX_BORDER_FG, SEARCHBOX_BORDER_BG, SEARCHBOX_BORDER_HL }, + {POSITION_INDICATOR_FG, POSITION_INDICATOR_BG, POSITION_INDICATOR_HL }, + {MENUBOX_FG, MENUBOX_BG, MENUBOX_HL }, + {MENUBOX_BORDER_FG, MENUBOX_BORDER_BG, MENUBOX_BORDER_HL }, + {ITEM_FG, ITEM_BG, ITEM_HL }, + {ITEM_SELECTED_FG, ITEM_SELECTED_BG, ITEM_SELECTED_HL }, + {TAG_FG, TAG_BG, TAG_HL }, + {TAG_SELECTED_FG, TAG_SELECTED_BG, TAG_SELECTED_HL }, + {TAG_KEY_FG, TAG_KEY_BG, TAG_KEY_HL }, + {TAG_KEY_SELECTED_FG, TAG_KEY_SELECTED_BG, TAG_KEY_SELECTED_HL }, + {CHECK_FG, CHECK_BG, CHECK_HL }, + {CHECK_SELECTED_FG, CHECK_SELECTED_BG, CHECK_SELECTED_HL }, + {UARROW_FG, UARROW_BG, UARROW_HL }, + {DARROW_FG, DARROW_BG, DARROW_HL }, +}; /* color_table */ + +#else + +extern color_names_st color_names[]; +extern int color_table[][3]; + +#endif /* __DIALOG_MAIN__ */ diff --git a/gnu/usr.bin/dialog/dialog.1 b/gnu/usr.bin/dialog/dialog.1 new file mode 100644 index 000000000000..3ab1119d60a2 --- /dev/null +++ b/gnu/usr.bin/dialog/dialog.1 @@ -0,0 +1,217 @@ +.TH DIALOG 1 "10 January 1994" +.SH NAME +dialog \- display dialog boxes from shell scripts +.SH SYNOPSIS +.B dialog --clear +.br +.BI "dialog --create-rc " file +.br +.B dialog +[ +.B \-\-title +.I title +] +[ +.B \-\-clear +] +.B box-options +.SH DESCRIPTION +.B Dialog +is a program that will let you to present a variety of questions or +display messages using dialog boxes from a shell script. Currently, +these types of dialog boxes are implemented: +.LP +.BR yes/no " box," " menu" " box," " input" " box," +.BR message " box," " text" " box," " info" " box, and" +.BR checklist " box." +.SH OPTIONS +.TP +.B \-\-clear +The screen will be cleared to the +.BR "screen attribute" " on exit." +.TP +.BI \-\-create-rc " file" +.RB "Since " dialog " supports run-time configuration," +this can be used to dump a sample configuration file to the file specified +by +.IR file "." +.TP +.BI \-\-title " title" +Specifies a +.I title +string to be displayed at the top of the dialog box. +.TP +.B Box Options +.TP +.BI \-\-yesno " text height width" +.RB A " yes/no" " dialog box of size" +.I height +rows by +.I width +columns will be displayed. The string specified by +.I text +is displayed inside the dialog box. If this string is too long to be fitted +in one line, it will be automatically divided into multiple lines at +appropriate places. The +.I text +string may also contain the sub-string +.I +"\en" +or newline characters +.I `\en\' +to control line breaking explicitly. This dialog box is useful for +asking questions that require the user to answer either yes or no. +.RB "The dialog box has a" " Yes" " button and a " No +button, in which the user can switch between by pressing the +.IR TAB " key." +.TP +.BI \-\-msgbox " text height width" +.RB A " message" " box is very similar to a" " yes/no" " box." +The only difference between a +.B message +box and a +.B yes/no +box is that a +.B message +box has only a single +.B OK +button. You can use this dialog box to display any message you like. +After reading the message, the user can press the +.I ENTER +key so that +.B dialog +will exit and the calling shell script can continue its operation. +.TP +.BI \-\-infobox " text height width" +.RB An " info" " box is basically a" " message" " box." +However, in this case, +.B dialog +will exit immediately after displaying the message to the user. The +screen is not cleared when +.B dialog +exits, so that the message will remain on the screen until the calling +shell script clears it later. This is useful when you want to inform +the user that some operations are carrying on that may require some +time to finish. +.TP +.BI \-\-inputbox " text height width" +.RB "An " input " box is useful when you want to ask questions that" +require the user to input a string as the answer. When inputing the +string, the +.I BACKSPACE +key can be used to correct typing errors. If the input string is longer than +can be fitted in the dialog box, the input field will be scrolled. On exit, +the input string will be printed on +.IR stderr "." +.TP +.BI \-\-textbox " file height width" +.RB A " text" " box lets you display the contents of a text file in a" +dialog box. It is like a simple text file viewer. The user can move +through the file by using the +.IR UP/DOWN ", " PGUP/PGDN +.RI and " HOME/END" " keys available on most keyboards." +If the lines are too long to be displayed in the box, the +.I LEFT/RIGHT +keys can be used to scroll the text region horizontally. For more +convenience, forward and backward searching functions are also provided. +.IP "\fB\-\-menu \fItext height width menu-height \fR[ \fItag item \fR] \fI..." +As its name suggests, a +.B menu +box is a dialog box that can be used to present a list of choices in +the form of a menu for the user to choose. Each menu entry consists of a +.IR tag " string and an " item " string. The" +.I tag +gives the entry a name to distinguish it from the other entries in the +menu. The +.I item +is a short description of the option that the entry represents. The +user can move between the menu entries by pressing the +.I UP/DOWN +keys, the first letter of the +.I tag +as a hot-key, or the number keys +.IR 1-9 ". There are" +.I menu-height +entries displayed in the menu at one time, but the menu will be +scrolled if there are more entries than that. When +.B dialog +exits, the +.I tag +of the chosen menu entry will be printed on +.IR stderr "." +.IP "\fB\-\-checklist \fItext height width list-height \fR[ \fItag item status \fR] \fI..." +.RB "A " checklist " box is similar to a " menu " box in that there are" +multiple entries presented in the form of a menu. Instead of choosing +one entry among the entries, each entry can be turned on or off by the +user. The initial on/off state of each entry is specified by +.IR status "." +On exit, a list of the +.I tag +strings of those entries that are turned on will be printed on +.IR stderr "." +.SH "RUN-TIME CONFIGURATION" +.TP 4 +1. +Create a sample configuration file by typing: +.LP +.in +1i +"dialog --create-rc " +.TP 4 +2. +At start, +.B dialog +determines the settings to use as follows: +.RS +.TP 4 +a) +if environment variable +.B DIALOGRC +is set, it's value determines the name of the configuration file. +.TP 4 +b) +if the file in (a) can't be found, use the file +.I $HOME/.dialogrc +as the configuration file. +.TP 4 +c) +if the file in (b) can't be found, use compiled in defaults. +.RE +.TP 4 +3. +Edit the sample configuration file and copy it to some place that +.B dialog +can find, as stated in step 2 above. +.SH ENVIROMENT +.TP 15 +.B DIALOGRC +Define this variable if you want to specify the name of the configuration file +to use. +.SH FILES +.TP 20 +.I $HOME/.dialogrc +default configuration file +.SH DIAGNOSTICS +Exit status is 0 if +.BR dialog " is exited by pressing the " Yes " or " OK +button, and 1 if the +.BR No " or " Cancel +button is pressed. Otherwise, if errors occur inside +.B dialog +or +.B dialog +is exited by pressing the +.I ESC +key, the exit status is -1. +.SH BUGS +Text files containing +.I tab +characters may cause problems with +.B text +box. +.I Tab +characters in text files must first be expanded to spaces before being +.RB "displayed by " text " box." +.TP +Screen update is too slow. +.SH AUTHOR +Savio Lam (lam836@cs.cuhk.hk) diff --git a/gnu/usr.bin/dialog/dialog.c b/gnu/usr.bin/dialog/dialog.c new file mode 100644 index 000000000000..1d710bdb28f1 --- /dev/null +++ b/gnu/usr.bin/dialog/dialog.c @@ -0,0 +1,545 @@ +/* + * dialog - Display simple dialog boxes from shell scripts + * + * AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * HISTORY: + * + * 17/12/93 - Version 0.1 released. + * + * 19/12/93 - menu will now scroll if there are more items than can fit + * on the screen. + * - added 'checklist', a dialog box with a list of options that + * can be turned on or off. A list of options that are on is + * returned on exit. + * + * 20/12/93 - Version 0.15 released. + * + * 29/12/93 - Incorporated patch from Patrick J. Volkerding + * (volkerdi@mhd1.moorhead.msus.edu) that made these changes: + * - increased MAX_LEN to 2048 + * - added 'infobox', equivalent to a message box without pausing + * - added option '--clear' that will clear the screen + * - Explicit line breaking when printing prompt text can be + * invoked by real newline '\n' besides the string "\n" + * - an optional parameter '--title ' can be used to + * specify a title string for the dialog box + * + * 03/01/94 - added 'textbox', a dialog box for displaying text from a file. + * - Version 0.2 released. + * + * 04/01/94 - some fixes and improvements for 'textbox': + * - fixed a bug that will cause a segmentation violation when a + * line is longer than MAX_LEN characters. Lines will now be + * truncated if they are longer than MAX_LEN characters. + * - removed wrefresh() from print_line(). This will increase + * efficiency of print_page() which calls print_line(). + * - display current position in the form of percentage into file. + * - Version 0.21 released. + * + * 05/01/94 - some changes for faster screen update. + * + * 07/01/94 - much more flexible color settings. Can use all 16 colors + * (8 normal, 8 highlight) of the Linux console. + * + * 08/01/94 - added run-time configuration using configuration file. + * + * 09/01/94 - some minor bug fixes and cleanups for menubox, checklist and + * textbox. + * + * 11/01/94 - added a man page. + * + * 13/01/94 - some changes for easier porting to other Unix systems (tested + * on Ultrix, SunOS and HPUX) + * - Version 0.3 released. + * + * 08/06/94 - Patches by Stuart Herbert - S.Herbert@shef.ac.uk + * Fixed attr_clear and the textbox stuff to work with ncurses 1.8.5 + * Fixed the wordwrap routine - it'll actually wrap properly now + * Added a more 3D look to everything - having your own rc file could + * prove 'interesting' to say the least :-) + * Added radiolist option + * - Version 0.4 released. + */ + + +#define __DIALOG_MAIN__ + + +#include "dialog.h" +#ifdef HAVE_NCURSES +#include "colors.h" +#endif + + +int main(int argc, unsigned char *argv[]) +{ + int offset = 0, clear_screen = 0, end_common_opts = 0, retval; + unsigned char *title = NULL; + +#if defined(LOCALE) + (void) setlocale(LC_ALL, ""); +#endif + + if (argc < 2) { + Usage(argv[0]); + exit(-1); + } + else if (!strcmp(argv[1], "--create-rc")) { +#ifdef HAVE_NCURSES + if (argc != 3) { + Usage(argv[0]); + exit(-1); + } + create_rc(argv[2]); + return 0; +#else + fprintf(stderr, "\nThis option is currently unsupported on your system.\n"); + return -1; +#endif + } + + while (offset < argc-1 && !end_common_opts) { /* Common options */ + if (!strcmp(argv[offset+1], "--title")) { + if (argc-offset < 3 || title != NULL) { /* No two "--title" please! */ + Usage(argv[0]); + exit(-1); + } + else { + title = argv[offset+2]; + offset += 2; + } + } + else if (!strcmp(argv[offset+1], "--clear")) { + if (clear_screen) { /* Hey, "--clear" can't appear twice! */ + Usage(argv[0]); + exit(-1); + } + else if (argc == 2) { /* we only want to clear the screen */ + init_dialog(); + refresh(); /* init_dialog() will clear the screen for us */ + endwin(); + return 0; + } + else { + clear_screen = 1; + offset++; + } + } + else /* no more common options */ + end_common_opts = 1; + } + + if (argc-1 == offset) { /* no more options */ + Usage(argv[0]); + exit(-1); + } + + /* Box options */ + + if (!strcmp(argv[offset+1], "--yesno")) { + if (argc-offset != 5) { + Usage(argv[0]); + exit(-1); + } + init_dialog(); + retval = dialog_yesno(title, argv[offset+2], atoi(argv[offset+3]), + atoi(argv[offset+4])); + + if (clear_screen) { /* clear screen before exit */ + attr_clear(stdscr, LINES, COLS, screen_attr); + refresh(); + } + endwin(); + return retval; + } + else if (!strcmp(argv[offset+1], "--msgbox")) { + if (argc-offset != 5) { + Usage(argv[0]); + exit(-1); + } + init_dialog(); + retval = dialog_msgbox(title, argv[offset+2], atoi(argv[offset+3]), + atoi(argv[offset+4]), 1); + + if (clear_screen) { /* clear screen before exit */ + attr_clear(stdscr, LINES, COLS, screen_attr); + refresh(); + } + endwin(); + return retval; + } + else if (!strcmp(argv[offset+1], "--infobox")) { + if (argc-offset != 5) { + Usage(argv[0]); + exit(-1); + } + init_dialog(); + retval = dialog_msgbox(title, argv[offset+2], atoi(argv[offset+3]), + atoi(argv[offset+4]), 0); + + if (clear_screen) { /* clear screen before exit */ + attr_clear(stdscr, LINES, COLS, screen_attr); + refresh(); + } + endwin(); + return retval; + } + else if (!strcmp(argv[offset+1], "--textbox")) { + if (argc-offset != 5) { + Usage(argv[0]); + exit(-1); + } + init_dialog(); + retval = dialog_textbox(title, argv[offset+2], atoi(argv[offset+3]), + atoi(argv[offset+4])); + + if (clear_screen) { /* clear screen before exit */ + attr_clear(stdscr, LINES, COLS, screen_attr); + refresh(); + } + endwin(); + return retval; + } + else if (!strcmp(argv[offset+1], "--menu")) { + if (argc-offset < 8 || ((argc-offset) % 2)) { + Usage(argv[0]); + exit(-1); + } + init_dialog(); + retval = dialog_menu(title, argv[offset+2], atoi(argv[offset+3]), + atoi(argv[offset+4]), atoi(argv[offset+5]), + (argc-offset-6)/2, argv+offset + 6); + + if (clear_screen) { /* clear screen before exit */ + attr_clear(stdscr, LINES, COLS, screen_attr); + refresh(); + } + endwin(); + return retval; + } + else if (!strcmp(argv[offset+1], "--checklist")) { + if (argc-offset < 9 || ((argc-offset-6) % 3)) { + Usage(argv[0]); + exit(-1); + } + init_dialog(); + retval = dialog_checklist(title, argv[offset+2], atoi(argv[offset+3]), + atoi(argv[offset+4]), atoi(argv[offset+5]), + (argc-offset-6)/3, argv+offset + 6); + + if (clear_screen) { /* clear screen before exit */ + attr_clear(stdscr, LINES, COLS, screen_attr); + refresh(); + } + endwin(); + return retval; + } + else if (!strcmp(argv[offset+1], "--radiolist")) { + if (argc-offset < 9 || ((argc-offset-6) % 3)) { + Usage(argv[0]); + exit(-1); + } + init_dialog(); + retval = dialog_radiolist(title, argv[offset+2], atoi(argv[offset+3]), + atoi(argv[offset+4]), atoi(argv[offset+5]), + (argc-offset-6)/3, argv+offset + 6); + + if (clear_screen) { /* clear screen before exit */ + attr_clear(stdscr, LINES, COLS, screen_attr); + refresh(); + } + endwin(); + return retval; + } + else if (!strcmp(argv[offset+1], "--inputbox")) { + if (argc-offset != 5) { + Usage(argv[0]); + exit(-1); + } + init_dialog(); + retval = dialog_inputbox(title, argv[offset+2], atoi(argv[offset+3]), + atoi(argv[offset+4])); + + if (clear_screen) { /* clear screen before exit */ + attr_clear(stdscr, LINES, COLS, screen_attr); + refresh(); + } + endwin(); + return retval; + } + + Usage(argv[0]); + exit(-1); +} +/* End of main() */ + + +/* + * Print program usage + */ +void Usage(unsigned char *name) +{ + fprintf(stderr, "\ +\ndialog version 0.3, by Savio Lam (lam836@cs.cuhk.hk).\ +\n patched to version %s by Stuart Herbert (S.Herbert@shef.ac.uk)\ +\n\ +\n* Display dialog boxes from shell scripts *\ +\n\ +\nUsage: %s --clear\ +\n %s --create-rc \ +\n %s [--title ] [--clear] <Box options>\ +\n\ +\nBox options:\ +\n\ +\n --yesno <text> <height> <width>\ +\n --msgbox <text> <height> <width>\ +\n --infobox <text> <height> <width>\ +\n --inputbox <text> <height> <width>\ +\n --textbox <file> <height> <width>\ +\n --menu <text> <height> <width> <menu height> <tag1> <item1>...\ +\n --checklist <text> <height> <width> <list height> <tag1> <item1> <status1>...\ +\n --radiolist <text> <height> <width> <list height> <tag1> <item1> <status1>...\n", VERSION, name, name, name); +} +/* End of Usage() */ + + +/* + * Do some initialization for dialog + */ +void init_dialog(void) +{ +#ifdef HAVE_NCURSES + if (parse_rc() == -1) /* Read the configuration file */ + exit(-1); +#endif + + initscr(); /* Init curses */ + keypad(stdscr, TRUE); + cbreak(); + noecho(); + +#ifdef HAVE_NCURSES + if (use_colors || use_shadow) /* Set up colors */ + color_setup(); +#endif + + /* Set screen to screen attribute */ + attr_clear(stdscr, LINES, COLS, screen_attr); + wnoutrefresh(stdscr); +} +/* End of init_dialog() */ + + +#ifdef HAVE_NCURSES +/* + * Setup for color display + */ +void color_setup(void) +{ + int i; + + if (has_colors()) { /* Terminal supports color? */ + start_color(); + + /* Initialize color pairs */ + for (i = 0; i < ATTRIBUTE_COUNT; i++) + init_pair(i+1, color_table[i][0], color_table[i][1]); + + /* Setup color attributes */ + for (i = 0; i < ATTRIBUTE_COUNT; i++) + attributes[i] = C_ATTR(color_table[i][2], i+1); + } +} +/* End of color_setup() */ +#endif + + +/* + * Set window to attribute 'attr' + */ +void attr_clear(WINDOW *win, int height, int width, chtype attr) +{ + int i, j; + + wattrset(win, attr); /* Set window to attribute 'attr' */ + for (i = 0; i < height; i++) { + wmove(win, i, 0); + for (j = 0; j < width; j++) + waddch(win, ' '); + } +} +/* End of attr_clear() */ + + +/* + * Print a string of text in a window, automatically wrap around to the + * next line if the string is too long to fit on one line. Note that the + * string may contain "\n" to represent a newline character or the real + * newline '\n', but in that case, auto wrap around will be disabled. + */ +void print_autowrap(WINDOW *win, unsigned char *prompt, int width, int y, int x) +{ + int first = 1, cur_x, cur_y; + unsigned char tempstr[MAX_LEN+1], *word, *tempptr, *tempptr1; + + strcpy(tempstr, prompt); + if ((strstr(tempstr, "\\n") != NULL) || + (strchr(tempstr, '\n') != NULL)) { /* Prompt contains "\n" or '\n' */ + word = tempstr; + cur_y = y; + wmove(win, cur_y, x); + while (1) { + tempptr = strstr(word, "\\n"); + tempptr1 = strchr(word, '\n'); + if (tempptr == NULL && tempptr1 == NULL) + break; + else if (tempptr == NULL) { /* No more "\n" */ + tempptr = tempptr1; + tempptr[0] = '\0'; + } + else if (tempptr1 == NULL) { /* No more '\n' */ + tempptr[0] = '\0'; + tempptr++; + } + else { /* Prompt contains both "\n" and '\n' */ + if (strlen(tempptr)-2 < strlen(tempptr1)-1) { + tempptr = tempptr1; + tempptr[0] = '\0'; + } + else { + tempptr[0] = '\0'; + tempptr++; + } + } + + waddstr(win, word); + word = tempptr + 1; + wmove(win, ++cur_y, x); + } + waddstr(win, word); + } + else if (strlen(tempstr) <= width-x*2) { /* If prompt is short */ + wmove(win, y, (width - strlen(tempstr)) / 2); + waddstr(win, tempstr); + } + else { + cur_x = x; + cur_y = y; + /* Print prompt word by word, wrap around if necessary */ + while ((word = strtok(first ? tempstr : NULL, " ")) != NULL) { + if (first) /* First iteration */ + first = 0; + if (cur_x+strlen(word) >= width) { /* wrap around to next line */ + cur_y++; + cur_x = x; + } + wmove(win, cur_y, cur_x); + waddstr(win, word); + getyx(win, cur_y, cur_x); + cur_x++; + } + } +} +/* End of print_autowrap() */ + + +/* + * Print a button + */ +void print_button(WINDOW *win, unsigned char *label, int y, int x, int selected) +{ + int i, temp; + + wmove(win, y, x); + wattrset(win, selected ? button_active_attr : button_inactive_attr); + waddstr(win, "<"); + temp = strspn(label, " "); + label += temp; + wattrset(win, selected ? button_label_active_attr : button_label_inactive_attr); + for (i = 0; i < temp; i++) + waddch(win, ' '); + wattrset(win, selected ? button_key_active_attr : button_key_inactive_attr); + waddch(win, label[0]); + wattrset(win, selected ? button_label_active_attr : button_label_inactive_attr); + waddstr(win, label+1); + wattrset(win, selected ? button_active_attr : button_inactive_attr); + waddstr(win, ">"); + wmove(win, y, x+temp+1); +} +/* End of print_button() */ + + +/* + * Draw a rectangular box with line drawing characters + */ +void draw_box(WINDOW *win, int y, int x, int height, int width, chtype box, chtype border) +{ + int i, j; + + wattrset(win, 0); + for (i = 0; i < height; i++) { + wmove(win, y + i, x); + for (j = 0; j < width; j++) + if (!i && !j) + waddch(win, border | ACS_ULCORNER); + else if (i == height-1 && !j) + waddch(win, border | ACS_LLCORNER); + else if (!i && j == width-1) + waddch(win, box | ACS_URCORNER); + else if (i == height-1 && j == width-1) + waddch(win, box | ACS_LRCORNER); + else if (!i) + waddch(win, border | ACS_HLINE); + else if (i == height-1) + waddch(win, box | ACS_HLINE); + else if (!j) + waddch(win, border | ACS_VLINE); + else if (j == width-1) + waddch(win, box | ACS_VLINE); + else + waddch(win, box | ' '); + } +} +/* End of draw_box() */ + + +#ifdef HAVE_NCURSES +/* + * Draw shadows along the right and bottom edge to give a more 3D look + * to the boxes + */ +void draw_shadow(WINDOW *win, int y, int x, int height, int width) +{ + int i; + + if (has_colors()) { /* Whether terminal supports color? */ + wattrset(win, shadow_attr); + wmove(win, y + height, x + 2); + for (i = 0; i < width; i++) + waddch(win, winch(win) & A_CHARTEXT); + for (i = y + 1; i < y + height + 1; i++) { + wmove(win, i, x + width); + waddch(win, winch(win) & A_CHARTEXT); + waddch(win, winch(win) & A_CHARTEXT); + } + wnoutrefresh(win); + } +} +/* End of draw_shadow() */ +#endif diff --git a/gnu/usr.bin/dialog/dialog.h b/gnu/usr.bin/dialog/dialog.h new file mode 100644 index 000000000000..849961f78c12 --- /dev/null +++ b/gnu/usr.bin/dialog/dialog.h @@ -0,0 +1,231 @@ +/* + * dialog.h -- common declarations for all dialog modules + * + * AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include <sys/types.h> +#include <fcntl.h> +#include <unistd.h> +#include <ctype.h> +#include <stdlib.h> +#include <string.h> + +#ifdef HAVE_NCURSES +#include <ncurses.h> + +#else + +#ifdef ultrix +#include <cursesX.h> +#else +#include <curses.h> +#endif + +#endif + +#if defined(LOCALE) +#include <locale.h> +#endif + +/* + * Change these if you want + */ +#define USE_SHADOW TRUE +#define USE_COLORS TRUE + +#define VERSION "0.4" +#define ESC 27 +#define TAB 9 +#define MAX_LEN 2048 +#define BUF_SIZE (10*1024) +#define MIN(x,y) (x < y ? x : y) +#define MAX(x,y) (x > y ? x : y) + +#ifndef HAVE_NCURSES +#ifndef ACS_ULCORNER +#define ACS_ULCORNER '+' +#endif +#ifndef ACS_LLCORNER +#define ACS_LLCORNER '+' +#endif +#ifndef ACS_URCORNER +#define ACS_URCORNER '+' +#endif +#ifndef ACS_LRCORNER +#define ACS_LRCORNER '+' +#endif +#ifndef ACS_HLINE +#define ACS_HLINE '-' +#endif +#ifndef ACS_VLINE +#define ACS_VLINE '|' +#endif +#ifndef ACS_LTEE +#define ACS_LTEE '+' +#endif +#ifndef ACS_RTEE +#define ACS_RTEE '+' +#endif +#ifndef ACS_UARROW +#define ACS_UARROW '^' +#endif +#ifndef ACS_DARROW +#define ACS_DARROW 'v' +#endif +#endif /* HAVE_NCURSES */ + + +/* + * Attribute names + */ +#define screen_attr attributes[0] +#define shadow_attr attributes[1] +#define dialog_attr attributes[2] +#define title_attr attributes[3] +#define border_attr attributes[4] +#define button_active_attr attributes[5] +#define button_inactive_attr attributes[6] +#define button_key_active_attr attributes[7] +#define button_key_inactive_attr attributes[8] +#define button_label_active_attr attributes[9] +#define button_label_inactive_attr attributes[10] +#define inputbox_attr attributes[11] +#define inputbox_border_attr attributes[12] +#define searchbox_attr attributes[13] +#define searchbox_title_attr attributes[14] +#define searchbox_border_attr attributes[15] +#define position_indicator_attr attributes[16] +#define menubox_attr attributes[17] +#define menubox_border_attr attributes[18] +#define item_attr attributes[19] +#define item_selected_attr attributes[20] +#define tag_attr attributes[21] +#define tag_selected_attr attributes[22] +#define tag_key_attr attributes[23] +#define tag_key_selected_attr attributes[24] +#define check_attr attributes[25] +#define check_selected_attr attributes[26] +#define uarrow_attr attributes[27] +#define darrow_attr attributes[28] + +/* number of attributes */ +#define ATTRIBUTE_COUNT 29 + + +/* + * Global variables + */ +#ifdef __DIALOG_MAIN__ + +#ifdef HAVE_NCURSES + +/* use colors by default? */ +bool use_colors = USE_COLORS; + +/* shadow dialog boxes by default? + Note that 'use_shadow' implies 'use_colors' */ +bool use_shadow = USE_SHADOW; + +#endif + + +/* + * Attribute values, default is for mono display + */ +chtype attributes[] = { + A_NORMAL, /* screen_attr */ + A_NORMAL, /* shadow_attr */ + A_REVERSE, /* dialog_attr */ + A_REVERSE, /* title_attr */ + A_REVERSE, /* border_attr */ + A_BOLD, /* button_active_attr */ + A_DIM, /* button_inactive_attr */ + A_UNDERLINE, /* button_key_active_attr */ + A_UNDERLINE, /* button_key_inactive_attr */ + A_NORMAL, /* button_label_active_attr */ + A_NORMAL, /* button_label_inactive_attr */ + A_REVERSE, /* inputbox_attr */ + A_REVERSE, /* inputbox_border_attr */ + A_REVERSE, /* searchbox_attr */ + A_REVERSE, /* searchbox_title_attr */ + A_REVERSE, /* searchbox_border_attr */ + A_REVERSE, /* position_indicator_attr */ + A_REVERSE, /* menubox_attr */ + A_REVERSE, /* menubox_border_attr */ + A_REVERSE, /* item_attr */ + A_NORMAL, /* item_selected_attr */ + A_REVERSE, /* tag_attr */ + A_REVERSE, /* tag_selected_attr */ + A_NORMAL, /* tag_key_attr */ + A_BOLD, /* tag_key_selected_attr */ + A_REVERSE, /* check_attr */ + A_REVERSE, /* check_selected_attr */ + A_REVERSE, /* uarrow_attr */ + A_REVERSE /* darrow_attr */ +}; + +#else + +#ifdef HAVE_NCURSES +extern bool use_colors; +extern bool use_shadow; +#endif + +extern chtype attributes[]; + +#endif /* __DIALOG_MAIN__ */ + + + +#ifdef HAVE_NCURSES + +/* + * Function prototypes + */ +#ifdef __DIALOG_MAIN__ + +extern void create_rc(unsigned char *filename); +extern int parse_rc(void); + +#endif /* __DIALOG_MAIN__ */ + +#endif + + +void Usage(unsigned char *name); +void init_dialog(void); +#ifdef HAVE_NCURSES +void color_setup(void); +#endif +void attr_clear(WINDOW *win, int height, int width, chtype attr); +void print_autowrap(WINDOW *win, unsigned char *prompt, int width, int y, int x); +void print_button(WINDOW *win, unsigned char *label, int y, int x, int selected); +void draw_box(WINDOW *win, int y, int x, int height, int width, chtype box, chtype border); +#ifdef HAVE_NCURSES +void draw_shadow(WINDOW *win, int y, int x, int height, int width); +#endif + +int dialog_yesno(unsigned char *title, unsigned char *prompt, int height, int width); +int dialog_msgbox(unsigned char *title, unsigned char *prompt, int height, int width, int pause); +int dialog_textbox(unsigned char *title, unsigned char *file, int height, int width); +int dialog_menu(unsigned char *title, unsigned char *prompt, int height, int width, int menu_height, int item_no, unsigned char **items); +int dialog_checklist(unsigned char *title, unsigned char *prompt, int height, int width, int list_height, int item_no, unsigned char **items); +int dialog_radiolist(char *title, char *prompt, int height, int width, int list_height, int item_no, unsigned char **items); +int dialog_inputbox(unsigned char *title, unsigned char *prompt, int height, int width); + diff --git a/gnu/usr.bin/dialog/inputbox.c b/gnu/usr.bin/dialog/inputbox.c new file mode 100644 index 000000000000..fe91613c45ab --- /dev/null +++ b/gnu/usr.bin/dialog/inputbox.c @@ -0,0 +1,252 @@ +/* + * inputbox.c -- implements the input box + * + * AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include "dialog.h" + + +/* + * Display a dialog box for inputing a string + */ +int dialog_inputbox(unsigned char *title, unsigned char *prompt, int height, int width) +{ + int i, x, y, box_y, box_x, box_width, + input_x = 0, scroll = 0, key = 0, button = -1; + unsigned char instr[MAX_LEN+1]; + WINDOW *dialog; + + /* center dialog box on screen */ + x = (COLS - width)/2; + y = (LINES - height)/2; + + memset(instr, 0, sizeof(instr)); + +#ifdef HAVE_NCURSES + if (use_shadow) + draw_shadow(stdscr, y, x, height, width); +#endif + dialog = newwin(height, width, y, x); + keypad(dialog, TRUE); + + draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr); + wattrset(dialog, border_attr); + wmove(dialog, height-3, 0); + waddch(dialog, ACS_LTEE); + for (i = 0; i < width-2; i++) + waddch(dialog, ACS_HLINE); + wattrset(dialog, dialog_attr); + waddch(dialog, ACS_RTEE); + wmove(dialog, height-2, 1); + for (i = 0; i < width-2; i++) + waddch(dialog, ' '); + + if (title != NULL) { + wattrset(dialog, title_attr); + wmove(dialog, 0, (width - strlen(title))/2 - 1); + waddch(dialog, ' '); + waddstr(dialog, title); + waddch(dialog, ' '); + } + wattrset(dialog, dialog_attr); + print_autowrap(dialog, prompt, width, 1, 3); + + /* Draw the input field box */ + box_width = width-6; + getyx(dialog, y, x); + box_y = y + 2; + box_x = (width - box_width)/2; + draw_box(dialog, y+1, box_x-1, 3, box_width+2, border_attr, dialog_attr); + + x = width/2-11; + y = height-2; + print_button(dialog, "Cancel", y, x+14, FALSE); + print_button(dialog, " OK ", y, x, TRUE); + + wmove(dialog, box_y, box_x); + wrefresh(dialog); + while (key != ESC) { + key = wgetch(dialog); + + if (button == -1) { /* Input box selected */ + switch (key) { + case TAB: + case KEY_BTAB: + case KEY_UP: + case KEY_DOWN: + break; + case KEY_LEFT: + if (input_x || scroll) { + wattrset(dialog, inputbox_attr); + if (!input_x) { + scroll = scroll < box_width-1 ? 0 : scroll-(box_width-1); + wmove(dialog, box_y, box_x); + for (i = 0; i < box_width; i++) + waddch(dialog, instr[scroll+input_x+i] ? instr[scroll+input_x+i] : ' '); + input_x = strlen(instr) - scroll; + } + else + input_x--; + i = strlen(instr); + while (i-1 >= scroll+input_x && instr[i-1] == ' ') + instr[--i] = '\0'; + wmove(dialog, box_y, input_x + box_x); + wrefresh(dialog); + } + continue; + case KEY_RIGHT: + if (scroll+input_x < MAX_LEN) { + wattrset(dialog, inputbox_attr); + if (!instr[scroll+input_x]) + instr[scroll+input_x] = ' '; + if (input_x == box_width-1) { + scroll++; + wmove(dialog, box_y, box_x); + for (i = 0; i < box_width-1; i++) + waddch(dialog, instr[scroll+i]); + } + else { + wmove(dialog, box_y, input_x + box_x); + waddch(dialog, instr[scroll+input_x]); + input_x++; + } + wrefresh(dialog); + } else + flash(); /* Alarm user about overflow */ + continue; + case KEY_BACKSPACE: + if (input_x || scroll) { + wattrset(dialog, inputbox_attr); + if (!input_x) { + scroll = scroll < box_width-1 ? 0 : scroll-(box_width-1); + wmove(dialog, box_y, box_x); + for (i = 0; i < box_width; i++) + waddch(dialog, instr[scroll+input_x+i] ? instr[scroll+input_x+i] : ' '); + input_x = strlen(instr) - scroll; + } + else + input_x--; + instr[scroll+input_x] = ' '; + wmove(dialog, box_y, input_x + box_x); + waddch(dialog, ' '); + wmove(dialog, box_y, input_x + box_x); + wrefresh(dialog); + i = strlen(instr); + while (i-1 >= scroll+input_x && instr[i-1] == ' ') + instr[--i] = '\0'; + } + continue; + default: + if (key < 0x100 && isprint(key)) { + if (scroll+input_x < MAX_LEN) { + wattrset(dialog, inputbox_attr); + instr[scroll+input_x] = key; + instr[scroll+input_x+1] = '\0'; + if (input_x == box_width-1) { + scroll++; + wmove(dialog, box_y, box_x); + for (i = 0; i < box_width-1; i++) + waddch(dialog, instr[scroll+i]); + } + else { + wmove(dialog, box_y, input_x++ + box_x); + waddch(dialog, key); + } + wrefresh(dialog); + } else + flash(); /* Alarm user about overflow */ + continue; + } + } + } + + switch (key) { + case 'O': + case 'o': + delwin(dialog); + fprintf(stderr, instr); + return 0; + case 'C': + case 'c': + delwin(dialog); + return 1; + case KEY_UP: + case KEY_LEFT: + case KEY_BTAB: + switch (button) { + case -1: + button = 1; /* Indicates "Cancel" button is selected */ + print_button(dialog, " OK ", y, x, FALSE); + print_button(dialog, "Cancel", y, x+14, TRUE); + wrefresh(dialog); + break; + case 0: + button = -1; /* Indicates input box is selected */ + print_button(dialog, "Cancel", y, x+14, FALSE); + print_button(dialog, " OK ", y, x, TRUE); + wmove(dialog, box_y, box_x + input_x); + wrefresh(dialog); + break; + case 1: + button = 0; /* Indicates "OK" button is selected */ + print_button(dialog, "Cancel", y, x+14, FALSE); + print_button(dialog, " OK ", y, x, TRUE); + wrefresh(dialog); + break; + } + break; + case TAB: + case KEY_DOWN: + case KEY_RIGHT: + switch (button) { + case -1: + button = 0; /* Indicates "OK" button is selected */ + print_button(dialog, "Cancel", y, x+14, FALSE); + print_button(dialog, " OK ", y, x, TRUE); + wrefresh(dialog); + break; + case 0: + button = 1; /* Indicates "Cancel" button is selected */ + print_button(dialog, " OK ", y, x, FALSE); + print_button(dialog, "Cancel", y, x+14, TRUE); + wrefresh(dialog); + break; + case 1: + button = -1; /* Indicates input box is selected */ + print_button(dialog, "Cancel", y, x+14, FALSE); + print_button(dialog, " OK ", y, x, TRUE); + wmove(dialog, box_y, box_x + input_x); + wrefresh(dialog); + break; + } + break; + case ' ': + case '\n': + delwin(dialog); + fprintf(stderr, instr); + return (button == -1 ? 0 : button); + case ESC: + break; + } + } + + delwin(dialog); + return -1; /* ESC pressed */ +} +/* End of dialog_inputbox() */ diff --git a/gnu/usr.bin/dialog/menubox.c b/gnu/usr.bin/dialog/menubox.c new file mode 100644 index 000000000000..e393c6c5458e --- /dev/null +++ b/gnu/usr.bin/dialog/menubox.c @@ -0,0 +1,310 @@ +/* + * menubox.c -- implements the menu box + * + * AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include "dialog.h" + + +static void print_item(WINDOW *win, unsigned char *tag, unsigned char *item, int choice, int selected); + + +static int menu_width, tag_x, item_x; + + +/* + * Display a menu for choosing among a number of options + */ +int dialog_menu(unsigned char *title, unsigned char *prompt, int height, int width, int menu_height, int item_no, unsigned char **items) +{ + int i, x, y, cur_x, cur_y, box_x, box_y, key = 0, button = 0, choice = 0, + scroll = 0, max_choice; + WINDOW *dialog, *menu; + + max_choice = MIN(menu_height, item_no); + + /* center dialog box on screen */ + x = (COLS - width)/2; + y = (LINES - height)/2; + +#ifdef HAVE_NCURSES + if (use_shadow) + draw_shadow(stdscr, y, x, height, width); +#endif + dialog = newwin(height, width, y, x); + keypad(dialog, TRUE); + + draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr); + wattrset(dialog, border_attr); + wmove(dialog, height-3, 0); + waddch(dialog, ACS_LTEE); + for (i = 0; i < width-2; i++) + waddch(dialog, ACS_HLINE); + wattrset(dialog, dialog_attr); + waddch(dialog, ACS_RTEE); + wmove(dialog, height-2, 1); + for (i = 0; i < width-2; i++) + waddch(dialog, ' '); + + if (title != NULL) { + wattrset(dialog, title_attr); + wmove(dialog, 0, (width - strlen(title))/2 - 1); + waddch(dialog, ' '); + waddstr(dialog, title); + waddch(dialog, ' '); + } + wattrset(dialog, dialog_attr); + print_autowrap(dialog, prompt, width, 1, 3); + + menu_width = width-6; + getyx(dialog, cur_y, cur_x); + box_y = cur_y + 1; + box_x = (width - menu_width)/2 - 1; + + /* create new window for the menu */ + menu = subwin(dialog, menu_height, menu_width, y + box_y + 1, x + box_x + 1); + keypad(menu, TRUE); + + /* draw a box around the menu items */ + draw_box(dialog, box_y, box_x, menu_height+2, menu_width+2, menubox_border_attr, menubox_attr); + + tag_x = 0; + item_x = 0; + /* Find length of longest item in order to center menu */ + for (i = 0; i < item_no; i++) { + tag_x = MAX(tag_x, strlen(items[i*2]) + strlen(items[i*2 + 1]) + 2); + item_x = MAX(item_x, strlen(items[i*2])); + } + tag_x = (menu_width - tag_x) / 2; + item_x = tag_x + item_x + 2; + + /* Print the menu */ + for (i = 0; i < max_choice; i++) + print_item(menu, items[i*2], items[i*2 + 1], i, i == choice); + wnoutrefresh(menu); + + if (menu_height < item_no) { + wattrset(dialog, darrow_attr); + wmove(dialog, box_y + menu_height + 1, box_x + tag_x + 1); + waddch(dialog, ACS_DARROW); + wmove(dialog, box_y + menu_height + 1, box_x + tag_x + 2); + waddstr(dialog,"(+)"); + } + + x = width/2-11; + y = height-2; + print_button(dialog, "Cancel", y, x+14, FALSE); + print_button(dialog, " OK ", y, x, TRUE); + wrefresh(dialog); + + while (key != ESC) { + key = wgetch(dialog); + /* Check if key pressed matches first character of any item tag in menu */ + for (i = 0; i < max_choice; i++) + if (key < 0x100 && toupper(key) == toupper(items[(scroll+i)*2][0])) + break; + + if (i < max_choice || (key >= '1' && key <= MIN('9', '0'+max_choice)) || + key == KEY_UP || key == KEY_DOWN || key == '-' || key == '+') { + if (key >= '1' && key <= MIN('9', '0'+max_choice)) + i = key - '1'; + else if (key == KEY_UP || key == '-') { + if (!choice) { + if (scroll) { +#ifdef BROKEN_WSCRL + /* wscrl() in ncurses 1.8.1 seems to be broken, causing a segmentation + violation when scrolling windows of height = 4, so scrolling is not + used for now */ + scroll--; + getyx(dialog, cur_y, cur_x); /* Save cursor position */ + /* Reprint menu to scroll down */ + for (i = 0; i < max_choice; i++) + print_item(menu, items[(scroll+i)*2], items[(scroll+i)*2 + 1], i, i == choice); + +#else + + /* Scroll menu down */ + getyx(dialog, cur_y, cur_x); /* Save cursor position */ + if (menu_height > 1) { + /* De-highlight current first item before scrolling down */ + print_item(menu, items[scroll*2], items[scroll*2 + 1], 0, FALSE); + scrollok(menu, TRUE); + wscrl(menu, -1); + scrollok(menu, FALSE); + } + scroll--; + print_item(menu, items[scroll*2], items[scroll*2 + 1], 0, TRUE); +#endif + wnoutrefresh(menu); + + /* print the up/down arrows */ + wmove(dialog, box_y, box_x + tag_x + 1); + wattrset(dialog, scroll ? uarrow_attr : menubox_attr); + waddch(dialog, scroll ? ACS_UARROW : ACS_HLINE); + wmove(dialog, box_y, box_x + tag_x + 2); + waddch(dialog, scroll ? '(' : ACS_HLINE); + wmove(dialog, box_y, box_x + tag_x + 3); + waddch(dialog, scroll ? '-' : ACS_HLINE); + wmove(dialog, box_y, box_x + tag_x + 4); + waddch(dialog, scroll ? ')' : ACS_HLINE); + wattrset(dialog, darrow_attr); + wmove(dialog, box_y + menu_height + 1, box_x + tag_x + 1); + waddch(dialog, ACS_DARROW); + wmove(dialog, box_y + menu_height + 1, box_x + tag_x + 2); + waddstr(dialog,"(+)"); + wmove(dialog, cur_y, cur_x); /* Restore cursor position */ + wrefresh(dialog); + } + continue; /* wait for another key press */ + } + else + i = choice - 1; + } + else if (key == KEY_DOWN || key == '+') + if (choice == max_choice - 1) { + if (scroll+choice < item_no-1) { +#ifdef BROKEN_WSCRL + /* wscrl() in ncurses 1.8.1 seems to be broken, causing a segmentation + violation when scrolling windows of height = 4, so scrolling is not + used for now */ + scroll++; + getyx(dialog, cur_y, cur_x); /* Save cursor position */ + /* Reprint menu to scroll up */ + for (i = 0; i < max_choice; i++) + print_item(menu, items[(scroll+i)*2], items[(scroll+i)*2 + 1], i, i == choice); + +#else + + /* Scroll menu up */ + getyx(dialog, cur_y, cur_x); /* Save cursor position */ + if (menu_height > 1) { + /* De-highlight current last item before scrolling up */ + print_item(menu, items[(scroll+max_choice-1)*2], items[(scroll+max_choice-1)*2 + 1], max_choice-1, FALSE); + scrollok(menu, TRUE); + scroll(menu); + scrollok(menu, FALSE); + } + scroll++; + print_item(menu, items[(scroll+max_choice-1)*2], items[(scroll+max_choice-1)*2 + 1], max_choice-1, TRUE); +#endif + wnoutrefresh(menu); + + /* print the up/down arrows */ + wattrset(dialog, uarrow_attr); + wmove(dialog, box_y, box_x + tag_x + 1); + waddch(dialog, ACS_UARROW); + wmove(dialog, box_y, box_x + tag_x + 2); + waddstr(dialog,"(-)"); + wmove(dialog, box_y + menu_height + 1, box_x + tag_x + 1); + wattrset(dialog, scroll+choice < item_no-1 ? darrow_attr : menubox_border_attr); + waddch(dialog, scroll+choice < item_no-1 ? ACS_DARROW : ACS_HLINE); + wmove(dialog, box_y + menu_height + 1, box_x + tag_x + 2); + waddch(dialog, scroll+choice < item_no-1 ? '(' : ACS_HLINE); + wmove(dialog, box_y + menu_height + 1, box_x + tag_x + 3); + waddch(dialog, scroll+choice < item_no-1 ? '+' : ACS_HLINE); + wmove(dialog, box_y + menu_height + 1, box_x + tag_x + 4); + waddch(dialog, scroll+choice < item_no-1 ? ')' : ACS_HLINE); + wmove(dialog, cur_y, cur_x); /* Restore cursor position */ + wrefresh(dialog); + } + continue; /* wait for another key press */ + } + else + i = choice + 1; + + if (i != choice) { + /* De-highlight current item */ + getyx(dialog, cur_y, cur_x); /* Save cursor position */ + print_item(menu, items[(scroll+choice)*2], items[(scroll+choice)*2 + 1], choice, FALSE); + + /* Highlight new item */ + choice = i; + print_item(menu, items[(scroll+choice)*2], items[(scroll+choice)*2 + 1], choice, TRUE); + wnoutrefresh(menu); + wmove(dialog, cur_y, cur_x); /* Restore cursor to previous position */ + wrefresh(dialog); + } + continue; /* wait for another key press */ + } + + switch (key) { + case 'O': + case 'o': + delwin(dialog); + fprintf(stderr, items[(scroll+choice)*2]); + return 0; + case 'C': + case 'c': + delwin(dialog); + return 1; + case KEY_BTAB: + case TAB: + case KEY_LEFT: + case KEY_RIGHT: + if (!button) { + button = 1; /* Indicates "Cancel" button is selected */ + print_button(dialog, " OK ", y, x, FALSE); + print_button(dialog, "Cancel", y, x+14, TRUE); + } + else { + button = 0; /* Indicates "OK" button is selected */ + print_button(dialog, "Cancel", y, x+14, FALSE); + print_button(dialog, " OK ", y, x, TRUE); + } + wrefresh(dialog); + break; + case ' ': + case '\n': + delwin(dialog); + if (!button) + fprintf(stderr, items[(scroll+choice)*2]); + return button; + case ESC: + break; + } + } + + delwin(dialog); + return -1; /* ESC pressed */ +} +/* End of dialog_menu() */ + + +/* + * Print menu item + */ +static void print_item(WINDOW *win, unsigned char *tag, unsigned char *item, int choice, int selected) +{ + int i; + + /* Clear 'residue' of last item */ + wattrset(win, menubox_attr); + wmove(win, choice, 0); + for (i = 0; i < menu_width; i++) + waddch(win, ' '); + wmove(win, choice, tag_x); + wattrset(win, selected ? tag_key_selected_attr : tag_key_attr); + waddch(win, tag[0]); + wattrset(win, selected ? tag_selected_attr : tag_attr); + waddstr(win, tag + 1); + wmove(win, choice, item_x); + wattrset(win, selected ? item_selected_attr : item_attr); + waddstr(win, item); +} +/* End of print_item() */ diff --git a/gnu/usr.bin/dialog/msgbox.c b/gnu/usr.bin/dialog/msgbox.c new file mode 100644 index 000000000000..7fe6ae24dc8d --- /dev/null +++ b/gnu/usr.bin/dialog/msgbox.c @@ -0,0 +1,81 @@ +/* + * msgbox.c -- implements the message box and info box + * + * AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include "dialog.h" + + +/* + * Display a message box. Program will pause and display an "OK" button + * if the parameter 'pause' is non-zero. + */ +int dialog_msgbox(unsigned char *title, unsigned char *prompt, int height, int width, int pause) +{ + int i, x, y, key = 0; + WINDOW *dialog; + + /* center dialog box on screen */ + x = (COLS - width)/2; + y = (LINES - height)/2; + +#ifdef HAVE_NCURSES + if (use_shadow) + draw_shadow(stdscr, y, x, height, width); +#endif + dialog = newwin(height, width, y, x); + keypad(dialog, TRUE); + + draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr); + + if (title != NULL) { + wattrset(dialog, title_attr); + wmove(dialog, 0, (width - strlen(title))/2 - 1); + waddch(dialog, ' '); + waddstr(dialog, title); + waddch(dialog, ' '); + } + wattrset(dialog, dialog_attr); + print_autowrap(dialog, prompt, width-2, 1, 2); + + if (pause) { + wattrset(dialog, border_attr); + wmove(dialog, height-3, 0); + waddch(dialog, ACS_LTEE); + for (i = 0; i < width-2; i++) + waddch(dialog, ACS_HLINE); + wattrset(dialog, dialog_attr); + waddch(dialog, ACS_RTEE); + wmove(dialog, height-2, 1); + for (i = 0; i < width-2; i++) + waddch(dialog, ' '); + print_button(dialog, " OK ", height-2, width/2-4, TRUE); + wrefresh(dialog); + while (key != ESC && key != '\n' && key != ' ') + key = wgetch(dialog); + } + else { + key = '\n'; + wrefresh(dialog); + } + + delwin(dialog); + return (key == ESC ? -1 : 0); +} +/* End of dialog_msgbox() */ diff --git a/gnu/usr.bin/dialog/radiolist.c b/gnu/usr.bin/dialog/radiolist.c new file mode 100644 index 000000000000..51259248a7fd --- /dev/null +++ b/gnu/usr.bin/dialog/radiolist.c @@ -0,0 +1,353 @@ +/* + * radiolist.c -- implements the radiolist box + * + * AUTHOR: Stuart Herbert - S.Herbert@sheffield.ac.uk + * (from checklist.c by Savio Lam (lam836@cs.cuhk.hk)) + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include "dialog.h" + + +static void print_item(WINDOW *win, char *tag, char *item, int status, int choice, int selected); + + +static int list_width, check_x, item_x; + + +/* + * Display a dialog box with a list of options that can be turned on or off + */ +int dialog_radiolist(char *title, char *prompt, int height, int width, int list_height, int item_no, unsigned char **items) +{ + int i, x, y, cur_x, cur_y, box_x, box_y, key = 0, button = 0, choice = 0, + scroll = 0, max_choice, *status; + WINDOW *dialog, *list; + + /* Allocate space for storing item on/off status */ + if ((status = malloc(sizeof(int)*item_no)) == NULL) { + endwin(); + fprintf(stderr, "\nCan't allocate memory in dialog_radiolist().\n"); + exit(-1); + } + /* Initializes status */ + for (i = 0; i < item_no; i++) + status[i] = !strcasecmp(items[i*3 + 2], "on"); + + max_choice = MIN(list_height, item_no); + + /* center dialog box on screen */ + x = (COLS - width)/2; + y = (LINES - height)/2; + +#ifdef HAVE_NCURSES + if (use_shadow) + draw_shadow(stdscr, y, x, height, width); +#endif + dialog = newwin(height, width, y, x); + keypad(dialog, TRUE); + + draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr); + wattrset(dialog, border_attr); + wmove(dialog, height-3, 0); + waddch(dialog, ACS_LTEE); + for (i = 0; i < width-2; i++) + waddch(dialog, ACS_HLINE); + wattrset(dialog, dialog_attr); + waddch(dialog, ACS_RTEE); + wmove(dialog, height-2, 1); + for (i = 0; i < width-2; i++) + waddch(dialog, ' '); + + if (title != NULL) { + wattrset(dialog, title_attr); + wmove(dialog, 0, (width - strlen(title))/2 - 1); + waddch(dialog, ' '); + waddstr(dialog, title); + waddch(dialog, ' '); + } + wattrset(dialog, dialog_attr); + print_autowrap(dialog, prompt, width, 1, 3); + + list_width = width-6; + getyx(dialog, cur_y, cur_x); + box_y = cur_y + 1; + box_x = (width - list_width)/2 - 1; + + /* create new window for the list */ + list = subwin(dialog, list_height, list_width, y + box_y + 1, x + box_x + 1); + keypad(list, TRUE); + + /* draw a box around the list items */ + draw_box(dialog, box_y, box_x, list_height+2, list_width+2, menubox_border_attr, menubox_attr); + + check_x = 0; + item_x = 0; + /* Find length of longest item in order to center radiolist */ + for (i = 0; i < item_no; i++) { + check_x = MAX(check_x, strlen(items[i*3]) + strlen(items[i*3 + 1]) + 6); + item_x = MAX(item_x, strlen(items[i*3])); + } + check_x = (list_width - check_x) / 2; + item_x = check_x + item_x + 6; + + /* Print the list */ + for (i = 0; i < max_choice; i++) + print_item(list, items[i*3], items[i*3 + 1], status[i], i, i == choice); + wnoutrefresh(list); + + if (list_height < item_no) { + wattrset(dialog, darrow_attr); + wmove(dialog, box_y + list_height + 1, box_x + check_x + 5); + waddch(dialog, ACS_DARROW); + wmove(dialog, box_y + list_height + 1, box_x + check_x + 6); + waddstr(dialog, "(+)"); + } + + x = width/2-11; + y = height-2; + print_button(dialog, "Cancel", y, x+14, FALSE); + print_button(dialog, " OK ", y, x, TRUE); + wrefresh(dialog); + + while (key != ESC) { + key = wgetch(dialog); + /* Check if key pressed matches first character of any item tag in list */ + for (i = 0; i < max_choice; i++) + if (toupper(key) == toupper(items[(scroll+i)*3][0])) + break; + + if (i < max_choice || (key >= '1' && key <= MIN('9', '0'+max_choice)) || + key == KEY_UP || key == KEY_DOWN || key == ' ' || + key == '+' || key == '-' ) { + if (key >= '1' && key <= MIN('9', '0'+max_choice)) + i = key - '1'; + else if (key == KEY_UP || key == '-') { + if (!choice) { + if (scroll) { +#ifdef BROKEN_WSCRL + /* wscrl() in ncurses 1.8.1 seems to be broken, causing a segmentation + violation when scrolling windows of height = 4, so scrolling is not + used for now */ + scroll--; + getyx(dialog, cur_y, cur_x); /* Save cursor position */ + /* Reprint list to scroll down */ + for (i = 0; i < max_choice; i++) + print_item(list, items[(scroll+i)*3], items[(scroll+i)*3 + 1], status[scroll+i], i, i == choice); + +#else + + /* Scroll list down */ + getyx(dialog, cur_y, cur_x); /* Save cursor position */ + if (list_height > 1) { + /* De-highlight current first item before scrolling down */ + print_item(list, items[scroll*3], items[scroll*3 + 1], status[scroll], 0, FALSE); + scrollok(list, TRUE); + wscrl(list, -1); + scrollok(list, FALSE); + } + scroll--; + print_item(list, items[scroll*3], items[scroll*3 + 1], status[scroll], 0, TRUE); +#endif + wnoutrefresh(list); + + /* print the up/down arrows */ + wmove(dialog, box_y, box_x + check_x + 5); + wattrset(dialog, scroll ? uarrow_attr : menubox_attr); + waddch(dialog, scroll ? ACS_UARROW : ACS_HLINE); + wmove(dialog, box_y, box_x + check_x + 6); + waddch(dialog, scroll ? '(' : ACS_HLINE); + wmove(dialog, box_y, box_x + check_x + 7); + waddch(dialog, scroll ? '-' : ACS_HLINE); + wmove(dialog, box_y, box_x + check_x + 8); + waddch(dialog, scroll ? ')' : ACS_HLINE); + wattrset(dialog, darrow_attr); + wmove(dialog, box_y + list_height + 1, box_x + check_x + 5); + waddch(dialog, ACS_DARROW); + wmove(dialog, box_y + list_height + 1, box_x + check_x + 6); + waddch(dialog, '('); + wmove(dialog, box_y + list_height + 1, box_x + check_x + 7); + waddch(dialog, '+'); + wmove(dialog, box_y + list_height + 1, box_x + check_x + 8); + waddch(dialog, ')'); + wmove(dialog, cur_y, cur_x); /* Restore cursor position */ + wrefresh(dialog); + } + continue; /* wait for another key press */ + } + else + i = choice - 1; + } + else if (key == KEY_DOWN || key == '+') { + if (choice == max_choice - 1) { + if (scroll+choice < item_no-1) { +#ifdef BROKEN_WSCRL + /* wscrl() in ncurses 1.8.1 seems to be broken, causing a segmentation + violation when scrolling windows of height = 4, so scrolling is not + used for now */ + scroll++; + getyx(dialog, cur_y, cur_x); /* Save cursor position */ + /* Reprint list to scroll up */ + for (i = 0; i < max_choice; i++) + print_item(list, items[(scroll+i)*3], items[(scroll+i)*3 + 1], status[scroll+i], i, i == choice); + +#else + + /* Scroll list up */ + getyx(dialog, cur_y, cur_x); /* Save cursor position */ + if (list_height > 1) { + /* De-highlight current last item before scrolling up */ + print_item(list, items[(scroll+max_choice-1)*3], items[(scroll+max_choice-1)*3 + 1], status[scroll+max_choice-1], max_choice-1, FALSE); + scrollok(list, TRUE); + scroll(list); + scrollok(list, FALSE); + } + scroll++; + print_item(list, items[(scroll+max_choice-1)*3], items[(scroll+max_choice-1)*3 + 1], status[scroll+max_choice-1], max_choice-1, TRUE); +#endif + wnoutrefresh(list); + + /* print the up/down arrows */ + wattrset(dialog, uarrow_attr); + wmove(dialog, box_y, box_x + check_x + 5); + waddch(dialog, ACS_UARROW); + wmove(dialog, box_y, box_x + check_x + 6); + waddstr(dialog, "(-)"); + wmove(dialog, box_y + list_height + 1, box_x + check_x + 5); + wattrset(dialog, scroll+choice < item_no-1 ? darrow_attr : menubox_border_attr); + waddch(dialog, scroll+choice < item_no-1 ? ACS_DARROW : ACS_HLINE); + wmove(dialog, box_y + list_height + 1, box_x + check_x + 6); + waddch(dialog, scroll+choice < item_no-1 ? '(' : ACS_HLINE); + wmove(dialog, box_y + list_height + 1, box_x + check_x + 7); + waddch(dialog, scroll+choice < item_no-1 ? '+' : ACS_HLINE); + wmove(dialog, box_y + list_height + 1, box_x + check_x + 8); + waddch(dialog, scroll+choice < item_no-1 ? ')' : ACS_HLINE); + wmove(dialog, cur_y, cur_x); /* Restore cursor position */ + wrefresh(dialog); + } + continue; /* wait for another key press */ + } + else + i = choice + 1; + } + else if (key == ' ') { /* Toggle item status */ + if (!status[scroll+choice]) + { + for (i=0; i<item_no; i++) + status[i]=0; + status[scroll+choice]=1; + getyx(dialog, cur_y, cur_x); /* Save cursor position */ + for (i = 0; i < max_choice; i++) + print_item(list, items[(scroll+i)*3], items[(scroll+i)*3 + 1], status[scroll+i], i, i == choice); + wnoutrefresh(list); + wmove(dialog, cur_y, cur_x); /* Restore cursor to previous position */ + wrefresh(dialog); + } + continue; /* wait for another key press */ + } + + if (i != choice) { + /* De-highlight current item */ + getyx(dialog, cur_y, cur_x); /* Save cursor position */ + print_item(list, items[(scroll+choice)*3], items[(scroll+choice)*3 +1], status[scroll+choice], choice, FALSE); + /* Highlight new item */ + choice = i; + print_item(list, items[(scroll+choice)*3], items[(scroll+choice)*3 + 1], status[scroll+choice], choice, TRUE); + wnoutrefresh(list); + wmove(dialog, cur_y, cur_x); /* Restore cursor to previous position */ + wrefresh(dialog); + } + continue; /* wait for another key press */ + } + + switch (key) { + case 'O': + case 'o': + delwin(dialog); + for (i = 0; i < item_no; i++) + if (status[i]) + fprintf(stderr, "%s", items[i*3]); + free(status); + return 0; + case 'C': + case 'c': + delwin(dialog); + free(status); + return 1; + case KEY_BTAB: + case TAB: + case KEY_LEFT: + case KEY_RIGHT: + if (!button) { + button = 1; /* Indicates "Cancel" button is selected */ + print_button(dialog, " OK ", y, x, FALSE); + print_button(dialog, "Cancel", y, x+14, TRUE); + } + else { + button = 0; /* Indicates "OK" button is selected */ + print_button(dialog, "Cancel", y, x+14, FALSE); + print_button(dialog, " OK ", y, x, TRUE); + } + wrefresh(dialog); + break; + case ' ': + case '\n': + delwin(dialog); + if (!button) + for (i = 0; i < item_no; i++) + if (status[i]) + fprintf(stderr, items[i*3]); + free(status); + return button; + case ESC: + break; + } + } + + delwin(dialog); + free(status); + return -1; /* ESC pressed */ +} +/* End of dialog_radiolist() */ + + +/* + * Print list item + */ +static void print_item(WINDOW *win, char *tag, char *item, int status, int choice, int selected) +{ + int i; + + /* Clear 'residue' of last item */ + wattrset(win, menubox_attr); + wmove(win, choice, 0); + for (i = 0; i < list_width; i++) + waddch(win, ' '); + wmove(win, choice, check_x); + wattrset(win, selected ? check_selected_attr : check_attr); + wprintw(win, "(%c)", status ? '*' : ' '); + wattrset(win, menubox_attr); + waddch(win, ' '); + wattrset(win, selected ? tag_key_selected_attr : tag_key_attr); + waddch(win, tag[0]); + wattrset(win, selected ? tag_selected_attr : tag_attr); + waddstr(win, tag + 1); + wmove(win, choice, item_x); + wattrset(win, selected ? item_selected_attr : item_attr); + waddstr(win, item); +} +/* End of print_item() */ diff --git a/gnu/usr.bin/dialog/rc.c b/gnu/usr.bin/dialog/rc.c new file mode 100644 index 000000000000..46add74bed2b --- /dev/null +++ b/gnu/usr.bin/dialog/rc.c @@ -0,0 +1,375 @@ +/* + * rc.c -- routines for processing the configuration file + * + * AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include "dialog.h" +#include "colors.h" +#include "rc.h" + + +static unsigned char *attr_to_str(int fg, int bg, int hl); +static int str_to_attr(unsigned char *str, int *fg, int *bg, int *hl); +static int parse_line(unsigned char *line, unsigned char **var, unsigned char **value); + + +/* + * Create the configuration file + */ +void create_rc(unsigned char *filename) +{ + int i; + FILE *rc_file; + + if ((rc_file = fopen(filename, "wt")) == NULL) { + fprintf(stderr, "\nError opening file for writing in create_rc().\n"); + exit(-1); + } + + fprintf(rc_file, "#\ +\n# Run-time configuration file for dialog\ +\n#\ +\n# Automatically generated by \"dialog --create-rc <file>\"\ +\n#\ +\n#\ +\n# Types of values:\ +\n#\ +\n# Number - <number>\ +\n# String - \"string\"\ +\n# Boolean - <ON|OFF>\ +\n# Attribute - (foreground,background,highlight?)\ +\n#\n\n"); + + /* Print an entry for each configuration variable */ + for (i = 0; i < VAR_COUNT; i++) { + fprintf(rc_file, "\n# %s\n", vars[i].comment); /* print comment */ + switch (vars[i].type) { + case VAL_INT: + fprintf(rc_file, "%s = %d\n", vars[i].name, *((int *) vars[i].var)); + break; + case VAL_STR: + fprintf(rc_file, "%s = \"%s\"\n", vars[i].name, (unsigned char *) vars[i].var); + break; + case VAL_BOOL: + fprintf(rc_file, "%s = %s\n", vars[i].name, *((bool *) vars[i].var) ? "ON" : "OFF"); + break; + case VAL_ATTR: + fprintf(rc_file, "%s = %s\n", vars[i].name, attr_to_str(((int *) vars[i].var)[0], ((int *) vars[i].var)[1], ((int *) vars[i].var)[2])); + break; + } + } + + fclose(rc_file); +} +/* End of create_rc() */ + + +/* + * Parse the configuration file and set up variables + */ +int parse_rc(void) +{ + int i, l = 1, parse, fg, bg, hl; + unsigned char str[MAX_LEN+1], *var, *value, *tempptr; + FILE *rc_file; + + /* + * + * At start, 'dialog' determines the settings to use as follows: + * + * a) if environment variable DIALOGRC is set, it's value determines the + * name of the configuration file. + * + * b) if the file in (a) can't be found, use the file $HOME/.dialogrc + * as the configuration file. + * + * c) if the file in (b) can't be found, use compiled in defaults. + * + */ + + if ((tempptr = getenv("DIALOGRC")) != NULL) + rc_file = fopen(tempptr, "rt"); + + if (tempptr == NULL || rc_file == NULL) { /* step (a) failed? */ + /* try step (b) */ + if ((tempptr = getenv("HOME")) == NULL) + return 0; /* step (b) failed, use default values */ + + if (tempptr[0] == '\0' || lastch(tempptr) == '/') + sprintf(str, "%s%s", tempptr, DIALOGRC); + else + sprintf(str, "%s/%s", tempptr, DIALOGRC); + + if ((rc_file = fopen(str, "rt")) == NULL) + return 0; /* step (b) failed, use default values */ + } + + /* Scan each line and set variables */ + while (fgets(str, MAX_LEN, rc_file) != NULL) { + if (lastch(str) != '\n') { /* ignore rest of file if line too long */ + fprintf(stderr, "\nParse error: line %d of configuration file too long.\n", l); + fclose(rc_file); + return -1; /* parse aborted */ + } + else { + lastch(str) = '\0'; + parse = parse_line(str, &var, &value); /* parse current line */ + + switch (parse) { + case LINE_BLANK: /* ignore blank lines and comments */ + case LINE_COMMENT: + break; + case LINE_OK: + /* search table for matching config variable name */ + for (i = 0; i < VAR_COUNT && strcmp(vars[i].name, var); i++); + + if (i == VAR_COUNT) { /* no match */ + fprintf(stderr, "\nParse error: unknown variable at line %d of configuration file.\n", l); + return -1; /* parse aborted */ + } + else { /* variable found in table, set run time variables */ + switch (vars[i].type) { + case VAL_INT: + *((int *) vars[i].var) = atoi(value); + break; + case VAL_STR: + if (!isquote(value[0]) || !isquote(lastch(value)) || strlen(value) < 2) { + fprintf(stderr, "\nParse error: string value expected at line %d of configuration file.\n", l); + return -1; /* parse aborted */ + } + else { + /* remove the (") quotes */ + value++; + lastch(value) = '\0'; + strcpy((unsigned char *) vars[i].var, value); + } + break; + case VAL_BOOL: + if (!strcasecmp(value, "ON")) + *((bool *) vars[i].var) = TRUE; + else if (!strcasecmp(value, "OFF")) + *((bool *) vars[i].var) = FALSE; + else { + fprintf(stderr, "\nParse error: boolean value expected at line %d of configuration file.\n", l); + return -1; /* parse aborted */ + } + break; + case VAL_ATTR: + if (str_to_attr(value, &fg, &bg, &hl) == -1) { + fprintf(stderr, "\nParse error: attribute value expected at line %d of configuration file.\n", l); + return -1; /* parse aborted */ + } + ((int *) vars[i].var)[0] = fg; + ((int *) vars[i].var)[1] = bg; + ((int *) vars[i].var)[2] = hl; + break; + } + } + break; + case LINE_ERROR: + fprintf(stderr, "\nParse error: syntax error at line %d of configuration file.\n", l); + return -1; /* parse aborted */ + } + } + + l++; /* next line */ + } + + fclose(rc_file); + return 0; /* parse successful */ +} +/* End of parse_rc() */ + + +/* + * Convert an attribute to a string representation like this: + * + * "(foreground,background,highlight)" + */ +static unsigned char *attr_to_str(int fg, int bg, int hl) +{ + int i; + static unsigned char str[MAX_LEN+1]; + + strcpy(str, "("); + /* foreground */ + for (i = 0; fg != color_names[i].value; i++); + strcat(str, color_names[i].name); + strcat(str, ","); + + /* background */ + for (i = 0; bg != color_names[i].value; i++); + strcat(str, color_names[i].name); + + /* highlight */ + strcat(str, hl ? ",ON)" : ",OFF)"); + + return str; +} +/* End of attr_to_str() */ + + +/* + * Extract the foreground, background and highlight values from an attribute + * represented as a string in this form: + * + * "(foreground,background,highlight)" + */ +static int str_to_attr(unsigned char *str, int *fg, int *bg, int *hl) +{ + int i = 0, j, get_fg = 1; + unsigned char tempstr[MAX_LEN+1], *part; + + if (str[0] != '(' || lastch(str) != ')') + return -1; /* invalid representation */ + + /* remove the parenthesis */ + strcpy(tempstr, str + 1); + lastch(tempstr) = '\0'; + + + /* get foreground and background */ + + while (1) { + /* skip white space before fg/bg string */ + while (whitespace(tempstr[i]) && tempstr[i] != '\0') i++; + if (tempstr[i] == '\0') + return -1; /* invalid representation */ + part = tempstr + i; /* set 'part' to start of fg/bg string */ + + /* find end of fg/bg string */ + while(!whitespace(tempstr[i]) && tempstr[i] != ',' && tempstr[i] != '\0') i++; + + if (tempstr[i] == '\0') + return -1; /* invalid representation */ + else if (whitespace(tempstr[i])) { /* not yet ',' */ + tempstr[i++] = '\0'; + + /* skip white space before ',' */ + while(whitespace(tempstr[i]) && tempstr[i] != '\0') i++; + + if (tempstr[i] != ',') + return -1; /* invalid representation */ + } + + tempstr[i++] = '\0'; /* skip the ',' */ + for (j = 0; j < COLOR_COUNT && strcasecmp(part, color_names[j].name); j++); + if (j == COLOR_COUNT) /* invalid color name */ + return -1; + if (get_fg) { + *fg = color_names[j].value; + get_fg = 0; /* next we have to get the background */ + } + else { + *bg = color_names[j].value; + break; + } + } /* got foreground and background */ + + + /* get highlight */ + + /* skip white space before highlight string */ + while (whitespace(tempstr[i]) && tempstr[i] != '\0') i++; + if (tempstr[i] == '\0') + return -1; /* invalid representation */ + part = tempstr + i; /* set 'part' to start of highlight string */ + + /* trim trailing white space from highlight string */ + i = strlen(part) - 1; + while(whitespace(part[i])) i--; + part[i+1] = '\0'; + + if (!strcasecmp(part, "ON")) + *hl = TRUE; + else if (!strcasecmp(part, "OFF")) + *hl = FALSE; + else + return -1; /* invalid highlight value */ + + return 0; +} +/* End of str_to_attr() */ + + +/* + * Parse a line in the configuration file + * + * Each line is of the form: "variable = value". On exit, 'var' will contain + * the variable name, and 'value' will contain the value string. + * + * Return values: + * + * LINE_BLANK - line is blank + * LINE_COMMENT - line is comment + * LINE_OK - line is ok + * LINE_ERROR - syntax error in line + */ +static int parse_line(unsigned char *line, unsigned char **var, unsigned char **value) +{ + int i = 0; + + /* ignore white space at beginning of line */ + while(whitespace(line[i]) && line[i] != '\0') i++; + + if (line[i] == '\0') /* line is blank */ + return LINE_BLANK; + else if (line[i] == '#') /* line is comment */ + return LINE_COMMENT; + else if (line[i] == '=') /* variables names can't strart with a '=' */ + return LINE_ERROR; + + /* set 'var' to variable name */ + *var = line + i++; /* skip to next character */ + + /* find end of variable name */ + while(!whitespace(line[i]) && line[i] != '=' && line[i] != '\0') i++; + + if (line[i] == '\0') /* syntax error */ + return LINE_ERROR; + else if (line[i] == '=') + line[i++] = '\0'; + else { + line[i++] = '\0'; + + /* skip white space before '=' */ + while(whitespace(line[i]) && line[i] != '\0') i++; + + if (line[i] != '=') /* syntax error */ + return LINE_ERROR; + else + i++; /* skip the '=' */ + } + + /* skip white space after '=' */ + while(whitespace(line[i]) && line[i] != '\0') i++; + + if (line[i] == '\0') + return LINE_ERROR; + else + *value = line + i; /* set 'value' to value string */ + + /* trim trailing white space from 'value' */ + i = strlen(*value) - 1; + while(whitespace((*value)[i])) i--; + (*value)[i+1] = '\0'; + + return LINE_OK; /* no syntax error in line */ +} +/* End of parse_line() */ diff --git a/gnu/usr.bin/dialog/rc.h b/gnu/usr.bin/dialog/rc.h new file mode 100644 index 000000000000..225ff6ddf306 --- /dev/null +++ b/gnu/usr.bin/dialog/rc.h @@ -0,0 +1,223 @@ +/* + * rc.h -- declarations for configuration file processing + * + * AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#define DIALOGRC ".dialogrc" +#define VAR_LEN 30 +#define COMMENT_LEN 70 + +/* Types of values */ +#define VAL_INT 0 +#define VAL_STR 1 +#define VAL_BOOL 2 +#define VAL_ATTR 3 + +/* Type of line in configuration file */ +#define LINE_BLANK 2 +#define LINE_COMMENT 1 +#define LINE_OK 0 +#define LINE_ERROR -1 + +/* number of configuration variables */ +#define VAR_COUNT (sizeof(vars) / sizeof(vars_st)) + +/* check if character is white space */ +#define whitespace(c) (c == ' ' || c == '\t') + +/* check if character is string quoting characters */ +#define isquote(c) (c == '"' || c == '\'') + +/* get last character of string */ +#define lastch(str) str[strlen(str)-1] + +/* + * Configuration variables + */ +typedef struct { + unsigned char name[VAR_LEN]; /* name of configuration variable as in DIALOGRC */ + void *var; /* address of actually variable to change */ + int type; /* type of value */ + unsigned char comment[COMMENT_LEN]; /* comment to put in "rc" file */ +} vars_st; + +vars_st vars[] = { + { "use_shadow", + &use_shadow, + VAL_BOOL, + "Shadow dialog boxes? This also turns on color." }, + + { "use_colors", + &use_colors, + VAL_BOOL, + "Turn color support ON or OFF" }, + + { "screen_color", + color_table[0], + VAL_ATTR, + "Screen color" }, + + { "shadow_color", + color_table[1], + VAL_ATTR, + "Shadow color" }, + + { "dialog_color", + color_table[2], + VAL_ATTR, + "Dialog box color" }, + + { "title_color", + color_table[3], + VAL_ATTR, + "Dialog box title color" }, + + { "border_color", + color_table[4], + VAL_ATTR, + "Dialog box border color" }, + + { "button_active_color", + color_table[5], + VAL_ATTR, + "Active button color" }, + + { "button_inactive_color", + color_table[6], + VAL_ATTR, + "Inactive button color" }, + + { "button_key_active_color", + color_table[7], + VAL_ATTR, + "Active button key color" }, + + { "button_key_inactive_color", + color_table[8], + VAL_ATTR, + "Inactive button key color" }, + + { "button_label_active_color", + color_table[9], + VAL_ATTR, + "Active button label color" }, + + { "button_label_inactive_color", + color_table[10], + VAL_ATTR, + "Inactive button label color" }, + + { "inputbox_color", + color_table[11], + VAL_ATTR, + "Input box color" }, + + { "inputbox_border_color", + color_table[12], + VAL_ATTR, + "Input box border color" }, + + { "searchbox_color", + color_table[13], + VAL_ATTR, + "Search box color" }, + + { "searchbox_title_color", + color_table[14], + VAL_ATTR, + "Search box title color" }, + + { "searchbox_border_color", + color_table[15], + VAL_ATTR, + "Search box border color" }, + + { "position_indicator_color", + color_table[16], + VAL_ATTR, + "File position indicator color" }, + + { "menubox_color", + color_table[17], + VAL_ATTR, + "Menu box color" }, + + { "menubox_border_color", + color_table[18], + VAL_ATTR, + "Menu box border color" }, + + { "item_color", + color_table[19], + VAL_ATTR, + "Item color" }, + + { "item_selected_color", + color_table[20], + VAL_ATTR, + "Selected item color" }, + + { "tag_color", + color_table[21], + VAL_ATTR, + "Tag color" }, + + { "tag_selected_color", + color_table[22], + VAL_ATTR, + "Selected tag color" }, + + { "tag_key_color", + color_table[23], + VAL_ATTR, + "Tag key color" }, + + { "tag_key_selected_color", + color_table[24], + VAL_ATTR, + "Selected tag key color" }, + + { "check_color", + color_table[25], + VAL_ATTR, + "Check box color" }, + + { "check_selected_color", + color_table[26], + VAL_ATTR, + "Selected check box color" }, + + { "uarrow_color", + color_table[27], + VAL_ATTR, + "Up arrow color" }, + + { "darrow_color", + color_table[28], + VAL_ATTR, + "Down arrow color" } +}; /* vars */ + + + +/* + * Routines to process configuration file + */ +void create_rc(unsigned char *filename); +int parse_rc(void); diff --git a/gnu/usr.bin/dialog/textbox.c b/gnu/usr.bin/dialog/textbox.c new file mode 100644 index 000000000000..23e12839a5e8 --- /dev/null +++ b/gnu/usr.bin/dialog/textbox.c @@ -0,0 +1,709 @@ +/* + * textbox.c -- implements the text box + * + * AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include "dialog.h" + + +static void back_lines(int n); +static void print_page(WINDOW *win, int height, int width); +static void print_line(WINDOW *win, int row, int width); +static unsigned char *get_line(void); +static int get_search_term(WINDOW *win, unsigned char *search_term, int height, int width); +static void print_position(WINDOW *win, int height, int width); + + +static int hscroll = 0, fd, file_size, bytes_read, begin_reached = 1, + end_reached = 0, page_length; +static unsigned char *buf, *page; + + +/* + * Display text from a file in a dialog box. + */ +int dialog_textbox(unsigned char *title, unsigned char *file, int height, int width) +{ + int i, x, y, cur_x, cur_y, fpos, key = 0, dir, temp, temp1; +#ifdef HAVE_NCURSES + int passed_end; +#endif + unsigned char search_term[MAX_LEN+1], *tempptr, *found; + WINDOW *dialog, *text; + + search_term[0] = '\0'; /* no search term entered yet */ + + /* Open input file for reading */ + if ((fd = open(file, O_RDONLY)) == -1) { + endwin(); + fprintf(stderr, "\nCan't open input file in dialog_textbox().\n"); + exit(-1); + } + /* Get file size. Actually, 'file_size' is the real file size - 1, + since it's only the last byte offset from the beginning */ + if ((file_size = lseek(fd, 0, SEEK_END)) == -1) { + endwin(); + fprintf(stderr, "\nError getting file size in dialog_textbox().\n"); + exit(-1); + } + /* Restore file pointer to beginning of file after getting file size */ + if (lseek(fd, 0, SEEK_SET) == -1) { + endwin(); + fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n"); + exit(-1); + } + /* Allocate space for read buffer */ + if ((buf = malloc(BUF_SIZE+1)) == NULL) { + endwin(); + fprintf(stderr, "\nCan't allocate memory in dialog_textbox().\n"); + exit(-1); + } + if ((bytes_read = read(fd, buf, BUF_SIZE)) == -1) { + endwin(); + fprintf(stderr, "\nError reading file in dialog_textbox().\n"); + exit(-1); + } + buf[bytes_read] = '\0'; /* mark end of valid data */ + page = buf; /* page is pointer to start of page to be displayed */ + + /* center dialog box on screen */ + x = (COLS - width)/2; + y = (LINES - height)/2; + +#ifdef HAVE_NCURSES + if (use_shadow) + draw_shadow(stdscr, y, x, height, width); +#endif + dialog = newwin(height, width, y, x); + keypad(dialog, TRUE); + + /* Create window for text region, used for scrolling text */ +/* text = newwin(height-4, width-2, y+1, x+1); */ + text = subwin(dialog, height-4, width-2, y+1, x+1); + keypad(text, TRUE); + + draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr); + + wattrset(dialog, border_attr); + wmove(dialog, height-3, 0); + waddch(dialog, ACS_LTEE); + for (i = 0; i < width-2; i++) + waddch(dialog, ACS_HLINE); + wattrset(dialog, dialog_attr); + waddch(dialog, ACS_RTEE); + wmove(dialog, height-2, 1); + for (i = 0; i < width-2; i++) + waddch(dialog, ' '); + + if (title != NULL) { + wattrset(dialog, title_attr); + wmove(dialog, 0, (width - strlen(title))/2 - 1); + waddch(dialog, ' '); + waddstr(dialog, title); + waddch(dialog, ' '); + } + print_button(dialog, " EXIT ", height-2, width/2-4, TRUE); + wnoutrefresh(dialog); + getyx(dialog, cur_y, cur_x); /* Save cursor position */ + + /* Print first page of text */ + attr_clear(text, height-4, width-2, dialog_attr); + print_page(text, height-4, width-2); + print_position(dialog, height, width); + wmove(dialog, cur_y, cur_x); /* Restore cursor position */ + wrefresh(dialog); + + while ((key != ESC) && (key != '\n')) { + key = wgetch(dialog); + switch (key) { + case 'E': /* Exit */ + case 'e': + delwin(dialog); + free(buf); + close(fd); + return 0; + case 'g': /* First page */ + case KEY_HOME: + if (!begin_reached) { + begin_reached = 1; + /* First page not in buffer? */ + if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) { + endwin(); + fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n"); + exit(-1); + } + if (fpos > bytes_read) { /* Yes, we have to read it in */ + if (lseek(fd, 0, SEEK_SET) == -1) { + endwin(); + fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n"); + exit(-1); + } + if ((bytes_read = read(fd, buf, BUF_SIZE)) == -1) { + endwin(); + fprintf(stderr, "\nError reading file in dialog_textbox().\n"); + exit(-1); + } + buf[bytes_read] = '\0'; + } + page = buf; + print_page(text, height-4, width-2); + print_position(dialog, height, width); + wmove(dialog, cur_y, cur_x); /* Restore cursor position */ + wrefresh(dialog); + } + break; + case 'G': /* Last page */ +#ifdef HAVE_NCURSES + case KEY_END: +#endif + end_reached = 1; + /* Last page not in buffer? */ + if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) { + endwin(); + fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n"); + exit(-1); + } + if (fpos < file_size) { /* Yes, we have to read it in */ + if (lseek(fd, -BUF_SIZE, SEEK_END) == -1) { + endwin(); + fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n"); + exit(-1); + } + if ((bytes_read = read(fd, buf, BUF_SIZE)) == -1) { + endwin(); + fprintf(stderr, "\nError reading file in dialog_textbox().\n"); + exit(-1); + } + buf[bytes_read] = '\0'; + } + page = buf + bytes_read; + back_lines(height-4); + print_page(text, height-4, width-2); + print_position(dialog, height, width); + wmove(dialog, cur_y, cur_x); /* Restore cursor position */ + wrefresh(dialog); + break; + case 'K': /* Previous line */ + case 'k': + case KEY_UP: + if (!begin_reached) { + back_lines(page_length+1); +#ifdef HAVE_NCURSES + /* We don't call print_page() here but use scrolling to ensure + faster screen update. However, 'end_reached' and 'page_length' + should still be updated, and 'page' should point to start of + next page. This is done by calling get_line() in the following + 'for' loop. */ + scrollok(text, TRUE); + wscrl(text, -1); /* Scroll text region down one line */ + scrollok(text, FALSE); + page_length = 0; + passed_end = 0; + for (i = 0; i < height-4; i++) { + if (!i) { + print_line(text, 0, width-2); /* print first line of page */ + wnoutrefresh(text); + } + else + get_line(); /* Called to update 'end_reached' and 'page' */ + if (!passed_end) + page_length++; + if (end_reached && !passed_end) + passed_end = 1; + } +#else + print_page(text, height-4, width-2); +#endif + print_position(dialog, height, width); + wmove(dialog, cur_y, cur_x); /* Restore cursor position */ + wrefresh(dialog); + } + break; + case 'B': /* Previous page */ + case 'b': + case KEY_PPAGE: + if (!begin_reached) { + back_lines(page_length + height-4); + print_page(text, height-4, width-2); + print_position(dialog, height, width); + wmove(dialog, cur_y, cur_x); /* Restore cursor position */ + wrefresh(dialog); + } + break; + case 'J': /* Next line */ + case 'j': + case KEY_DOWN: + if (!end_reached) { + begin_reached = 0; + scrollok(text, TRUE); + scroll(text); /* Scroll text region up one line */ + scrollok(text, FALSE); + print_line(text, height-5, width-2); +#ifndef HAVE_NCURSES + wmove(text, height-5, 0); + waddch(text, ' '); + wmove(text, height-5, width-3); + waddch(text, ' '); +#endif + wnoutrefresh(text); + print_position(dialog, height, width); + wmove(dialog, cur_y, cur_x); /* Restore cursor position */ + wrefresh(dialog); + } + break; + case ' ': /* Next page */ + case KEY_NPAGE: + if (!end_reached) { + begin_reached = 0; + print_page(text, height-4, width-2); + print_position(dialog, height, width); + wmove(dialog, cur_y, cur_x); /* Restore cursor position */ + wrefresh(dialog); + } + break; + case '0': /* Beginning of line */ + case 'H': /* Scroll left */ + case 'h': + case KEY_LEFT: + if (hscroll > 0) { + if (key == '0') + hscroll = 0; + else + hscroll--; + /* Reprint current page to scroll horizontally */ + back_lines(page_length); + print_page(text, height-4, width-2); + wmove(dialog, cur_y, cur_x); /* Restore cursor position */ + wrefresh(dialog); + } + break; + case 'L': /* Scroll right */ + case 'l': + case KEY_RIGHT: + if (hscroll < MAX_LEN) { + hscroll++; + /* Reprint current page to scroll horizontally */ + back_lines(page_length); + print_page(text, height-4, width-2); + wmove(dialog, cur_y, cur_x); /* Restore cursor position */ + wrefresh(dialog); + } + break; + case '/': /* Forward search */ + case 'n': /* Repeat forward search */ + case '?': /* Backward search */ + case 'N': /* Repeat backward search */ + /* set search direction */ + dir = (key == '/' || key == 'n') ? 1 : 0; + if (dir ? !end_reached : !begin_reached) { + if (key == 'n' || key == 'N') { + if (search_term[0] == '\0') { /* No search term yet */ + fprintf(stderr, "\a"); /* beep */ + break; + } + } + else /* Get search term from user */ + if (get_search_term(text, search_term, height-4, width-2) == -1) { + /* ESC pressed in get_search_term(). Reprint page to clear box */ + wattrset(text, dialog_attr); + back_lines(page_length); + print_page(text, height-4, width-2); + wmove(dialog, cur_y, cur_x); /* Restore cursor position */ + wrefresh(dialog); + break; + } + /* Save variables for restoring in case search term can't be found */ + tempptr = page; + temp = begin_reached; + temp1 = end_reached; + if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) { + endwin(); + fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n"); + exit(-1); + } + fpos -= bytes_read; + /* update 'page' to point to next (previous) line before + forward (backward) searching */ + back_lines(dir ? page_length-1 : page_length+1); + found = NULL; + if (dir) /* Forward search */ + while((found = strstr(get_line(), search_term)) == NULL) { + if (end_reached) + break; + } + else /* Backward search */ + while((found = strstr(get_line(), search_term)) == NULL) { + if (begin_reached) + break; + back_lines(2); + } + if (found == NULL) { /* not found */ + fprintf(stderr, "\a"); /* beep */ + /* Restore program state to that before searching */ + if (lseek(fd, fpos, SEEK_SET) == -1) { + endwin(); + fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n"); + exit(-1); + } + if ((bytes_read = read(fd, buf, BUF_SIZE)) == -1) { + endwin(); + fprintf(stderr, "\nError reading file in dialog_textbox().\n"); + exit(-1); + } + buf[bytes_read] = '\0'; + page = tempptr; + begin_reached = temp; + end_reached = temp1; + /* move 'page' to point to start of current page in order to + re-print current page. Note that 'page' always points to + start of next page, so this is necessary */ + back_lines(page_length); + } + else /* Search term found */ + back_lines(1); + /* Reprint page */ + wattrset(text, dialog_attr); + print_page(text, height-4, width-2); + if (found != NULL) + print_position(dialog, height, width); + wmove(dialog, cur_y, cur_x); /* Restore cursor position */ + wrefresh(dialog); + } + else /* no need to find */ + fprintf(stderr, "\a"); /* beep */ + break; + case ESC: + break; + } + } + + delwin(dialog); + free(buf); + close(fd); + return -1; /* ESC pressed */ +} +/* End of dialog_textbox() */ + + +/* + * Go back 'n' lines in text file. Called by dialog_textbox(). + * 'page' will be updated to point to the desired line in 'buf'. + */ +static void back_lines(int n) +{ + int i, fpos; + + begin_reached = 0; + /* We have to distinguish between end_reached and !end_reached since at end + of file, the line is not ended by a '\n'. The code inside 'if' basically + does a '--page' to move one character backward so as to skip '\n' of the + previous line */ + if (!end_reached) { + /* Either beginning of buffer or beginning of file reached? */ + if (page == buf) { + if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) { + endwin(); + fprintf(stderr, "\nError moving file pointer in back_lines().\n"); + exit(-1); + } + if (fpos > bytes_read) { /* Not beginning of file yet */ + /* We've reached beginning of buffer, but not beginning of file yet, + so read previous part of file into buffer. Note that we only + move backward for BUF_SIZE/2 bytes, but not BUF_SIZE bytes to + avoid re-reading again in print_page() later */ + /* Really possible to move backward BUF_SIZE/2 bytes? */ + if (fpos < BUF_SIZE/2 + bytes_read) { + /* No, move less then */ + if (lseek(fd, 0, SEEK_SET) == -1) { + endwin(); + fprintf(stderr, "\nError moving file pointer in back_lines().\n"); + exit(-1); + } + page = buf + fpos - bytes_read; + } + else { /* Move backward BUF_SIZE/2 bytes */ + if (lseek(fd, -(BUF_SIZE/2 + bytes_read), SEEK_CUR) == -1) { + endwin(); + fprintf(stderr, "\nError moving file pointer in back_lines().\n"); + exit(-1); + } + page = buf + BUF_SIZE/2; + } + if ((bytes_read = read(fd, buf, BUF_SIZE)) == -1) { + endwin(); + fprintf(stderr, "\nError reading file in back_lines().\n"); + exit(-1); + } + buf[bytes_read] = '\0'; + } + else { /* Beginning of file reached */ + begin_reached = 1; + return; + } + } + if (*(--page) != '\n') { /* '--page' here */ + /* Something's wrong... */ + endwin(); + fprintf(stderr, "\nInternal error in back_lines().\n"); + exit(-1); + } + } + + /* Go back 'n' lines */ + for (i = 0; i < n; i++) + do { + if (page == buf) { + if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) { + endwin(); + fprintf(stderr, "\nError moving file pointer in back_lines().\n"); + exit(-1); + } + if (fpos > bytes_read) { + /* Really possible to move backward BUF_SIZE/2 bytes? */ + if (fpos < BUF_SIZE/2 + bytes_read) { + /* No, move less then */ + if (lseek(fd, 0, SEEK_SET) == -1) { + endwin(); + fprintf(stderr, "\nError moving file pointer in back_lines().\n"); + exit(-1); + } + page = buf + fpos - bytes_read; + } + else { /* Move backward BUF_SIZE/2 bytes */ + if (lseek(fd, -(BUF_SIZE/2 + bytes_read), SEEK_CUR) == -1) { + endwin(); + fprintf(stderr, "\nError moving file pointer in back_lines().\n"); + exit(-1); + } + page = buf + BUF_SIZE/2; + } + if ((bytes_read = read(fd, buf, BUF_SIZE)) == -1) { + endwin(); + fprintf(stderr, "\nError reading file in back_lines().\n"); + exit(-1); + } + buf[bytes_read] = '\0'; + } + else { /* Beginning of file reached */ + begin_reached = 1; + return; + } + } + } while (*(--page) != '\n'); + page++; +} +/* End of back_lines() */ + + +/* + * Print a new page of text. Called by dialog_textbox(). + */ +static void print_page(WINDOW *win, int height, int width) +{ + int i, passed_end = 0; + + page_length = 0; + for (i = 0; i < height; i++) { + print_line(win, i, width); + if (!passed_end) + page_length++; + if (end_reached && !passed_end) + passed_end = 1; + } + wnoutrefresh(win); +} +/* End of print_page() */ + + +/* + * Print a new line of text. Called by dialog_textbox() and print_page(). + */ +static void print_line(WINDOW *win, int row, int width) +{ + int i, y, x; + unsigned char *line; + + line = get_line(); + line += MIN(strlen(line),hscroll); /* Scroll horizontally */ + wmove(win, row, 0); /* move cursor to correct line */ + waddch(win,' '); +#ifdef HAVE_NCURSES + waddnstr(win, line, MIN(strlen(line),width-2)); +#else + line[MIN(strlen(line),width-2)] = '\0'; + waddstr(win, line); +#endif + + getyx(win, y, x); + /* Clear 'residue' of previous line */ + for (i = 0; i < width-x; i++) + waddch(win, ' '); +} +/* End of print_line() */ + + +/* + * Return current line of text. Called by dialog_textbox() and print_line(). + * 'page' should point to start of current line before calling, and will be + * updated to point to start of next line. + */ +static unsigned char *get_line(void) +{ + int i = 0, fpos; + static unsigned char line[MAX_LEN+1]; + + end_reached = 0; + while (*page != '\n') { + if (*page == '\0') { /* Either end of file or end of buffer reached */ + if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) { + endwin(); + fprintf(stderr, "\nError moving file pointer in get_line().\n"); + exit(-1); + } + if (fpos < file_size) { /* Not end of file yet */ + /* We've reached end of buffer, but not end of file yet, so read next + part of file into buffer */ + if ((bytes_read = read(fd, buf, BUF_SIZE)) == -1) { + endwin(); + fprintf(stderr, "\nError reading file in get_line().\n"); + exit(-1); + } + buf[bytes_read] = '\0'; + page = buf; + } + else { + if (!end_reached) + end_reached = 1; + break; + } + } + else + if (i < MAX_LEN) + line[i++] = *(page++); + else { + if (i == MAX_LEN) /* Truncate lines longer than MAX_LEN characters */ + line[i++] = '\0'; + page++; + } + } + if (i <= MAX_LEN) + line[i] = '\0'; + if (!end_reached) + page++; /* move pass '\n' */ + + return line; +} +/* End of get_line() */ + + +/* + * Display a dialog box and get the search term from user + */ +static int get_search_term(WINDOW *win, unsigned char *search_term, int height, int width) +{ + int i, x, y, input_x = 0, scroll = 0, key = 0, + box_height = 3, box_width = 30; + + x = (width - box_width)/2; + y = (height - box_height)/2; +#ifdef HAVE_NCURSES + if (use_shadow) + draw_shadow(win, y, x, box_height, box_width); +#endif + draw_box(win, y, x, box_height, box_width, dialog_attr, searchbox_border_attr); + wattrset(win, searchbox_title_attr); + wmove(win, y, x+box_width/2-4); + waddstr(win, " Search "); + + box_width -= 2; + wmove(win, y+1, x+1); + wrefresh(win); + search_term[0] = '\0'; + wattrset(win, searchbox_attr); + while (key != ESC) { + key = wgetch(win); + switch (key) { + case '\n': + if (search_term[0] != '\0') + return 0; + break; + case KEY_BACKSPACE: + if (input_x || scroll) { + if (!input_x) { + scroll = scroll < box_width-1 ? 0 : scroll-(box_width-1); + wmove(win, y+1, x+1); + for (i = 0; i < box_width; i++) + waddch(win, search_term[scroll+input_x+i] ? + search_term[scroll+input_x+i] : ' '); + input_x = strlen(search_term) - scroll; + } + else + input_x--; + search_term[scroll+input_x] = '\0'; + wmove(win, y+1, input_x + x+1); + waddch(win, ' '); + wmove(win, y+1, input_x + x+1); + wrefresh(win); + } + break; + case ESC: + break; + default: + if (isprint(key)) + if (scroll+input_x < MAX_LEN) { + search_term[scroll+input_x] = key; + search_term[scroll+input_x+1] = '\0'; + if (input_x == box_width-1) { + scroll++; + wmove(win, y+1, x+1); + for (i = 0; i < box_width-1; i++) + waddch(win, search_term[scroll+i]); + } + else { + wmove(win, y+1, input_x++ + x+1); + waddch(win, key); + } + wrefresh(win); + } + } + } + + return -1; /* ESC pressed */ +} +/* End of get_search_term() */ + + +/* + * Print current position + */ +static void print_position(WINDOW *win, int height, int width) +{ + int fpos, percent; + + if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) { + endwin(); + fprintf(stderr, "\nError moving file pointer in print_position().\n"); + exit(-1); + } + wattrset(win, position_indicator_attr); + percent = !file_size ? 100 : ((fpos-bytes_read+page-buf)*100)/file_size; + wmove(win, height-3, width-9); + wprintw(win, "(%3d%%)", percent); +} +/* End of print_position() */ diff --git a/gnu/usr.bin/dialog/yesno.c b/gnu/usr.bin/dialog/yesno.c new file mode 100644 index 000000000000..7a9806d9cd79 --- /dev/null +++ b/gnu/usr.bin/dialog/yesno.c @@ -0,0 +1,113 @@ +/* + * yesno.c -- implements the yes/no box + * + * AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include "dialog.h" + + +/* + * Display a dialog box with two buttons - Yes and No + */ +int dialog_yesno(unsigned char *title, unsigned char * prompt, int height, int width) +{ + int i, x, y, key = 0, button = 0; + WINDOW *dialog; + + /* center dialog box on screen */ + x = (COLS - width)/2; + y = (LINES - height)/2; + +#ifdef HAVE_NCURSES + if (use_shadow) + draw_shadow(stdscr, y, x, height, width); +#endif + dialog = newwin(height, width, y, x); + keypad(dialog, TRUE); + + draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr); + wattrset(dialog, border_attr); + wmove(dialog, height-3, 0); + waddch(dialog, ACS_LTEE); + for (i = 0; i < width-2; i++) + waddch(dialog, ACS_HLINE); + wattrset(dialog, dialog_attr); + waddch(dialog, ACS_RTEE); + wmove(dialog, height-2, 1); + for (i = 0; i < width-2; i++) + waddch(dialog, ' '); + + if (title != NULL) { + wattrset(dialog, title_attr); + wmove(dialog, 0, (width - strlen(title))/2 - 1); + waddch(dialog, ' '); + waddstr(dialog, title); + waddch(dialog, ' '); + } + wattrset(dialog, dialog_attr); + print_autowrap(dialog, prompt, width, 1, 3); + + x = width/2-10; + y = height-2; + print_button(dialog, " No ", y, x+13, FALSE); + print_button(dialog, " Yes ", y, x, TRUE); + wrefresh(dialog); + + while (key != ESC) { + key = wgetch(dialog); + switch (key) { + case 'Y': + case 'y': + delwin(dialog); + return 0; + case 'N': + case 'n': + delwin(dialog); + return 1; + case KEY_BTAB: + case TAB: + case KEY_UP: + case KEY_DOWN: + case KEY_LEFT: + case KEY_RIGHT: + if (!button) { + button = 1; /* Indicates "No" button is selected */ + print_button(dialog, " Yes ", y, x, FALSE); + print_button(dialog, " No ", y, x+13, TRUE); + } + else { + button = 0; /* Indicates "Yes" button is selected */ + print_button(dialog, " No ", y, x+13, FALSE); + print_button(dialog, " Yes ", y, x, TRUE); + } + wrefresh(dialog); + break; + case ' ': + case '\n': + delwin(dialog); + return button; + case ESC: + break; + } + } + + delwin(dialog); + return -1; /* ESC pressed */ +} +/* End of dialog_yesno() */