diff options
author | Steve Slaven <bpk@hoopajoo.net> | 2005-03-12 00:27:55 (GMT) |
---|---|---|
committer | Steve Slaven <bpk@hoopajoo.net> | 2005-03-12 00:27:55 (GMT) |
commit | 77b250bfb63a28a8fe8a8da67de7354bce6e61ff (patch) | |
tree | e28f72c18305016c19c608f5fce4432529e7673d | |
parent | 5dfb1906b299bf7c8a1ee3ba5cd1c9ea40648d89 (diff) | |
download | powwow-77b250bfb63a28a8fe8a8da67de7354bce6e61ff.zip powwow-77b250bfb63a28a8fe8a8da67de7354bce6e61ff.tar.gz powwow-77b250bfb63a28a8fe8a8da67de7354bce6e61ff.tar.bz2 |
Initial revisionv1.2.7
-rw-r--r-- | AUTHORS | 0 | ||||
-rw-r--r-- | COPYING | 348 | ||||
-rw-r--r-- | ChangeLog.old | 746 | ||||
-rw-r--r-- | Config.demo | 401 | ||||
-rw-r--r-- | Hacking | 67 | ||||
-rw-r--r-- | INSTALL | 229 | ||||
-rw-r--r-- | Makefile.am | 20 | ||||
-rw-r--r-- | Makefile.in | 658 | ||||
-rw-r--r-- | NEWS | 0 | ||||
-rw-r--r-- | README | 140 | ||||
-rw-r--r-- | README.follow | 18 | ||||
-rw-r--r-- | README.term | 26 | ||||
-rw-r--r-- | TODO | 46 | ||||
-rw-r--r-- | aclocal.m4 | 1020 | ||||
-rw-r--r-- | beam.c | 438 | ||||
-rw-r--r-- | beam.h | 17 | ||||
-rw-r--r-- | catrw.c | 39 | ||||
-rw-r--r-- | cmd.c | 2464 | ||||
-rw-r--r-- | cmd.h | 21 | ||||
-rw-r--r-- | cmd2.c | 1665 | ||||
-rw-r--r-- | cmd2.h | 32 | ||||
-rwxr-xr-x | configure | 5415 | ||||
-rw-r--r-- | configure.in | 49 | ||||
-rw-r--r-- | debian/changelog | 9 | ||||
-rw-r--r-- | debian/control | 12 | ||||
-rwxr-xr-x | debian/rules | 78 | ||||
-rw-r--r-- | defines.h | 367 | ||||
-rwxr-xr-x | depcomp | 464 | ||||
-rw-r--r-- | edit.c | 886 | ||||
-rw-r--r-- | edit.h | 75 | ||||
-rw-r--r-- | eval.c | 1450 | ||||
-rw-r--r-- | eval.h | 58 | ||||
-rw-r--r-- | follow.c | 166 | ||||
-rwxr-xr-x | install-sh | 294 | ||||
-rw-r--r-- | list.c | 679 | ||||
-rw-r--r-- | list.h | 47 | ||||
-rw-r--r-- | log.c | 322 | ||||
-rw-r--r-- | log.h | 22 | ||||
-rw-r--r-- | main.c | 1995 | ||||
-rw-r--r-- | main.h | 117 | ||||
-rw-r--r-- | map.c | 193 | ||||
-rw-r--r-- | map.h | 15 | ||||
-rwxr-xr-x | missing | 336 | ||||
-rwxr-xr-x | mkinstalldirs | 111 | ||||
-rw-r--r-- | movie.c | 93 | ||||
-rw-r--r-- | muc.c | 298 | ||||
-rw-r--r-- | plugtest.c | 18 | ||||
-rw-r--r-- | powwow.6 | 115 | ||||
-rw-r--r-- | powwow.doc | 2152 | ||||
-rw-r--r-- | powwow.help | 553 | ||||
-rw-r--r-- | ptr.c | 578 | ||||
-rw-r--r-- | ptr.h | 68 | ||||
-rw-r--r-- | tcp.c | 1022 | ||||
-rw-r--r-- | tcp.h | 78 | ||||
-rw-r--r-- | tty.c | 774 | ||||
-rw-r--r-- | tty.h | 52 | ||||
-rw-r--r-- | utils.c | 1279 | ||||
-rw-r--r-- | utils.h | 48 |
58 files changed, 28683 insertions, 0 deletions
@@ -0,0 +1,348 @@ + + The GNU General Public License (GPL) below is copyrighted by the + Free Software Foundation, but the instance of code that it refers to + (the program powwow) is copyrighted by me and others who actually wrote it. + + Massimiliano Ghilardi + +------------------------------------------------------------------------------- + + 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. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + 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. + + <signature of Ty Coon>, 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/ChangeLog.old b/ChangeLog.old new file mode 100644 index 0000000..d8a83e0 --- /dev/null +++ b/ChangeLog.old @@ -0,0 +1,746 @@ +2004-07-01 12:05 bpk + + * main.c: Bug/enhancement fix, # followed by nothing is now + ignored, would be nice to kill to end of line though + +2004-07-01 10:54 bpk + + * Makefile, configure.in, utils.c: Added multiline support for + reading from files, using \ at end of line + +2004-07-01 10:52 bpk + + * Makefile, Makefile.am, cmd.c, cmd.h, main.c, plugtest.c: Added + #module support and a test plugin + +2004-07-01 10:46 bpk + + * Makefile.am, aclocal.m4, configure.in, muc.c: Addec muc movie + player and autoconf support + +2004-07-01 10:42 bpk + + * Initial import of stock powwow 1.2.5 + +Changes from 1.2.4 to 1.2.5 (Massimiliano Ghilardi, ...) 21 Jan 2002 + * Added append-mode to #capture: use #capture >file-name + * Cleaned #spawned commands interface: text they print on + standard output *MUST* terminate with a newline ('\n') + in order for powwow to execute it. + * Fixed missing #include <time.h> in main.h. + * Fixed broken matching of #mark patterns starting with $ + * Added the following user-contributed patches: + * Put also 1-char lines into history; + * Do not capture/movie data coming from spawned commands; + * Fixed a bug in command parser. + +Changes from 1.2.3 to 1.2.4 (Massimiliano Ghilardi) 24 May 2000 + * Added support for IAC GA as end-of-prompt marker. + * Added #request [prompt][editor][all] + * Fixed missing/slow prompt redrawing under some circumstances + if #isprompt <number> was used. + +Changes from 1.2.2 to 1.2.3 (Massimiliano Ghilardi) 18 Jan 2000 + * Fixed `#spawn' command that was completely screwed up. + Also fixed CTRL-C not to kill spawned commands. + * Sending/receiving data to/from spawned commands erased the prompt + instead of reprinting it. Fixed. + (If you don't like powwow to show the prompt before executing + lines from spawned commands, set #option +compact) + +Changes from 1.2.1 to 1.2.2 (Massimiliano Ghilardi) 10 May 1999 + * Fixed `#delim custom' to accept whatever character as delimiters. + Previously stopped before the first word-delimiting char (argh!) + * Fixed screen corruption when doing some editing functions + (&del-word-right, &del-word-left, &complete-word, &complete-line, + parentheses flashing) while data comes from the MUD. + * Fixed a line redrawing bug when inserting chars on terminals + with VT100-like wrapglitch. + * Fixed SEGFAULT on #send, #emulate, #exe of a numeric expression. + * Fixed stupid SEGFAULT when cancelling an editing session. + * Fixed sending/receiving latin-1 '\377' (ASCII char 255) as IAC IAC + to conform telnet protocol, both directly and inside MPI messages. + * Fixed matching #actions, #prompts and #marks on MUD data splitted + into multiple fragments. + * Fixed line length calculation when receiving '\r' in the middle + of a line. + * Fixed extra prompt redrawing in #option +compact mode. + * Added #option sendsize and #option autoclear. + Changed default not to send window size upon connecting. + (if the MUD asks it, the window size is sent anyway) + Use #option +sendsize to automatically send it when you connect. + * Added command #rawsend. + * Removed bits of ANSI code giving problems + with really picky non-ANSI compilers + +Changes from 1.2.0 to 1.2.1 (Massimiliano Ghilardi) 20 Nov 1998 + * Fixed a typo in Makefile. + * Reversed order of saved #history lines. + * Fixed out-of-bound array accesses in tcp_find() and tcp_show() + which could give SEGFAULT on #connect, #snoop and #zap. + * Fixed buggy loop in saving #history in definition file that could + create a huge temporary file, filling the filesystem. + * Fixed sporadic SEGFAULT when hitting backspace and some other + editing keys. + * Math operator `?' could freeze due to buggy code. + Systems providing GNU memmem() didn't experience the problem + as it was used instead of my replacement code. + * Enhanced support for terminals with VT100-like wrapglitch: + on them, the rightmost character of every line is used too. + * Fixed wrapping in #printing strings containing ASCII chars > 127 + when #option wrap is on. + * Fixed incorrect drawing of prompt and command line under some + circumstances. + * Fixed wrong wrapping of lines immediately after the prompt + in #option +wrap mode. + * Removed extra newlines sent after each line in `#send <filename' + and `send !command'. + * Fixed a few off-by-one errors causing corruption in #movie/#capture + and (reprint) buffers. + * Powwow now discards all \r received immediately before or after \n, + to avoid troubles when strange data comes just before the prompt. + * Changed MPI key to `unsigned int' because MUME uses a 32 bit + unsigned value for it. + * Cleaned up remote file editing not to leave stale files in /tmp. + * Cleaned up multiple connections support: + Fixed spurious `#too many open connections' errors. + Fixed prompt drawing glitches when getting data from subsidiary + connections. + +Changes from 1.1.7 to 1.2.0 (Massimiliano Ghilardi) 05 Oct 1998 + * Copyright change. Powwow is now GPL-ed. + * Version number bump. I hope there aren't many bugs left. + If you are coming from 1.0.x versions, read this file and powwow.doc + carefully, many things have changed! + * Fixed double-newline printing after each line if #option +wrap + was set. + * Suppressed useless reprinting of files sent back to MUD + using MUME remote editing protocol. + * Updated a few details in docs. + * Some old compilers choked on bits of ANSI code. Fixed. + * Fixed extra newline after prompt in #movie and #capture + when #setvar buffer is not zero. + * Fixed extra \r at beginning of a line under rare circumstances. + * #delim now unescapes the custom delimeters. + * Added missing close() when remote host closes connection. + * Rewrote the code to merge lines received in two (or more) fragments. + * Added `#help warranty' and `#help copyright' to conform GPL :-/ + +Changes from 1.1.6 to 1.1.7 (Massimiliano Ghilardi) 15 Sep 1998 + * Changed meaning and effect of #prompt and #isprompt. + If you used them, re-read their docs in powwow.doc! + * Alias names containing spaces are now rejected too. + Relaxed rules a little, unbalanced () {} or "" + now just print a warning instead of causing an error. + * Added #option reprint. + * Old #prompts were not removed on #load. fixed. + * Fixed SEGFAULT when chaining very long strings: + #("foo..." + "bar...") + * Fixed small compiling problems on some platforms. + * Fixed an off-by-one error in math operator >: + * Fixed math operator `=' bug on copying empty strings. + * Fixed a crashy bug in #reset var. + * Fixed some quirks in unescaping strings: + ending backslashes caused SEGFAULT, + sequences like \\\``` were unescaped incorrectly. + * Fixed incorrect code in #mark and #action that + mismatched patterns containing two or more wildcards. + +Changes from 1.1.5 to 1.1.6 (Massimiliano Ghilardi) 03 Sep 1998 + * Added circular backbuffer for #capture and #movie. + Can be enabled/disabled/resized with #setvar buffer. + * Sanitized aliases: powwow now rejects alias names containing + unbalanced special chars ""(){} . Example: + #alias (=#print is illegal, while + #alias "("=#print is ok. + #alias {}=#print is ok, + #alias \\{=#print is ok too as it matches \{ and _not_ { + * Removed a redundant alias unescaping. If #alias foo=\\bar + then `foo' now sends `\bar' instead of `bar'. + * Fixed a compatibility problem when reading #binds of new savefiles + using old versions of powwow. + * Fixed some problems with #var on numbered variables. + * Fixed #internal error, selflookup_sortednode() failed! + that affected 1.1.5 + * Fixed SEGFAULT upon #exe \; (introduced in 1.1.5). + * When getting data from the MUD after a prompt which set #isprompt + the data is now printed as a separate line even if it doesn't start + with a newline. Helps turning things like + * HP:Fine>You hit the wolf's head hard. + into + * HP:Fine> + You hit the wolf's head hard. + Anyway, such data has _always_ been considered separate + from the prompt if it set #isprompt, i.e. #action patterns like + "^You hit the wolf" already worked in the above case. + +Changes from 1.1.4 to 1.1.5 (Massimiliano Ghilardi) 30 Aug 1998 + * Massive code cleanup. + * Finished removing size limits on strings, text lines and variables. + * Renamed `#settimer' as `#setvar timer' and `#lines' as `#setvar lines' + Added `#setvar mem' to set/edit/remove length limit on text/strings. + * Powwow now stops command execution after any error. + * #key now works also with editing keys. + * Added #keyedit command. "#keyedit &prev-line" runs + the editing function `&prev-line' and so on. + * Added "&insert-string <string>" editing function. + * Added #mark ^pattern, which matches only at line start. + * Decreased CPU usage when/after a lot of variables, aliases or marks + are created. + * Added `*' and `*=' math operator for strings. + * Fixed math operators ^^=, ||= and &&= to always return 0 or 1. + * Fixed SEGFAULT when creating more than 100 variables. + (bug introduced in 1.1.0) + * Fixed SEGFAULT when realloc()ing very big strings. + * Fixed memory leaks when running out of memory. + * Fixed escaping/printing of nasty strings like + backslash + control char. + * Fixed some redrawing glitches on very long input lines. + Input lines bigger than the whole window are still not drawn + correctly. Same problem on prompts longer than a line. + * Fixed #prompts to fully work also on prompts received inside + a set of newline-terminated lines. + * Documented #prompt, #capture and #movie to work only for + the main MUD connection + +Changes from 1.1.3 to 1.1.4 (Massimiliano Ghilardi) 23 Jul 1998 + * Renamed `movie_play' to `movie'. Will do the replay if invoked as + `movie_play' and will convert to ASCII if invoked as `movie2ascii' + * Fixed a 1.1.1 bug that could cause a lot of missed binds. + * Finished adding ANSI prototypes. Renamed some files and remixed + some code in the process. + * Removed -DUSE_TERMIO. If you used it, no problem. + If you didn't use it, you must now add -DUSE_SGTTY. + * Fixed a few compiling problems on OSF1 and other systems + with really annoying compilers. + * Fixed missing sig_oneshot on systems without SA_ONESHOT + * Fixed input of chars with high bit set (again). + +Changes from 1.1.2 to 1.1.3 (Massimiliano Ghilardi) 21 Jul 1998 + * Variable names are now expressions too. This means that + @("foo"+"bar") is the variable @foobar. + * Added `just in time' substitution: ${varname} @{varname} and #{expr} + Not yet implemented for regexp patterns, sorry. + This introduces a subtle incompatibility with older versions, + as now also text coming from $n substitution gets unescaped. + Sorry again. (see powwow.doc for details). + * #action and #prompt did not work when using an expression + as pattern. Now fixed. + * Fixed small bug in anonymous actions. Someone still using them? + * powwow_help renamed powwow.help + * Fixed a bug in #alias: $1..$9 all contained the first word ($1) + * Fixed math operators . : .? :? .< .> <. >. :< :> <: >: which + segfaulted on empty strings (bug introduced in 1.1.0) + * Made SIGINT signal handler non-permanent to allow interrupting + system calls like connect(). Partially reverses the change in 0.9.3 + * Undone a change Gustav made in 0.9.3: now #connect with no args + always lists the open connections. To open a new connection you must + give at least one argument, for example #connect main. + * Changed edit function &redraw-line not to clear prompt. + Use &redraw-line-noprompt to get the old behaviour. + * Added #movie command to record all output from the MUD + and local commands to a file, adding timestamps to allow replay + at correct speed. Also added `movie_play' standalone program + to actually do the replay. + +Changes from 1.1.1 to 1.1.2 (Massimiliano Ghilardi) 16 Jun 1998 + * The wildcard `$' now correctly matches single words only + both in #actions and in #marks. + It was (again!) matching also multiple words like `&' + * Fixed up attr and noattr math operators, which broke in 1.1.0 + * Added workaround for buggy terminals which create empty lines with + coloured background when using #hilite <whatever> on <colour>. + Must compile with -DBUG_ANSI to enable it. + +Changes from 1.1.0 to 1.1.1 (Massimiliano Ghilardi) 11 Jun 1998 + * Added some changes from 1.0.1 that didn't go in 1.1.0. + The 1.0.x and the 1.1.x trees are indipendent... + * Wrote a memmem() replacement for systems that don't have it. + * Decreased CPU usage when receiving lots of text from the terminal + (for example using cut-n-paste) + * Continued adding ANSI prototypes. + +Changes from 1.0.0 to 1.1.0 (Massimiliano Ghilardi) 20 May 1998 + * Splitted 1.0.x and 1.1.x source trees. + * Started adding ANSI function prototypes. + Old K&R compilers still work. + * Removed all size limits in all strings, text lines and variables. + Also allowed '\0' (ASCII zero) in strings. + It was a _huge_ task! Probably messed up all and everything. + * Side effect of the above: lines of arbitrary length received from + the MUD should now work perfectly (at least as long as you have + enough memory) + +Changes from 1.0.0 to 1.0.1 (Massimiliano Ghilardi) 18 May 1998 + * Changed name of some files (Changelog, Hacking, Compile.how, + Config.demo) + * Fixed #capture and #record to save text from main connection only. + * Fixed a buffer overrun in $last_line when receiving lines longer + than 1024 chars. Hopefully lines up to 4095 chars will now work. + * Fixed message "Creating %s" when creating a new definition file. + * Added `catrw' standalone mini-program for splitting powwow output + in multiple windows (quick tutorial in powwow.doc, section #write) + * Added #rebindall and #rebindALL + +Changes from 0.9.9 to 1.0.0 (Massimiliano Ghilardi) 13 May 1998 + * Disabled NAGLE for tcp connections (set TCP_NODELAY option) + which should hopefully increase performance during lossy conditions + (idea and code contributed by Finne Arne Gangstad) + * Cleaned up error handling. Powwow tries really hard to report + any system call error, quitting only when there is really no hope. + Anyway, if you get a '#system call error' message, you should + seriously consider quitting as soon as possible since either + the connection is messed up or your system is running + out of resources. + * Removed extra newline after prompt bug when in #option -compact mode, + introduced in 0.9.7 + * Fixed $last_line to contain last non-empty line from the MUD. + * Updated config.demo with definitions for time-inside-prompt + and other things. + +Changes from 0.9.8 to 0.9.9 (Massimiliano Ghilardi) 12 May 1998 + * Changed rx.h to regex.h in includes + * Fixed behaviour on prompts and lines received in multiple packets: + 0.9.7 and 0.9.8 sometimes print garbage. + * Added some flush()es in the code to cope with the new + terminal I/O buffering. + +Changes from 0.9.7 to 0.9.8 (Massimiliano Ghilardi) 11 May 1998 + * Fixed compile problems on AIX (got out of sync). + * Fixed a stupid bug that caused all actions to be regexp + (introduced in 0.9.7) + * Introduced a more efficient terminal I/O buffering. + +Changes from 0.9.6 to 0.9.7 (Massimiliano Ghilardi) 11 May 1998 + * Increased stability when receiving extremely long lines (>1024 bytes) + The fix is only partial, powwow can still crash on lines slightly + shorter than 4096 bytes when a lot of #marks are used. + * Cleaned up the names of various #defines + In particular, USETERMIO is now USE_TERMIO and + TELNETBUG is now BUG_TELNET + * Added #option autoprint, to automatically print lines matched + by #actions. + * Added #spawn command. + * Added #prompt command. Just like #action, but matches both on + prompts and on normal text. + * #actions now work differently on prompts: + prompts are not matched immediately against #actions, + but only after a \n arrives from the MUD, just in case they are + actually normal lines received in multiple packets and not prompts. + + Thanks to the this change, powwow behaves better on lines received + in two (or more) packets. + See the file powwow.doc, section `#prompt' for the gory details. + +Changes from 0.9.5 to 0.9.6 + (Gustav Hållberg, Massimiliano Ghilardi) 16 Oct 1997 + * Fixed a nasty security hole in MPI messages + * Fixed handling of \; at the end of a command + * Fixed some other problems: + short messages from MUD could interfere with remote editing, + #bind escape sequences containing \0 were incorrectly printed/saved + +Changes from 0.9.4 to 0.9.5 + (Gustav Hållberg, Massimiliano Ghilardi) 18 Sep 1997 + * Continued code cleanup + * Allowed aliases starting with `#' + * Removed #speedwalk, #info, #echo, #keyecho, #compact and #debug + and turned them into #options: `#option echo' and so on. + For compatibility, `#echo' is aliased to `#option echo' and so on. + * Fixed a dangerous bug making cursor jump to start of typed text + when receiving a line that wraps. The bug appeared in 0.9.4, + so blame Gustav ;) + * Fixed an old bug making powwow sometimes miss a bind + * Made the command from a bound key appear with `#hilite' setting + * Made a DEFAULT_HELP_DIR define in powwow.c + * Changed to from ' ' to ` ' in some messages + +Changes from 0.9.3 to 0.9.4 (Massimiliano Ghilardi) 04 Sep 1997 + * Included all the huge changes made by Gustav Hållberg: + I really have no time to double-check them all. + If something works in 0.9.2 but is broken in 0.9.4, + you know who to bother :) + * Small esthetic changes in the source, no effects on executable + * Changed identifier for regexp #actions from ']' to '%' + +Changes from 0.9.2 to 0.9.3 (Gustav Hållberg) 11 Aug 1997 + * Fixed so packets ending with \r*\n\r* set promptstr to "" + * Made all signal handlers permanent (sig_permanent) + * Debugged and reinstalled #option (it was commented out for some + obscure reason (Massimiliano: I never finished it...)), + allowing storage of command history and word + completions in the savefile. Added the 'exit' option to allow + powwow to autoexit when the last connection closes + * #echo, #info, #wrap and #debug now get saved in the savefile + * Made repetitive use of &complete-word and &complete-line cycle + through possible completions + * Made a memory-safe strdup (called str_dup) + * When starting a child viewer/editor, that process' TITLE + environment variable is set to something appropriate (?) + * Regular expressions (Extended POSIX regexp) + available for actions; uses GNU rx. + * Actions with label "" forbidden + * Added the #delim command to change word delimeter mode + * Whenever main_conn changes permanently, linemode is set to 0 and + promptstr to "" + * Fixed a crashy bug in the >: operator + * Fixed the notorious extra-space-on-insert bug (both 'ic' and 'im' + shall NOT be sent if you want to insert something) and a VT100 + mode bug while I was feeling creative + * Made the local editing protocol respect prompts (i.e. they get + rewritten after protocol messages are shown). After texts are sent + back to the mud, the output buffer is flushed (no more pressing + ENTER after you've stopped editing!) + * Fixed a few bugs in #mark; pattern "&" doesn't crash anymore. + Patterns with consecutive wildcards never worked, so I forbade them. + It could be implemented, but I hardly think it's worth it + * Added the ANSIBUG compiler directive to fix the bug in some terms + that show new lines in the current output attrib (screws #mark e.g.) + * Made '#connect' without parameters try to open a connection + titled 'main' to 'hostname' (if specified) if no conns are open. + The initstr from #init will be used in this case + * Added &transpose-words, &upcase-word and &downcase-word (defaults + to M-t, M-u and M-l). Repetition of the latter two changes case + of the whole line + * Changed default key names to be more emacs-like (C-b, Ret etc) + * Made #host get written to the savefile iff *hostname != 0, and + if powwow is started as 'powwow filename', without any #host in + the file, #init is ran immediately + * Fixed a bug in cmd_print() that didn't cope with $0 not being set + * Allowed \0 to be part of a bound key's escape sequence. New format + for #bind allows octal \012 be part of the string representation + of the esc seq (chars with high bit set get saved in octal now) + * Made permanent variables $last_line and $prompt + * Made "#var" without arguments list all defined named variables + +Changes from 0.9.1 to 0.9.2 (Massimiliano Ghilardi) 04 Jun 1997 + * Added #keyecho command toggle echo of bound keys. + Previously, this was controlled by the generic #echo command. + * CTRL-C can now safely interrupt blocking commands like + #connect and #bind. + * POWWOWDIR is now used correctly in all cases: + not only when starting powwow with a filename but also when using + #load, #save or #file + * Changed #file syntax. Now you need = before the save-file. + Putting = alone undefines the save-file and disables autosave + when you quit. + * Cleaned up naming conventions: 'session' means editing session + while 'connection' means remote host connection. + * Fixed handling of 8 bit chars typed from keyboard + * Fixed '#reset bind' which was not reloading cursor binds + * Fixed remote host name spelling in files generated by #save. + * Fixed a bug that caused powwow to crash when failing to + connect to a mud. + +Changes from 0.9.0 to 0.9.1 (Massimiliano Ghilardi) 31 Apr 1997 + * New connections opened with #connect are set as main connection. + You will have to switch back manually if you need it. + * Cleaned up multiple connection support. Better error handling. + * Cleaned up TELNETBUG support. I did not use it recently, + and was out of sync. + * Enhanced #bind syntax: now you can specify control codes + sent by your keyboard directly from the command line. + As a side effect, #exe <file now works also on files created + with #save + * Added #rebind command. Changes the control codes associated + to a key binding without changing its name or its effect. + * Added #quit command. + +Changes from 0.8.6 to 0.9.0 (Massimiliano Ghilardi) 29 Apr 1997 + * Added FreeBSD support in make_it (thanks to Jaako Knuutila) + * Cleaned up terminal interface. + * #save and #load now accept a filename as argument + * Handle SIGQUIT as SIGINT: use to stop long or infinite loops + * Now can switch main connection on the fly with ##<connection-name> + * Allow powwow #commands also on subsidiary connections + +Changes from 0.8.5 to 0.8.6 (Paolo Gatti, Massimiliano Ghilardi) 28 Apr 1997 + * Finally and definitively changed the name to powwow. + Previously, sometimes the program was referred to as pow-wow + and sometimes as powwow, generating confusion. + * Partial port of powwow to AmigaDOS. Incomplete, will NOT compile. + Paolo abandoned the project, so maybe it will just never compile. + * Fixed a bug causing extra new-lines on screen when powwow received + strange data sequences like ASCII codes 10 13 + (on DOS, new-line is 13 10, while on UN*X is 10 only) + * Fixed a bug in #mark not matching correctly the wildcard $ + * Powwow crashed #loading files containing empty lines. Fixed + +Changes from 0.8.4 to 0.8.5 (Massimiliano Ghilardi) + * Fixed a bug introduced by updating files from cancan 2.6.0b sources + (happened in version 0.8.3): powwow was sendind TWO new-line chars + instead of one immediately after every password. + +Changes from 0.8.3 to 0.8.4 (Massimiliano Ghilardi) + * Fixed (I hope definitively) an ancient bug: + some lines were sometimes printed twice or not printed at all. + It is still the bug that appeared in version 0.4... + The bug was almost fixed in version 0.8b but reintroduced in 0.8.3 + +Changes from 0.8b to 0.8.3 (Massimiliano Ghilardi) + * Slightly changed version numbering (0.8.3 instead of 0.8c) + * #save and #load are now safe even in case of errors + (example: `disk full') + * hitting a #bind-ed key now echoes the corresponding command + only if #echo is on + * updated term.c (terminal handling code) and tel.c (telnet code) + with files from cancan 2.6.0b (yes, I shamelessly copied them) + No external changes anyway (unless I introduced some bugs) + note: beam.c NOT updated/copied + * 'follow' standalone mini-program added (see README.follow) + * #key is now explicitly stated not to support editing keys. + They cannot be added cleanly without rewriting the line-editing code + from scratch ('#key up' and '#key return' give the biggest problems) + and I don't have the time for that right now + * blink attribute added + * Now can use multiple attributes in #mark, #hilite, #color + example: #mark *An Orc*=inverse bold blue on red + Note: bold, blink, underline and inverse must appear BEFORE colors + * fixed some bugs: + * changed "VERSION" to "POWWOW_VERSION" in powwow.c. + It seems some compilers use VERSION for internal purposes... + * #wrap mode was discarding lines containing only escape sequences + (example: color codes coming from the MUD) + * #hilite was restoring hilight attributes after EVERY line + coming from the MUD + * self-recursive aliases were causing crash after 100 loops instead + of trapping error and reporting '#error: stack overflow' + (not always, and not on all OS). Now they are completely safe. + Note: they still eat 1MB of memory (10K per loop - released + immediately after) + +Changes from 0.8a to 0.8b (Massimiliano Ghilardi) + * hexadecimal numbers added (and in any other base) + can be used only from calculator, prefix is # + * '#write' command added + * fixed a bug with #nice affecting #load + now #load places actions/marks in memory in the same order as + config file, indipendently from #nice value. + Also, default #nice changes from 1 (top) to 0 (bottom) + * fixed a bug in #save that sometimes caused crashes and destroyed + config file + * now word completion (issued with TAB key) checks + word completion list _before_ built-in commands + +Changes from 0.8 to 0.8a (Massimiliano Ghilardi) + * remind me NEVER to work on Sunday, because I filled version 0.8 with + these bugs (now fixed): + - some debugging stuff was not deleted from official version + - deleting a named variable could cause a crash + - creating a named variable was giving a message even while reading + a definition file + - #settimer was not working due to a change in version 0.8 + - forgot to say that #map variable was added + * #rand, #map and #timer variables renamed rand, map and timer + (removed the #) - sorry for the change but it was necessary. + * removed limit of 50 named variables of each kind (numeric and string) + now the only limit is the memory available + +Changes from 0.7b to 0.8 (Massimiliano Ghilardi) + * #mark now accepts wildcards ($ for a single word, & for a string) + * named variables are now supported + * #assign renamed #var (I never liked the name 'assign' ...) + also, #var can be used to delete variables from memory + * #nice command added. It sets/shows priority of new actions/marks + +Changes from 0.7a to 0.7b (Finn Arne Gangstad) + * make_it now also works for sunos 5.x, irix 5.x and hpux 9.x + +Changes from 0.7 to 0.7a (Massimiliano Ghilardi) + * fixed a _HUGE_ hole in security: $n in actions was matching also ; + (but not spaces) so robotic actions gave a chance to other players + to force you (*AAARGH*) + * startup changed: now powwow does not clear screen when executed, + but jumps to the end of screen (this avoids mess in the first lines + you get from the mud) + +Changes from 0.6d to 0.7 (Massimiliano Ghilardi) + * finally fixed the unpleasant bug of auto-wrap making confusion when + receiving lines that contain escape sequences + (the fix in 0.6d was far from satisfactory) + * high-intensity colours added (for the terminals that support them) + * #assign can be used to put the contents of a variable on input line + * number of global variables raised to 50, max lenght of string + variables raised to 512 bytes + * #settimer command added, '#time' variable changed into '#timer' + * fixed a bug: math operator >= was wrong, worked as <= + +Changes from 0.6c to 0.6d (Massimiliano Ghilardi) + * break key now is also used to stop command-parsing. Useful to stop + long or infinite loops without exiting from powwow. + * #stop command added. It disables all active delayed commands. + * #mark now works also with prompts (was not implemented before) + * fixed an ancient bug with #action not working on lines splitted into + multiple data packets by telnet. + * fixed two other ancient bugs: + #mark not working on auto-wrapped words + and auto-wrap making confusion when receiving lines that contain + escape sequences (only partially fixed to be honest) + * Now the unescaping is performed ALSO on quoted strings, when powwow + evaluates them. Thus there might be to update your definition file + if it contains escapes placed in strings. + +Changes from 0.6b to 0.6c (Massimiliano Ghilardi) + * If you have problems with #rand, random() and srandom() (typically + your compiler is unable to find the functions) you can define + NO_RANDOM at compile time. (temporary solution) + * Now also editing keys can be redefined + * #assign command added (same syntax of #print, #send and #exe) + * Now you can specify start and end line of a file or output of Bourne + shell command when using #print, #send, #exe, #emulate or #assign + * #debug command added (try it in test mode...) + * Now #echo, #info, #speedwalk and #debug also accept 'on' or 'off' + +Changes from 0.6 to 0.6b (Massimiliano Ghilardi) + * #emulate command added (same syntax of #print, #send and #exe) + * now also prompts can be intercepted by #actions + (but cannot be 'gagged') + * powwow can run in test-mode without being connected to a MUD + +Changes from 0.5 to 0.6 (Massimiliano Ghilardi) + * more debug work + * #exe, #send and #print extended to use shell commands and files + Also, #send replaces #read + * #time variable added + * #rand function added + * #connect now supports a different remote host for each connection + (i.e. you can now play on different MUDs with the same invocation + of powwow) + + Ideas coming from Cancan 2.5.1c and implemented on powwow 0.6: + + * output to the remote host is buffered up and sent all at once in the + main loop, to reduce the number of network packets. Long aliases + might benefit from this, as would repeated commands (#10 buy bread). + * #help now works on commands. A help file is needed and provided. + * new command: #record, records lines you type in a file + * source changed so path for helpfile is taken from environment + variable POWWOWHELP (if this variable is not defined, powwow looks + in current directory) + * to print the message of the day, must define MOTDFILE in compiling + with the name (and complete path) of the file containing the message + * Now compiles on BSD/386 as well, automatically detected by make_it + +Changes from 0.4 to 0.5 (Massimiliano Ghilardi) + * Heavy debug work, since 0.4 was an alpha version + (it is not a good idea to place here the huge list of bugs fixed...) + * added #history to list/execute commands in history + Note: #history commands are not placed in history... + * now internal commands can be abbreviated, for example #al can be used + istead of #alias. However, internal commands are still completed + using TAB + +Changes from Cancan 2.5.0b to powwow 0.4 (Massimiliano Ghilardi) + * Inline calculator, with both global and local variables, and C-like + syntax + * added commands #(), #print, #send, #exe to use inline calculator + * added commands #if-#else, #for and #while. + * added #key, #save, #load, #save, #lines, #info, #echo, #compact, + #net, #clock, #time + * added #in and #at to define/edit delayed commands + * #mark and all attrib-related commands now accept also the attribute + 'none' + * #marks and #actions now are not automatically sorted (to sort them, + define SORT in compiling). #aliases and #binds instead are always + sorted. + * #aliases can be self-recursive now (it is potentially dangerous, + powwow will not enter a very long - but not infinite - loop) + * Must not escape ';' anymore to place multiple commands in #alias, + #action or #bind. Instead, multiple commands must be surrounded by + braces, { and } + * #action changed syntax (not need double quotes anymore, but need one + of > < + - = before label) See powwow.doc for details + Lines matched with #action are not printed on screen automatically, + must use a #print to echo them + * #gag is suppressed (not needed anymore), and #add is now a command + * Escaping technique changed. Now unescaping '\\\#' gives '\\#' (i.e. + remove one \ each time), and you can also escape \, in this way: + \` gives \ alone, \`` gives \` and so on. So for example, if you + want to place a \ at the end of an #action pattern, you must write + \` , to avoid escaping the = after the pattern + * Some bugs of Cancan fixed (small things, expecially wrapping) + +Changes from 2.5.0a to 2.5.0b (Finn Arne Gangstad) + * Fixed bug with client aborting when window was resized. + +Changes from 2.5.0 to 2.5.0a (Finn Arne Gangstad) + * Various tweaks to make it compile on most systems. + +Changes from 2.4.4 to 2.5.0 (Mattias Engdegard) + * the length of the prompt is now correctly calculated + even if it contains escape sequences (for muds with coloured prompt). + * built-in commands are always completed with tab and aren't stored in + the word list + * #hilite and #mark now accept general attributes: ansi colours and + bold, underline, inverse. + * the #action command has changed syntax; now double quotes are + required around the pattern, but they can be named. Actions can be + turned on and off. + * the keydefs list contains all keyboard bindings. The #bind command + can define new keys. + * the #alias, #action, #bind and #mark commands can now put a + definition line in the input buffer for easy editing. + The keys M-p and M-n are no longer used. + * some new files, new source module discipline with external + declarations only in header files. + * added the file `Hacking' with some advice. + * mapping functions cleaned up. #map now displays ssss as 4s. + * the definition file is tagged with a file version, to make it easier + to recognize older save formats. + * cancan now displays a motd file whose location is set at compile + time (see Makefile). + * define TELNETBUG to work around an NCSA telnet 2.2 colour bug. + #stdcolour can be used to set the background colour if TELNETBUG is + defined. + +Changes from 2.4.3 to 2.4.4 (David Gay) + * telnet window size option supported + +Changes from 2.4.2 to 2.4.3 + * added term support + * added #hilite to hilite user entered text + * added #mark and #unmark to mark special keywords... + * changed #identify to allow it to send alias' or commands to the + mud when beginning/ending an editing session. + * changes the Makefile a bit to support termcancan + +Changes from 2.4.1 to 2.4.2 + * Added multiple-session support with following # commands: + '#connect', '#zap', '#snoop', '##' + * Added numeric keypad movement, keypad sends commands + n,e,s,w,u,d and exits.. (not on all systems) + * Easier editing of actions with meta-p and meta-n (not on all systems) + * Changed the 'make_it' script a bit, so that it echoes the make + command it executes. + +Changes from 2.4.1 to 2.4.1b + * Improved modularity of source, new files cmd.c, cmd.h + +Changes from 2.4.0 to 2.4.1 + * Changed & in actions to match a single word for backward + compatibility. &0..&9 still match multi-worded text. + * Now compiles on HP-UX (at least HP-UX 9.01A ) + * Included a 'make_it' script that automatically compiles cancan for + Linux, IRIX, AIX, ULTRIX, DolphinOS, SunOS and HP-UX sytems. + +Changes from 2.3.6 to 2.4.0 + * Extended param substitution for & to &0..&9. + * Added '&&' syntax for delayed param substitution. + * Added '#init' command to send initialization string on connect. + * Added '#speedwalk' to toggle speedwalk on and off. + * Added '#map' with automapping. + * Added '#retrace' to retrace steps. + * Added sorting for alias and action lists, which is disabled if + compiled with -DNOSORT. + * Added compile option -DNOSHELL to remove '#!' shell escape function. + +Changes from Cancan 2.3.5 to 2.3.6 + * Fixed a bug with MUME's spinning delay bars and word wrap. + * & can now be escaped. This allows for aliases that create aliases, + and other things. + * Added this change log (not too early) + * Checks the window size after being suspended, in case it was + changed. + * Lines longer than screen width because of invisible spaces and/or + trailing CR:s are not unnecessarily wrapped. + diff --git a/Config.demo b/Config.demo new file mode 100644 index 0000000..7eb537e --- /dev/null +++ b/Config.demo @@ -0,0 +1,401 @@ +#savefile-version 1 +#("We use an old version number to force creation of sane default #binds") + +#init ={#(@oldxp=0);mapend;#option +compact -info -echo} + +#("Connect to MUME") +#host mume.pvv.org 4242 + +#("Some aliases to use labeled #actions") +#alias ac=#action $0 +#alias <=#action <$0 +#alias \==#action =$0 +#alias >=#action >$0 +#alias +=#action +$0 +#alias -=#action -$0 + +#("Some variables") +#(@emergency = 1, @xp = -0) +#($E_col = "bold") +#($Elbereth = "Grima Slinket Crug Camaro") +#($S_col = "inverse") +#($Sauron = "Homie Aridhol Quigley Mournblade ") + +#("Some useful binds -- they all are on numeric keypad") +#alias ?=#history 1 +#alias ??=#history $0 +#bind * ^[Oj=stat +#bind + ^[Ol=open honeycomb +#bind - ^[Om=close honeycomb +#bind . ^[On=sneak +#bind / ^[Oo=! +#bind 0 ^[Op=? +#bind 1 ^[Oq=hide +#bind 2 ^[Or=s +#bind 3 ^[Os=d +#bind 4 ^[Ot=w +#bind 5 ^[Ou=exits +#bind 6 ^[Ov=e +#bind 7 ^[Ow=look +#bind 8 ^[Ox=n +#bind 9 ^[Oy=u + +#alias plusminus={#bind +=open $1;#bind -=close $1} +#action >+close The $1 is open={#print;plusminus $1} +#action >+open2 The $1 seems to be closed={#print;plusminus $1} +#action >+open1 The $1 is closed={#print;plusminus $1} + +#("Bindings for function keys") +#alias HELP=#alias HELP={remove ring;narrate HELP! EMERGENCY TRANSFER! rings off!} +#bind F01 ^[OP=HELP +#alias wi=change wimpy $0 +#alias wq=wi 100 +#alias ww=wi 1000 +#bind F02 ^[OQ=ww +#bind F03 ^[OR=wq +#bind F04 ^[OS=examine +#bind F05 ^[m=now +#bind F06 ^[[17~=#option compact +#bind F07 ^[[18~=listen all +#bind F08 ^[[19~=listen none +#alias ck=change mood berserk +#alias ca=change mood aggressive +#alias cb=change mood brave +#alias cn=change mood normal +#alias cp=chan mood prudent +#alias cw=change mood wimpy +#bind F09 ^[[20~=cw +#bind F10 ^[[21~=ca +#alias pi={remove sword;draw} +#alias sla={sheath;wield sword} +#bind F11 ^[[23~=pi +#bind F12 ^[[24~=sla + +#("Two nice aliases") +#alias ,e=emote leaves east +#alias emsay=emote says '$0' + +#("Teleporting") +#alias ll=cast 'locate life' $0 +#alias tp=cast 'teleport' $0 +#alias portal=cast 'portal' $0 +#alias go={#if (!*\$0:>2) #(\$0+="tp"); #else #if (\$0:>2=="portal") #(\$0+=" u"); #exe (\$0:>2+" "+\$0:1)} + +#alias loc={#var $talias=$1; #action +tkey; ll $2} +#action >tkey Key: '$1'={#print; #action -tkey; #alias ${talias}=go $1 \$0} + +#alias zharlond=go whicewhile $0 +#alias zmichdelv=go sillelega $0 +#alias zbree=go dorwhimile $0 +#alias 1=zHarlond +#alias 2=zMichDelv +#alias 3=zBree + +#("An emote for enchanting weapons") +#alias ench=cast 'enchant weapon' $0 +#alias enchant={, makes a swift gesture and the $0 starts floating in mid air...;EnchSet +;ench $0} +#alias EnchSet={#action $1EnchSucc;#action $1EnchFail;#action $1BackFire} +#action >-BackFire Your spell backfired!={#print;, starts swearing loudly;EnchSet -} +#action >-EnchFail You lost your concentration!={#print;, frowns and exclaims, 'This cannot be! I failed!';EnchSet -} +#action >-EnchSucc $1 glows blue.={#print;, gestures again, and arcane runes flare on the $1!;EnchSet -} + +#("Keep count of game time and also put it in the prompt") + #mark Game time =underline +#("length of a game tick in milliseconds :") + #(@tick = 61500) +#("this is to synchronize") + #action >+clock ^The current time is $1:$2 $3.={#print;#if (\@0=$1*@tick+$2*@tick/60, \$3=="pm" ^^ $1==12) #(\@0+=12*@tick); #settimer (\@0);settick} +#("print time") + #alias time={#if ((\@1=timer%@tick*60/@tick) < 10) #(\$1=":0"); #else #(\$1=":");#print ("Game time "+%(timer/@tick%24)+\$1+%\@1)} +#("manually set time") + #alias now={#if (*\$1) #(\@0=$1*@tick+0$2*@tick/60); #else #if ((\@0=timer-(\@1=timer%@tick)), \@1 >= @tick/2) #(\@0+=@tick); #settimer (\@0)} +#("put time into the prompt. works for MUME.") +#("change to use appropriate patterns for other MUDs") + #prompt %+empty ^[o\\*]>={#isprompt -1; timeprompt} + #prompt %+full ^[o\\*] [^>]*>={#isprompt -1; timeprompt} + #alias timeprompt={#if ((\@1=timer%@tick*60/@tick) < 10) #(\$1=":0"); #else #(\$1=":");#($prompt=$prompt.1+" "+%(timer/@tick%24)+\$1+%\@1+$prompt.>2)} +#("automatically print time at every tick. type `settick' to activate") +#("or change #alias `now' and #action `clock' to run it") + #alias settick=set tick 0 time + #alias set=#exe ("#in $1 ("+%((-timer-1)%@tick+2)+") {"+\$0:>3+";#in $1 ((-timer-1)%@tick+2)}") + +#("Code to help mapping mazes -- keeps track of room number") +#("using binary numbers -- 1 copper == 1, 2 coppers == 0") +#("doesn't work anymore as you now get `six pile of coins' etc. tough luck.") +#alias d1=drop 1 copper +#alias d2=drop 2 copper +#alias m=#for (\@1=$1; \@1; \@1/=2) #if (\@1&1) d1; #else d2 +#alias mapend={- copper-penny;- pile-of-coins;#(@map=0)} +#alias mapstart={+ copper-penny;+ pile-of-coins;#(@map=0);#in map-timeout (-1) {#print ("Room: "+%@map);#(@map=0)}} +#alias mapcount={#(@map*=2, @map+=$1);#in map-timeout (100)} +#action >-pile-of-coins ^A pile of coins=mapcount 0 +#action >-copper-penny ^One miserable copper penny=mapcount 1 + +#("Spells and fight") +#($self = "Cosmos") +#alias self=#($self=$(0)) +#alias k=kill $0 +#alias f=flee +#alias ff=order followers assist ${self} +#alias fw=order followers assist waran +#alias of=order followers $0 +#alias ol=of k lord +#alias on=of k noble +#alias he={#if (!*$(0)) #($(0)=$self);#send ("cast 'heal' "+$(0))} +#alias in={#if (!*$(0)) #($(0)=$self);#send ("cast 'invisibility' "+$(0))} +#alias rp={#if (!*$(0)) #($(0)=$self);#send ("cast 'remove poison' "+$(0))} +#alias sct={#if (!*$(0)) #($(0)=$self);#send ("cast 'sanctuary' "+$(0))} +#alias str={#if (!*$(0)) #($(0)=$self);#send ("cast 'strength' "+$(0))} +#alias ar={#if (!*$(0)) #($(0)=$self);#send ("cast 'armour' "+$(0))} +#alias sspell=#exe ("#alias $1={#if (!*$(0)) #($(0)=$self);#send (\\"cast '"+\$0:>2+"' \\"+$(0))}") +#alias sto=cast 'store' $0 +#alias stb=sto fireball +#alias stl=sto call lightning +#alias stp=sto teleport +#alias stq=sto earthquake +#alias sty=sto colour spray +#alias bd=cast 'block door' $0 +#alias bl=cast 'blindness' $0 +#alias bob=cast 'breath of briskness' +#alias ch=cast 'charm' $0 +#alias cwt=cast 'control weather' $0 +#alias b=cast 'fireball' $0 +#alias j=cast 'lightning bolt' $0 +#alias li=cast 'call lightning' $0 +#alias sl=cast 'sleep' $0 +#alias sle=sl $0 + +#($target = "assassin") +#alias .=$0 ${target} +#alias bl.=bl ${target} +#alias b.=b ${target} +#alias j.=j ${target} +#alias k.=k ${target} +#alias li.=li ${target} +#alias sl.=sl ${target} +#alias blo=bl orc +#alias blt=bl troll +#alias jo=j orc +#alias jt=j troll +#alias ka=k assassin +#alias kw=k wolf + +#alias tr=track $0 +#alias to=tr orc +#alias tt=tr troll +#alias tr.=tr ${target} + +#alias bs=backstab $0 +#alias bs.=bs ${target} +#alias nn=$0 Necromancer + +#("Misc stuff") +#($water = "skin") +#alias dw=drink water +#alias dk=drink ${water} +#alias lk=look in ${water} +#alias po=pour water ${water} +#alias sk=sip ${water} +#alias cv=cast 'create water' $0 +#alias cvk=cv ${water} + +#($pack = "backpack") +#alias gp=get $0 ${pack} +#alias pp=put $0 ${pack} +#alias lp=look in ${pack} + +#($light = "lantern") +#alias hl=wear ${light} +#alias rl=remove ${light} +#alias vl=cover ${light} +#alias ul=uncover ${light} +#alias cl=cast 'create light' $0 +#alias cll=cl ${light} + +#alias lg=look in moneybag +#alias gg=get $1 gold moneybag +#alias pg=put $1 gold moneybag +#alias ggj=get ruby moneybag +#alias pgj=put ruby moneybag + +#alias cf=cast 'create food' +#alias gf=get food +#alias ef=eat food +#alias food={cf;gf;ef} + +#alias bc=#if (*$(1)) butcher $1.corpse; #else butcher corpse +#alias lc=#if (*$(1)) look in $1.corpse; #else look in corpse +#alias ga=#if (*$(1)) get all $1.corpse; #else get all corpse +#alias gc=#if (*$(1)) get coins $1.corpse; #else get coins corpse +#alias gx=#if (*$(2)) get $1 $2.corpse; #else get $1 corpse +#alias xc={hl;gc $0;rl} +#alias gl=get all +#alias glc={get all.coins;get all.copper} +#action >-greed is dead! R.I.P.={#print;gc} + +#alias ldh=#if (*($1)) lead $1.horse; #else lead horse +#alias rdh=#if (*$(1)) ride $0.horse; #else ride horse +#alias ldp=#if (*($1)) lead $1.pony; #else lead pony +#alias rdp=#if (*$(1)) ride $1.pony; #else ride pony +#alias ds=dismount +#action >-Ct ^Clip-clop...the riding horse= +#action >-Cp ^Clip-clop...a pony= +#action >-Cb ^The Horse= +#action >-At ^A riding horse= +#action >-Ap ^A cute and docile pony= +#action >-Ab ^A beautiful horse= + +#alias re=t Alsbreth $0 +#action >+reply ^$1 tells you '={#print;#alias re=t $1 \$0} +#action >-xeval ^$1 tells you 'calc &2'={#print;#alias re=t $1 \$0;if (\$2?";" || \$2?"$" || \$2?"@") {tell $1 *grin*;#()}; #else #send ("t $1 "+%($2))} + +#alias rep={+ report;score} +#action >-report $1 hit, $2 mana and $3 moves.={#print;, has $1 hit, $2 mana and $3 moves.;- report} +#alias rd={#opt +speedwalk;4ensenwdnenne;#opt -speedwalk} +#alias fd={#opt +speedwalk;wsswsuwwdww;#opt -speedwalk} + +#alias lr={look n;look s;look e;look w;look u;look d} +#alias x=#alias $0 +#alias kk=#bind $0 +#alias l=examine $0 +#alias gr=group $0 +#alias le=group ${self} +#alias mm=#mark $0 +#alias sa=#save +#alias se=search $0 +#alias mo=help month +#alias ng=, nods gravely. +#alias nh=, nods happily. +#alias ns=, nods sadly. +#alias p=' open +#alias rf=rem staff +#alias rn=read next +#alias rs=rem stone +#alias rt=rem ticket +#alias sms=, smiles sadly. +#alias ss=spam +#alias fade=emote quickly wraps in his cloak and vanishes. +#alias matz=emote unwraps his cloak and materializes. +#alias fun={fade;$0;matz} +#alias tele={fade;tp $0;matz} +#alias title=chan title the Hungry +#alias tm=t Meryaten $0 +#alias wavall=, waves good-bye to you. +#alias wf=weather fog +#alias wg=weather global +#alias wh=where human +#alias wk={wake;st} +#alias wl=weather local +#alias wr={wake;rest} +#alias grz=na --- === *** C O N G R A T U L A T I O N S !! *** === --- +#alias lin={#lines $0;chan height $0} +#alias lv=na --- === *** L E V E L !! *** === --- +#alias macintosh={#bind ~home ^[OH=eq;#bind ~~home ^[O@=eq;#bind ~F01 ^[OP=#key F01;#bind ~F02 ^[OQ=ww;#bind ~F03 ^[OR=wq;#bind ~F04 ^[OS=examine;#bind ~F05 ^[m=now;#bind ~+ ^[Ok=open patch;#bind ~~F05 ^[[16~=now} + + +#alias listadd=#for (\@0=1; *$$1:\@0 && $$1:\@0!=*13; \@0++) #exe ("#mark "+$$1:\\@0+"="+$$2)} +#alias listclear={#for (\@0=1; *$$1:\@0 && $$1:\@0!=*13; \@0++) #exe ("#mark "+$$1:\\@0+"=");#($$1="")} +#alias elb={listclear Elbereth;#ac +elbereth;t elbereth list} +#alias elblist=#print ("Elf Enemies: "+$Elbereth) +#alias sauronclean={#for (\@0=1; *\$-1:\@0; \@0++) #($-1=$-1:<\\@0<.2+" "+$-1:>(\\@0+1))} +#alias pk={listclear Sauron;#ac +sauron0;#ac +sauron1;t sauron list} +#alias pklist=#print ("PKillers: "+$Sauron) +#action >-elbereth ^Elbereth Gilthoniel tells you 'Elf Enemies: &1'={#($Elbereth=\$1);listadd -5 -6;#ac -elbereth;#print} +#action >-sauron2 ^ &1more to come.'={#($Sauron+=$-1=\$1<.3+",");sauronclean;#ac -sauron2;listadd -3 -4;#($Sauron+=$-1, $-1="");#print} +#action >-sauron1 ^Sauron tells you 'My Envoys: &1={#($Sauron=$-1=\$1<.2+",");sauronclean;#ac -sauron0;#ac -sauron1;#ac +sauron2;listadd -3 -4;#($Sauron=$-1);#print} +#action >-sauron0 ^Sauron tells you 'My Envoys: &1more to come.'={#($-1=\$1<.3+",");sauronclean;#ac -sauron0;#ac -sauron1;listadd -3 -4;#($Sauron=$-1);#print} + +#action >+disappear disappears into nothing.= +#action >+exp ^Needed: $1 xp={#print;#if (\@1=-$1, !@oldxp) #(@oldxp=@xp=\@1);#print ("Exp: "+%(\@1-@xp)+" from last score, "+%(\@1-@oldxp)+" from start of session");#(@xp=\@1)} +#action >+hunt *&1* leaves $2={#mark $2=bold;#print;#mark $2=} +#action >+save Saving=#print ("---> "+\$0+" <---") +#action >-someone ^Your blood freezes as you hear $1 =#if (\$1!="The" && \$1!="the" && \$1!="A" && \$1!="a" && \$1!="An" && \$1!="an") #print +#action >+Willow A sudden drowsiness overcomes you, you yawn and...={#print;wk} + +#mark sitting=bold +#mark resting=bold +#mark sleeping=bold +#mark Room: =bold +#mark tells you=underline +#mark YOU=bold red +#mark is dead! R.I.P.=bold +#mark glows with a bright light!=bold +#mark victim shocked=bold +#mark You feel a watchful eye=bold + +#mark The corpse of *&*=bold +#mark *an Orc*=bold yellow on red +#mark *$ the Orc*=bold yellow on red +#mark *a Troll*=bold cyan on yellow +#mark *$ the Troll*=bold cyan on yellow +#mark *a Human*=blue on cyan +#mark *$ the Human*=blue on cyan +#mark *$ the Numenorean*=blue on cyan +#mark *$ the Black Numenorean*=blue on cyan +#mark *a Dwarf*=bold cyan on magenta +#mark *$ the Dwarf*=bold cyan on magenta +#mark *an Elf*=blue on green +#mark *$ the Elf*=blue on green +#mark *a Hobbit*=bold yellow on blue +#mark *$ the Hobbit*=bold yellow on blue +#alias mumecolor={change col all default;change col shout bold yellow;change col damage bold red;change col hit bold blue} +#alias nocolors={#mark *an Orc*=inverse;#mark *$ the Orc*=inverse;#mark *a Troll*=inverse;#mark *$ the Troll*=inverse;#mark *a Human*=inverse;#mark *$ the Human*=inverse;#mark *$ the Numenorean*=inverse;#mark *$ the Black Numenorean*=inverse;#mark *a Dwarf*=inverse;#mark *$ the Dwarf*=inverse;#mark *an Elf*=inverse;#mark *$ the Elf*=inverse;#mark *a Hobbit*=inverse;#mark *$ the Hobbit*=inverse} +#alias colors={#mark *an Orc*=bold yellow on red;#mark *$ the Orc*=bold yellow on red;#mark *a Troll*=bold cyan on yellow;#mark *$ the Troll*=bold cyan on yellow;#mark *a Human*=blue on cyan;#mark *$ the Human*=blue on cyan;#mark *$ the Numenorean*=blue on cyan;#mark *$ the Black Numenorean*=blue on cyan;#mark *a Dwarf*=bold cyan on magenta;#mark *$ the Dwarf*=bold cyan on magenta;#mark *an Elf*=blue on green;#mark *$ the Elf*=blue on green;#mark *a Hobbit*=bold yellow on blue;#mark *$ the Hobbit*=bold yellow on blue} + +#bind >del ^[[P=&del-char-right +#bind A-bs ^[[071q=&clear-line +#bind A-del ^[[M=&kill-to-eol +#bind A-left ^[[160q=&begin-of-line +#bind A-return ^[[100q=&to-history +#bind A-right ^[[169q=&end-of-line +#bind M-B ^[b=&prev-word +#bind M-D ^[d=&del-word-right +#bind M-F ^[f=&next-word +#bind M-backsp ^[=&del-word-left +#bind M-bs ^[^H=&del-word-left +#bind M-tab ^[^I=&complete-line +#bind ^2 ^[[186q={s;hide} +#bind ^3 ^[[194q={d;hide} +#bind ^4 ^[[174q={w;hide} +#bind ^6 ^[[192q={e;hide} +#bind ^8 ^[[182q={n;hide} +#bind ^9 ^[[190q={u;hide} +#bind ^A ^A=&begin-of-line +#bind ^B ^B=&prev-char +#bind ^D ^D=&del-char-right +#bind ^E ^E=&end-of-line +#bind ^F ^F=&next-char +#bind ^K ^K=&kill-to-eol +#bind ^L ^L=&redraw-line +#bind ^N ^N=&next-line +#bind ^P ^P=&prev-line +#bind ^Q ^Q=&clear-line +#bind ^S ^S=#capture +#bind ^T ^T=&transpose +#bind ^V ^V=#stop +#bind ^W ^W=&to-history +#bind ^X ^X=#exe ("#capture emergency"+%@emergency++) +#bind ^Z ^Z=&suspend +#bind ^bs ^[[085q=&del-word-left +#bind ^del ^[[142q=&del-word-right +#bind ^left ^[[159q=&prev-word +#bind ^right ^[[168q=&next-word +#bind ^tab ^[[072q=&complete-line +#bind backsp =&del-char-left +#bind bs ^H=&del-char-left +#bind del ^[[3~=jo +#bind down ^[OB=&next-line +#bind end ^[[4~=jt +#bind enter ^[OM=flee +#bind home ^[[1~=stat +#bind ins ^[[2~=time +#bind left ^[OD=&prev-char +#bind lf ^J=&enter-line +#bind pgdwn ^[[6~=jh +#bind pgup ^[[5~=score +#bind return ^M=&enter-line +#bind right ^[OC=&next-char +#bind tab ^I=&complete-word +#bind up ^[OA=&prev-line +#bind ~^Q ^[~q=&clear-line +#bind ~^S ^[~s=#capture @@ -0,0 +1,67 @@ +Some notices for you who would like to hack the source in order to +improve powwow, fix bugs or just have fun: + +* Try not to run large chunks of existing code through your C + beautifier if the indentation style doesn't please you. This will + only greatly confuse the original author (if he can't recognize and + maintain his own code, who can?). If you write any new functions, + ok, use your own style as long as it's clear and consistent. + +* For portability, powwow is written using a few #defines that can + generate either K&R and ANSI function prototypes depending on the compiler, + so that it (should) compile fine in both cases. + If people convince me that non-ANSI compilers are rare enough these days, + we could switch to ANSI-only prototypes. Even then, please, do NOT + use any gcc-specific features (I've seen the char constant '\e' in some + places) even if gcc is very common. Our goal should be to let the + maximum number of people use powwow. (Most non-ANSI compilers grok + void and unsigned, so these are safe to use.) + +* For the same reason, do NOT use C++ style comments // + +* To sum it up, assume that the user has: + - a non-ANSI C compiler (use the __P, __P0, __P1, ... defines!) + - an exotic non-VT100 terminal (use TERMCAP!), possibly on a slow line + - a slow workstation, or a larger computer shared by 100 users and + aggressive sysadmins who think that mudding doesn't justify 10% or + even 5% CPU load. + +* Document your changes! A brief report of changes in the Changelog file is + absolutely necessary. So is updating the doc files (powwow.doc, powwow_help + and README) Also, sending an e-mail to the code author/mantainer documenting + your changes will be appreciated. + +Report from cancan's `Hacking': + +******************************************************************************* + Remember, that although I (Yorick) am the original author, I don't dictate + the code; it is explicitly in the public domain. I am merely trying to keep + some kind of order; if versions are permitted to diverge, they are very + painful to merge later. Also, different version branches are very confusing, + and makes it hard to define the "latest and best" version. Please try to + synchronize your hacks into one - the latest - version! +******************************************************************************* + +Well, Yorick refused to merge Powwow and Cancan, so now they both exist +indipendently... Now I (Cosmos) say exactly the same thing Yorick said +('do not let version diverge'), but I fear this will happen again :( +Only difference is that powwow is now GPL-ed and not Public Domain. +I hope this will help a little. + +* Rather than you just distributing your hacked version, I _really_ prefer you + to send back to me your changes, so that I can put them into the following + release. You lose nothing doing so, since even in case I refuse to include + your changes you can still distribute your version if you absolutely want :) + + Even if you decide to distribute such a modified version, please + make it clear that it is not the original version, use a version number + which can't be confused with an original version, and put your name + in Changelog and in POWWOW_VERSION. + +* I've tried to make the code obey the following rules for modularity: + - All exported things from one .c file is declared in its .h file. + - Conversely, symbols are imported by #including .h files, + not by local extern declarations. + - Everything that can be static should be (this is not quite true yet) + + Please obey these rules (or improve them). @@ -0,0 +1,229 @@ +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software +Foundation, Inc. + + This file is free documentation; the Free Software Foundation gives +unlimited permission to copy, distribute and modify it. + +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. (Caching is +disabled by default to prevent problems with accidental use of stale +cache files.) + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You only need +`configure.ac' if you want to change it or regenerate `configure' using +a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. Run `./configure --help' +for details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not support the `VPATH' +variable, you have to compile the package for one architecture at a +time in the source code directory. After you have installed the +package for one architecture, use `make distclean' before reconfiguring +for another architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=PATH' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' cannot figure out +automatically, but needs to determine by the type of machine the package +will run on. Usually, assuming the package is built to be run on the +_same_ architectures, `configure' can figure that out, but if it prints +a message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the `--target=TYPE' option to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + + Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +will cause the specified gcc to be used as the C compiler (unless it is +overridden in the site shell script). + +`configure' Invocation +====================== + + `configure' recognizes the following options to control how it +operates. + +`--help' +`-h' + Print a summary of the options to `configure', and exit. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..6e5be04 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,20 @@ +bin_PROGRAMS = powwow muc catrw follow movie +powwow_SOURCES = beam.c cmd.c log.c edit.c cmd2.c eval.c \ + utils.c main.c tcp.c list.c map.c tty.c \ + ptr.c +powwow_LDFLAGS = -rdynamic -ldl +powwowdir = $(pkgincludedir) +powwow_HEADERS = beam.h cmd.h log.h edit.h cmd2.h eval.h \ + utils.h main.h tcp.h list.h map.h tty.h \ + ptr.h defines.h +muc_SOURCES = muc.c +movie_SOURCES = movie.c +follow_SOURCES = follow.c +catrw_SOURCES = catrw.c + +man_MANS = powwow.6 +EXTRA_DIST = README README.follow README.term TODO Hacking Config.demo \ + powwow.doc powwow.help powwow.6 plugtest.c + +plugtest.so: plugtest.c + gcc -shared -o plugtest.so plugtest.c diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..33a722f --- /dev/null +++ b/Makefile.in @@ -0,0 +1,658 @@ +# Makefile.in generated by automake 1.9.4 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +SOURCES = $(catrw_SOURCES) $(follow_SOURCES) $(movie_SOURCES) $(muc_SOURCES) $(powwow_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = . +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +bin_PROGRAMS = powwow$(EXEEXT) muc$(EXEEXT) catrw$(EXEEXT) \ + follow$(EXEEXT) movie$(EXEEXT) +subdir = . +DIST_COMMON = README $(am__configure_deps) $(powwow_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(top_srcdir)/configure AUTHORS COPYING ChangeLog INSTALL NEWS \ + TODO depcomp install-sh missing mkinstalldirs +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno configure.status.lineno +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_CLEAN_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man6dir)" \ + "$(DESTDIR)$(powwowdir)" +binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +PROGRAMS = $(bin_PROGRAMS) +am_catrw_OBJECTS = catrw.$(OBJEXT) +catrw_OBJECTS = $(am_catrw_OBJECTS) +catrw_LDADD = $(LDADD) +am_follow_OBJECTS = follow.$(OBJEXT) +follow_OBJECTS = $(am_follow_OBJECTS) +follow_LDADD = $(LDADD) +am_movie_OBJECTS = movie.$(OBJEXT) +movie_OBJECTS = $(am_movie_OBJECTS) +movie_LDADD = $(LDADD) +am_muc_OBJECTS = muc.$(OBJEXT) +muc_OBJECTS = $(am_muc_OBJECTS) +muc_LDADD = $(LDADD) +am_powwow_OBJECTS = beam.$(OBJEXT) cmd.$(OBJEXT) log.$(OBJEXT) \ + edit.$(OBJEXT) cmd2.$(OBJEXT) eval.$(OBJEXT) utils.$(OBJEXT) \ + main.$(OBJEXT) tcp.$(OBJEXT) list.$(OBJEXT) map.$(OBJEXT) \ + tty.$(OBJEXT) ptr.$(OBJEXT) +powwow_OBJECTS = $(am_powwow_OBJECTS) +powwow_LDADD = $(LDADD) +DEFAULT_INCLUDES = -I. -I$(srcdir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(catrw_SOURCES) $(follow_SOURCES) $(movie_SOURCES) \ + $(muc_SOURCES) $(powwow_SOURCES) +DIST_SOURCES = $(catrw_SOURCES) $(follow_SOURCES) $(movie_SOURCES) \ + $(muc_SOURCES) $(powwow_SOURCES) +man6dir = $(mandir)/man6 +NROFF = nroff +MANS = $(man_MANS) +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +powwowHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(powwow_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + { test ! -d $(distdir) \ + || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -fr $(distdir); }; } +DIST_ARCHIVES = $(distdir).tar.gz +GZIP_ENV = --best +distuninstallcheck_listfiles = find . -type f -print +distcleancheck_listfiles = find . -type f -print +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +powwow_SOURCES = beam.c cmd.c log.c edit.c cmd2.c eval.c \ + utils.c main.c tcp.c list.c map.c tty.c \ + ptr.c + +powwow_LDFLAGS = -rdynamic -ldl +powwowdir = $(pkgincludedir) +powwow_HEADERS = beam.h cmd.h log.h edit.h cmd2.h eval.h \ + utils.h main.h tcp.h list.h map.h tty.h \ + ptr.h defines.h + +muc_SOURCES = muc.c +movie_SOURCES = movie.c +follow_SOURCES = follow.c +catrw_SOURCES = catrw.c +man_MANS = powwow.6 +EXTRA_DIST = README README.follow README.term TODO Hacking Config.demo \ + powwow.doc powwow.help powwow.6 plugtest.c + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +am--refresh: + @: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --gnu '; \ + cd $(srcdir) && $(AUTOMAKE) --gnu \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \ + $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \ + rm -f "$(DESTDIR)$(bindir)/$$f"; \ + done + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) +catrw$(EXEEXT): $(catrw_OBJECTS) $(catrw_DEPENDENCIES) + @rm -f catrw$(EXEEXT) + $(LINK) $(catrw_LDFLAGS) $(catrw_OBJECTS) $(catrw_LDADD) $(LIBS) +follow$(EXEEXT): $(follow_OBJECTS) $(follow_DEPENDENCIES) + @rm -f follow$(EXEEXT) + $(LINK) $(follow_LDFLAGS) $(follow_OBJECTS) $(follow_LDADD) $(LIBS) +movie$(EXEEXT): $(movie_OBJECTS) $(movie_DEPENDENCIES) + @rm -f movie$(EXEEXT) + $(LINK) $(movie_LDFLAGS) $(movie_OBJECTS) $(movie_LDADD) $(LIBS) +muc$(EXEEXT): $(muc_OBJECTS) $(muc_DEPENDENCIES) + @rm -f muc$(EXEEXT) + $(LINK) $(muc_LDFLAGS) $(muc_OBJECTS) $(muc_LDADD) $(LIBS) +powwow$(EXEEXT): $(powwow_OBJECTS) $(powwow_DEPENDENCIES) + @rm -f powwow$(EXEEXT) + $(LINK) $(powwow_LDFLAGS) $(powwow_OBJECTS) $(powwow_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/beam.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/catrw.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd2.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/edit.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eval.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/follow.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/list.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/map.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/movie.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/muc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ptr.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tcp.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tty.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utils.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-man6: $(man6_MANS) $(man_MANS) + @$(NORMAL_INSTALL) + test -z "$(man6dir)" || $(mkdir_p) "$(DESTDIR)$(man6dir)" + @list='$(man6_MANS) $(dist_man6_MANS) $(nodist_man6_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.6*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 6*) ;; \ + *) ext='6' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man6dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man6dir)/$$inst"; \ + done +uninstall-man6: + @$(NORMAL_UNINSTALL) + @list='$(man6_MANS) $(dist_man6_MANS) $(nodist_man6_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.6*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 6*) ;; \ + *) ext='6' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f '$(DESTDIR)$(man6dir)/$$inst'"; \ + rm -f "$(DESTDIR)$(man6dir)/$$inst"; \ + done +install-powwowHEADERS: $(powwow_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(powwowdir)" || $(mkdir_p) "$(DESTDIR)$(powwowdir)" + @list='$(powwow_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f=$(am__strip_dir) \ + echo " $(powwowHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(powwowdir)/$$f'"; \ + $(powwowHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(powwowdir)/$$f"; \ + done + +uninstall-powwowHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(powwow_HEADERS)'; for p in $$list; do \ + f=$(am__strip_dir) \ + echo " rm -f '$(DESTDIR)$(powwowdir)/$$f'"; \ + rm -f "$(DESTDIR)$(powwowdir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + $(am__remove_distdir) + mkdir $(distdir) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done + -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(SHELL) $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r $(distdir) +dist-gzip: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 + $(am__remove_distdir) + +dist-tarZ: distdir + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__remove_distdir) + +dist-shar: distdir + shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz + $(am__remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__remove_distdir) + +dist dist-all: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + case '$(DIST_ARCHIVES)' in \ + *.tar.gz*) \ + GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + esac + chmod -R a-w $(distdir); chmod a+w $(distdir) + mkdir $(distdir)/_build + mkdir $(distdir)/_inst + chmod a-w $(distdir) + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && cd $(distdir)/_build \ + && ../configure --srcdir=.. --prefix="$$dc_install_base" \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist \ + && rm -rf $(DIST_ARCHIVES) \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck + $(am__remove_distdir) + @(echo "$(distdir) archives ready for distribution: "; \ + list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ + sed -e '1{h;s/./=/g;p;x;}' -e '$${p;x;}' +distuninstallcheck: + @cd $(distuninstallcheck_dir) \ + && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) $(MANS) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man6dir)" "$(DESTDIR)$(powwowdir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic mostlyclean-am + +distclean: distclean-am + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-man install-powwowHEADERS + +install-exec-am: install-binPROGRAMS + +install-info: install-info-am + +install-man: install-man6 + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-info-am uninstall-man \ + uninstall-powwowHEADERS + +uninstall-man: uninstall-man6 + +.PHONY: CTAGS GTAGS all all-am am--refresh check check-am clean \ + clean-binPROGRAMS clean-generic ctags dist dist-all dist-bzip2 \ + dist-gzip dist-shar dist-tarZ dist-zip distcheck distclean \ + distclean-compile distclean-generic distclean-tags \ + distcleancheck distdir distuninstallcheck dvi dvi-am html \ + html-am info info-am install install-am install-binPROGRAMS \ + install-data install-data-am install-exec install-exec-am \ + install-info install-info-am install-man install-man6 \ + install-powwowHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-binPROGRAMS uninstall-info-am \ + uninstall-man uninstall-man6 uninstall-powwowHEADERS + + +plugtest.so: plugtest.c + gcc -shared -o plugtest.so plugtest.c +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: @@ -0,0 +1,140 @@ + + powwow 1.2.4 README + +Powwow is a client program intended mainly for playing MUD. +It implements (a subset of) the telnet protocol. + +Files you should have received: + + README This text. + Changelog What has changed since the last release. + powwow.doc Complete documentation. READ this! + make_it A shell script that automatically compiles powwow on + many systems. + Compile.how A hopefully detailed text file showing how to compile + powwow on different systems. + Makefile Makefile: tailor it for your system if make_it fails. + *.[ch] Sources. + tools/* Additional standalone utilities. + powwow.help Online help file (in plain ASCII). + powwow.6 Man page. + Config.demo A demonstrative definition file for powwow + Hacking Read this if you want to improve/destroy powwow + yourself. + README.follow Documentation for the 'follow' mini-program. + README.term How to make termpowwow + +COMPILING + + Try the shell-script 'make_it', ie type './make_it'. + If that doesn't work, read the file 'Compile.how', try to edit + the 'Makefile' manually and either run './make_it' or 'make'. + If you have to edit the Makefile, or edit the source + code, to get it to work, pleae e-mail any changes you did to: + <max@Linuz.sns.it>. Also include info on what system you have + (type 'uname -a' to get the necessary info). + + You may also want to edit the Makefile in order to fine-tune powwow + to your system (change optimizations, include regexp library, etc.) + +INSTALLING + + If you want powwow's definition files to go in a specific directory, + set the environment variable POWWOWDIR to that directory. It will be + searched first for definition files at startup. + + Put the file powwow.6 in a suitable directory if you want users on + your system to be able to read the long and comprehensive man page ;) + + Powwow supports the MUME editing protocol. It enables you to edit + texts locally with your favourite editor. So far, only MUME supports + this protocol, but this might change in the future. + + Powwow looks for the editor in the POWWOWEDITOR enviroment variable, + and if it doesn't exist, in EDITOR, and uses "emacs" as default. For + text viewing, powwow looks for POWWOWPAGER, then PAGER, then uses + "more" as default. + + If you are on a multi-window terminal (such as an X terminal or NCSA + telnet from a Mac or PC), powwow will let you start the editor in + another window and remain active. You will then also be able to edit + several texts at the same time. To achieve this, let the first + character of your editor/pager be '&' (which is then skipped). + + Example: (Bourne shell syntax) + + POWWOWEDITOR=vi Use vi as normal editor (same window as + powwow) + POWWOWEDITOR='&emacs' Use emacs as editor in a separate window (if + you are on an X terminal) + POWWOWEDITOR='&xterm -e vi' Use vi in another X window + POWWOWPAGER='&xterm -e less' Use less as your file viewer in another + X window + + If you use a multi-window terminal and have emacsclient installed, it + is a good choice, since you only need one emacs window for all your + editing sessions and you don't have to start and exit emacs all the + time. Set POWWOWEDITOR='&emacsclient' in that case, and make sure your + emacs has a running server (put (server-start) in your .emacs file or + type M-x server-start). + + If you want to use the editing functions, you must execute the + `#identify' command to notify the server that the client supports the + protocol. This can also be done with an action; see the documentation + for details. + + For editing Mudlle programs with emacs, there is a special mode that + helps you with indenting. To use it, put mudlle.el in a suitable + place, and add the two following lines to your .emacs file: + + (setq load-path (append load-path '("mydirectory"))) + (autoload 'mudlle-mode "mudlle.el" "Turns on mudlle editing mode" t) + + where you replace mydirectory with the directory where mudlle.el can + be found. If you put the string -*-mudlle-*- in the first line of + a mudlle program (i.e. in a comment), then emacs will automatically + turn on mudlle mode for that file when you edit it. + The mudlle mode can be customized to some extent. See the source for + details. + +BUGS + + If you have any problems with powwow, try to fix them yourself + (you have the source, right?) or at least isolate the bugs so + the maintainer has a fair change of fixing them. Don't expect + a bug to be fixed, unless you explain it in detail (expecially + how to reproduce it) and supply the powwow and OS version, + as well as the compilation options. + Suggestions for improvements are also very welcome. + +AUTHORS OF CANCAN + + Since powwow is based on cancan, we report also this. + + Mattias Engdegard <f91-men@nada.kth.se> was the original author. + Many other people have contributed at least as much, including + Finn Arne Gangstad <finnag@pvv.unit.no>, David Gay <dgay@di.epfl.ch>, + Gary Dezern <gdezern@satelnet.org> + and Lai-Chang Woo <vivriel@scs.com.sg>. + It is unclear who the current maintainer is, but it seems to be + Finn Arne Gangstad. Ask around at MUME to find out more about cancan. + +AUTHORS OF POWWOW + + Massimiliano Ghilardi <max@Linuz.sns.it>, alias Cosmos, + is the original author, and Gustav Hållberg <f92-gha@nada.kth.se> + contributed a lot of new features. + The powwow WWW page is: http://Linuz.sns.it/~max/powwow.html + + If you forgot where you downloaded powwow from, you can get it from + the above address, or from + ftp://Linuz.sns.it/pub/Linux/ext-pack/powwow/ + + To learn more about MUME, have a look at http://fire.pvv.org/mume/ + which also explains how to connect. + +COPYRIGHT + + Powwow is placed under the terms of GPL (GNU General Public License) + The GPL License can be found in the file COPYING. + diff --git a/README.follow b/README.follow new file mode 100644 index 0000000..8b4e185 --- /dev/null +++ b/README.follow @@ -0,0 +1,18 @@ + + follow 0.1 README + +This mini-program is mainly intended for debugging powwow. +It is completely standalone, and needs to be called with a file-name +(example: `follow mycapture'). +Hitting ESC or ^C quits `follow', hitting RETURN prints the next line +of the file, any other key prints the next character (only one) of the file + +I know it is a _stupid_ program, but it is useful if you find screen-related +bugs in powwow, i.e. powwow does not print some lines or prints something +wrong. +In that case, if you redirect powwow output to a file and reproduce the bug, +you can use `follow your-filename' to examine the file and see what is wrong + +How to send a copy of powwow output to a file: +powwow your-arguments | tee your-filename + diff --git a/README.term b/README.term new file mode 100644 index 0000000..46d9a73 --- /dev/null +++ b/README.term @@ -0,0 +1,26 @@ + +'term' was written by Michael O'Reilly. + +If you don't know what term is, then you can ignore this file. :) + +Otherwise, if you want term support, read on... + +You need to edit the Makefile and edit the TERMDIR variable to the +directory of your term source and client.a. + +If you don't want 'term' compression on for powwow, take out the +-DTERM_COMPRESS in the CFLAGS variable in the Makefile. + +Edit any of the other variables you find neccessary. + +Read the original README for information you might need to know. + +Then do `make termpowwow' + +Note: Unfortunately one of the setbacks of termpowwow is that it won't +detect unknown hosts, nor will it detect if the host refused the connection. +If you don't get any output from a host after a few moments, then you'll +have to ^C. I don't think there's any way around this. + +(note - term support does not allow multiple sessions...) + @@ -0,0 +1,46 @@ +-*-indented-text-*- + +From the authors of cancan: + + THINGS TO DO + Cancan should know the codes of at least some keys + by looking in the TERMCAP. (especially control keys are trivial!) + + - Run (a)lint! + + - There seems to be problems with running cancan on exotic terminals. + This defeats the very purpose of all the carefully terminal- + independent code with TERMCAP, and is generally embarrassing. + + - more system calls should be checked for EINTR for sysV unices + + - negotiate the telnet BINARY option + + - support the telnet IAC GA command to identify prompts + (But what for? Prompts have to be identified as such in the absence + of GA anyway, and there doesn't seem to be a need for it right + now.) + + - implement reverse-incremental-search (like ^R in GNU Readline) + + KNOWN BUGS + - Deleting more than one character with deletechar() might leave + ugly traces on lines that are entirely deleted. + + - using #hilite with coloured background might have effects beyond the + input line, depending on the terminal (don't do that, then :-) + + FUTURE POSSIBLE IMPROVEMENTS + Do some more for portability (clean up the terminal mess) + The source should be more modular + Filtering output through shell command (grep etc) + + +THINGS TO DO/PLANNED IMPROVEMENTS on powwow: + - make a better #help + - add termcap `end of bold', `end of blink' etc. + + If you have ideas, suggestions or whatever, e-mail them to me + (max@Linuz.sns.it) and if I find them interesting, I will add them. + Also, I am trying to keep powwow updated with further releases + of cancan. diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 0000000..7b25188 --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,1020 @@ +# generated automatically by aclocal 1.9.4 -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 +# Free Software Foundation, Inc. +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +# -*- Autoconf -*- +# Copyright (C) 2002, 2003 Free Software Foundation, Inc. +# Generated from amversion.in; do not edit by hand. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version="1.9"]) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION so it can be traced. +# This function is AC_REQUIREd by AC_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], + [AM_AUTOMAKE_VERSION([1.9.4])]) + +# AM_AUX_DIR_EXPAND + +# Copyright (C) 2001, 2003 Free Software Foundation, Inc. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to +# `$srcdir', `$srcdir/..', or `$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is `.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[dnl Rely on autoconf to set up CDPATH properly. +AC_PREREQ([2.50])dnl +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997, 2000, 2001, 2003, 2004 Free Software Foundation, Inc. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# serial 6 + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ(2.52)dnl + ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE]) +AC_SUBST([$1_FALSE]) +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + +# serial 7 -*- Autoconf -*- + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 +# Free Software Foundation, Inc. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + + +# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "GCJ", or "OBJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +ifelse([$1], CC, [depcc="$CC" am_compiler_list=], + [$1], CXX, [depcc="$CXX" am_compiler_list=], + [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE(dependency-tracking, +[ --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH]) +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 +# Free Software Foundation, Inc. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +#serial 2 + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[for mf in $CONFIG_FILES; do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # So let's grep whole file. + if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done +done +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each `.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# Do all the work for Automake. -*- Autoconf -*- + +# This macro actually does too much some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 +# Free Software Foundation, Inc. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# serial 11 + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.58])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +# test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && + test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) + AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) +AM_MISSING_PROG(AUTOCONF, autoconf) +AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) +AM_MISSING_PROG(AUTOHEADER, autoheader) +AM_MISSING_PROG(MAKEINFO, makeinfo) +AM_PROG_INSTALL_SH +AM_PROG_INSTALL_STRIP +AC_REQUIRE([AM_PROG_MKDIR_P])dnl +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES(CC)], + [define([AC_PROG_CC], + defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES(CXX)], + [define([AC_PROG_CXX], + defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl +]) +]) + + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $1 | $1:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count]) + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. + +# Copyright (C) 2001, 2003 Free Software Foundation, Inc. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +install_sh=${install_sh-"$am_aux_dir/install-sh"} +AC_SUBST(install_sh)]) + +# -*- Autoconf -*- +# Copyright (C) 2003 Free Software Foundation, Inc. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# serial 1 + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# serial 2 + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo done +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# We grep out `Entering directory' and `Leaving directory' +# messages which can occur if `w' ends up in MAKEFLAGS. +# In particular we don't look at `^make:' because GNU make might +# be invoked under some other name (usually "gmake"), in which +# case it prints its new name instead of `make'. +if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then + am__include=include + am__quote= + _am_result=GNU +fi +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then + am__include=.include + am__quote="\"" + _am_result=BSD + fi +fi +AC_SUBST([am__include]) +AC_SUBST([am__quote]) +AC_MSG_RESULT([$_am_result]) +rm -f confinc confmf +]) + +# -*- Autoconf -*- + + +# Copyright (C) 1997, 1999, 2000, 2001, 2003 Free Software Foundation, Inc. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# serial 3 + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it supports --run. +# If it does, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + AC_MSG_WARN([`missing' script is too old or missing]) +fi +]) + +# AM_PROG_MKDIR_P +# --------------- +# Check whether `mkdir -p' is supported, fallback to mkinstalldirs otherwise. + +# Copyright (C) 2003, 2004 Free Software Foundation, Inc. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# Automake 1.8 used `mkdir -m 0755 -p --' to ensure that directories +# created by `make install' are always world readable, even if the +# installer happens to have an overly restrictive umask (e.g. 077). +# This was a mistake. There are at least two reasons why we must not +# use `-m 0755': +# - it causes special bits like SGID to be ignored, +# - it may be too restrictive (some setups expect 775 directories). +# +# Do not use -m 0755 and let people choose whatever they expect by +# setting umask. +# +# We cannot accept any implementation of `mkdir' that recognizes `-p'. +# Some implementations (such as Solaris 8's) are not thread-safe: if a +# parallel make tries to run `mkdir -p a/b' and `mkdir -p a/c' +# concurrently, both version can detect that a/ is missing, but only +# one can create it and the other will error out. Consequently we +# restrict ourselves to GNU make (using the --version option ensures +# this.) +AC_DEFUN([AM_PROG_MKDIR_P], +[if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then + # We used to keeping the `.' as first argument, in order to + # allow $(mkdir_p) to be used without argument. As in + # $(mkdir_p) $(somedir) + # where $(somedir) is conditionally defined. However this is wrong + # for two reasons: + # 1. if the package is installed by a user who cannot write `.' + # make install will fail, + # 2. the above comment should most certainly read + # $(mkdir_p) $(DESTDIR)$(somedir) + # so it does not work when $(somedir) is undefined and + # $(DESTDIR) is not. + # To support the latter case, we have to write + # test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir), + # so the `.' trick is pointless. + mkdir_p='mkdir -p --' +else + # On NextStep and OpenStep, the `mkdir' command does not + # recognize any option. It will interpret all options as + # directories to create, and then abort because `.' already + # exists. + for d in ./-p ./--version; + do + test -d $d && rmdir $d + done + # $(mkinstalldirs) is defined by Automake if mkinstalldirs exists. + if test -f "$ac_aux_dir/mkinstalldirs"; then + mkdir_p='$(mkinstalldirs)' + else + mkdir_p='$(install_sh) -d' + fi +fi +AC_SUBST([mkdir_p])]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# serial 2 + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# ------------------------------ +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), 1)]) + +# _AM_SET_OPTIONS(OPTIONS) +# ---------------------------------- +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# +# Check to make sure that the build environment is sane. +# + +# Copyright (C) 1996, 1997, 2000, 2001, 2003 Free Software Foundation, Inc. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# serial 3 + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftest.file +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftest.file` + fi + rm -f conftest.file + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT(yes)]) + +# AM_PROG_INSTALL_STRIP + +# Copyright (C) 2001, 2003 Free Software Foundation, Inc. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# One issue with vendor `install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in `make install-strip', and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be `maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004 Free Software Foundation, Inc. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# serial 1 + + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of `v7', `ustar', or `pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. +AM_MISSING_PROG([AMTAR], [tar]) +m4_if([$1], [v7], + [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], + [m4_case([$1], [ustar],, [pax],, + [m4_fatal([Unknown tar format])]) +AC_MSG_CHECKING([how to create a $1 tar archive]) +# Loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' +_am_tools=${am_cv_prog_tar_$1-$_am_tools} +# Do not fold the above two line into one, because Tru64 sh and +# Solaris sh will not grok spaces in the rhs of `-'. +for _am_tool in $_am_tools +do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; + do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar <conftest.tar]) + grep GrepMe conftest.dir/file >/dev/null 2>&1 && break + fi +done +rm -rf conftest.dir + +AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) +AC_MSG_RESULT([$am_cv_prog_tar_$1])]) +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + @@ -0,0 +1,438 @@ +/* + * beam.c -- code to beam texts across the TCP connection following a + * special protocol + * + * Copyright (C) 1998 by Massimiliano Ghilardi + * + * 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. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <time.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/wait.h> + +#include "defines.h" +#include "main.h" +#include "utils.h" +#include "beam.h" +#include "map.h" +#include "tcp.h" +#include "tty.h" +#include "edit.h" +#include "eval.h" + +editsess *edit_sess; /* head of session list */ + +char edit_start[BUFSIZE]; /* messages to send to host when starting */ +char edit_end[BUFSIZE]; /* or leaving editing sessions */ + +static void write_message __P1 (char *,s) +{ + clear_input_line(opt_compact); + if (!opt_compact) { + tty_putc('\n'); + status(1); + } + tty_puts(s); +} + +/* + * Process editing protocol message from buf with len remaining chars. + * Return number of characters used in the message. + */ +int process_message __P2 (char *,buf, int,len) +{ + int msglen, i, l, used; + char *text; + char msg[BUFSIZE]; + + status(1); + + msglen = atoi(buf + 1); + for (i = 1; i < len && isdigit(buf[i]); i++) + ; + + if (i < len && buf[i] == '\r') i++; + if (i >= len || buf[i] != '\n') { + write_message ("#warning: MPI protocol error\n"); + return 0; + } + + l = len - ++i; + if (msglen < l) { + l = msglen; + used = msglen + i; + } else + used = len; + + text = (char *)malloc(msglen); + if (!text) { + errmsg("malloc"); + return used > len ? len : used; + } + + memmove(text, buf + i, l); + i = l; + while(i < msglen) { + /* + * read() might block here, but it should't be long. I should also + * process any telnet protocol commands, but I don't care right now. + */ + while ((l = read(tcp_fd, text + i, msglen - i)) == -1 && errno == EINTR) + ; + if (l == -1) { + errmsg("read message from socket"); + return used > len ? len : used; + } + tty_printf("\rgot %d chars out of %d", i, msglen); + tty_flush(); + i += l; + } + tty_printf("\rread all %d chars.%s\n", msglen, tty_clreoln); + + if ((msglen = tcp_unIAC(text, msglen))) + switch(*buf) { + case 'E': + message_edit(text, msglen, 0, 0); + break; + case 'V': + message_edit(text, msglen, 1, 0); + break; + default: + sprintf(msg, "#warning: received a funny message (0x%x)\n", *buf); + write_message(msg); + free(text); + break; + } + + return used; +} + +/* + * abort an editing session when + * the MUD socket it comes from gets closed + */ +void abort_edit_fd __P1 (int,fd) +{ + editsess **sp, *p; + + if (fd < 0) + return; + + for (sp = &edit_sess; *sp; sp = &(*sp)->next) { + p = *sp; + if (p->fd != fd) + continue; + + if (kill(p->pid, SIGKILL) < 0) { /* Editicide */ + errmsg("kill editor child"); + continue; + } + + PRINTF("#aborted `%s' (%u)\n", p->descr, p->key); + p->cancel = 1; + } +} + +/* + * cancel an editing session; does not free anything + * (the child death signal handler will remove the session from the list) + */ +void cancel_edit __P1 (editsess *,sp) +{ + char buf[BUFSIZE]; + char keystr[16]; + + if (kill(sp->pid, SIGKILL) < 0) { /* Editicide */ + errmsg("kill editor child"); + return; + } + PRINTF("#killed `%s' (%u)\n", sp->descr, sp->key); + sprintf(keystr, "C%u\n", sp->key); + sprintf(buf, "%sE%d\n%s", MPI, (int)strlen(keystr), keystr); + tcp_write(sp->fd, buf); + sp->cancel = 1; +} + +/* + * send back edited text to server, or cancel the editing session if the + * file was not changed. + */ +static void finish_edit __P1 (editsess *,sp) +{ + char *realtext = NULL, *text; + int fd, txtlen, hdrlen; + struct stat sbuf; + char keystr[16], buf[256], hdr[65]; + + if (sp->fd == -1) + goto cleanup_file; + + fd = open(sp->file, O_RDONLY); + if (fd == -1) { + errmsg("open edit file"); + goto cleanup_file; + } + if (fstat(fd, &sbuf) == -1) { + errmsg("fstat edit file"); + goto cleanup_fd; + } + + txtlen = sbuf.st_size; + + if (!sp->cancel && (sbuf.st_mtime > sp->ctime || txtlen != sp->oldsize)) { + /* file was changed by editor: send back result to server */ + + realtext = (char *)malloc(2*txtlen + 65); + /* *2 to protect IACs, +1 is for possible LF, +64 for header */ + if (!realtext) { + errmsg("malloc"); + goto cleanup_fd; + } + + text = realtext + 64; + if ((txtlen = tcp_read_addIAC(fd, text, txtlen)) == -1) + goto cleanup_text; + + if (txtlen && text[txtlen - 1] != '\n') { + /* If the last line isn't LF-terminated, add an LF; + * however, empty files must remain empty */ + text[txtlen] = '\n'; + txtlen++; + } + + sprintf(keystr, "E%u\n", sp->key); + + sprintf(hdr, "%sE%d\n%s", MPI, (int)(txtlen + strlen(keystr)), keystr); + + text -= (hdrlen = strlen(hdr)); + memcpy(text, hdr, hdrlen); + + /* text[hdrlen + txtlen] = '\0'; */ + tcp_raw_write(sp->fd, text, hdrlen + txtlen); + + sprintf(buf, "#completed session %s (%u)\n", sp->descr, sp->key); + write_message(buf); + } else { + /* file wasn't changed, cancel editing session */ + sprintf(keystr, "C%u\n", sp->key); + sprintf(hdr, "%sE%d\n%s", MPI, (int) strlen(keystr), keystr); + + tcp_raw_write(sp->fd, hdr, strlen(hdr)); + + sprintf(buf, "#cancelled session %s (%u)\n", sp->descr, sp->key); + write_message(buf); + } + +cleanup_text: if (realtext) free(realtext); +cleanup_fd: close(fd); +cleanup_file: if (unlink(sp->file) < 0) + errmsg("unlink edit file"); +} + +/* + * start an editing session: process the EDIT/VIEW message + * if view == 1, text will be viewed, else edited + */ +void message_edit __P4 (char *,text, int,msglen, char,view, char,builtin) +{ + char tmpname[BUFSIZE], command_str[BUFSIZE], buf[BUFSIZE]; + char *errdesc = "#warning: protocol error (message_edit, no %s)\n"; + int tmpfd, i, childpid; + unsigned int key; + editsess *s; + char *editor, *descr; + char *args[4]; + int waitforeditor; + + status(1); + + args[0] = "/bin/sh"; args[1] = "-c"; + args[2] = command_str; args[3] = 0; + + if (view) { + key = (unsigned int)-1; + i = 0; + } else { + if (text[0] != 'M') { + tty_printf(errdesc, "M"); + free(text); + return; + } + for (i = 1; i < msglen && isdigit(text[i]); i++) + ; + if (text[i++] != '\n' || i >= msglen) { + tty_printf(errdesc, "\\n"); + free(text); + return; + } + key = strtoul(text + 1, NULL, 10); + } + descr = text + i; + while (i < msglen && text[i] != '\n') i++; + if (i >= msglen) { + tty_printf(errdesc, "desc"); + free(text); + return; + } + text[i++] = '\0'; + + sprintf(tmpname, "/tmp/powwow.%u.%d%d", key, getpid(), abs(rand()) >> 8); + if ((tmpfd = open(tmpname, O_WRONLY | O_CREAT, 0600)) < 0) { + errmsg("create temp edit file"); + free(text); + return; + } + if (write(tmpfd, text + i, msglen - i) < msglen - i) { + errmsg("write to temp edit file"); + free(text); + close(tmpfd); + return; + } + close(tmpfd); + + s = (editsess*)malloc(sizeof(editsess)); + if (!s) { + errmsg("malloc"); + return; + } + s->ctime = time((time_t*)NULL); + s->oldsize = msglen - i; + s->key = key; + s->fd = (view || builtin) ? -1 : tcp_fd; /* MUME doesn't expect a reply. */ + s->cancel = 0; + s->descr = my_strdup(descr); + s->file = my_strdup(tmpname); + free(text); + + /* send a edit_start message (if wanted) */ + if ((!edit_sess) && (*edit_start)) { + error = 0; + parse_instruction(edit_start, 0, 0, 1); + history_done = 0; + } + + if (view) { + if (!(editor = getenv("POWWOWPAGER")) && !(editor = getenv("PAGER"))) + editor = "more"; + } else { + if (!(editor = getenv("POWWOWEDITOR")) && !(editor = getenv("EDITOR"))) + editor = "emacs"; + } + + if (editor[0] == '&') { + waitforeditor = 0; + editor++; + } else + waitforeditor = 1; + + if (waitforeditor) { + tty_quit(); + /* ignore SIGINT since interrupting the child would interrupt us too, + if we are in the same tty group */ + sig_permanent(SIGINT, SIG_IGN); + sig_permanent(SIGCHLD, SIG_DFL); + } + + switch(childpid = fork()) { /* let's get schizophrenic */ + case 0: + sprintf(command_str, "%s %s", editor, s->file); + sprintf(buf, "TITLE=%s", s->descr); + putenv(buf); + /* setenv("TITLE", s->descr, 1);*/ + execvp((char *)args[0], (char **)args); + syserr("execve"); + break; + case -1: + errmsg("fork"); + free(s->descr); + free(s->file); + free(s); + return; + } + s->pid = childpid; + if (waitforeditor) { + while ((i = waitpid(childpid, (int*)NULL, 0)) == -1 && errno == EINTR) + ; + + signal_start(); /* reset SIGINT and SIGCHLD handlers */ + tty_start(); + + if (s->fd != -1) { + tty_gotoxy(0, lines - 1); + tty_putc('\n'); + } + + if (i == -1) + errmsg("waitpid"); + else + finish_edit(s); + + free(s->descr); + free(s->file); + if (i != -1 && !edit_sess && *edit_end) { + error = 0; + parse_instruction(edit_end, 0, 0, 1); + history_done = 0; + } + + free(s); + + } else { + s->next = edit_sess; + edit_sess = s; + } +} + +/* + * Our child has snuffed it. check if it was an editor, and update the + * session list if that is the case. + */ +void sig_chld_bottomhalf __P0 (void) +{ + int fd, pid, ret; + editsess **sp, *p; + + /* GH: while() instead of just one check */ + while ((pid = waitpid(-1, &ret, WNOHANG)) > 0) { + + /* GH: check for WIFSTOPPED unnecessary since no */ + /* WUNTRACED to waitpid() */ + for (sp = &edit_sess; *sp && (*sp)->pid != pid; sp = &(*sp)->next) + ; + if (*sp) { + finish_edit(*sp); + p = *sp; *sp = p->next; + fd = p->fd; + free(p->descr); + free(p->file); + free(p); + + /* GH: only send message if found matching session */ + + /* send the edit_end message if this is the last editor... */ + if ((!edit_sess) && (*edit_end)) { + int otcp_fd = tcp_fd; /* backup current socket fd */ + tcp_fd = fd; + error = 0; + parse_instruction(edit_end, 0, 0, 1); + history_done = 0; + tcp_fd = otcp_fd; + } + } + } +} + @@ -0,0 +1,17 @@ +/* public things from beam.c */ + +#ifndef _BEAM_H_ +#define _BEAM_H_ + +int process_message __P ((char *buf, int len)); +void cancel_edit __P ((editsess *sp)); +void abort_edit_fd __P ((int fd)); +void message_edit __P ((char *text, int msglen, char view, char builtin)); +void sig_chld_bottomhalf __P ((void)); + +extern char edit_start[]; +extern char edit_end[]; +extern editsess *edit_sess; + +#endif /* _BEAM_H_ */ + @@ -0,0 +1,39 @@ +/* + * catrw.c -- open a file with O_RDWR and print it. + * + * This file is placed in the public domain. + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> + +#define BUFSIZE 4096 +char buf[BUFSIZE]; + +void catrw(int fd) { + int i; + for (;;) { + while ( (i = read(fd, buf, BUFSIZE)) < 0 && errno == EINTR) + ; + if (i <= 0) + break; + write(1, buf, i); + } +} + +int main(int argc, char *argv[]) { + int fd; + if (argc == 1) + catrw(0); + else { + while (--argc && (fd = open(*++argv, O_RDWR))) { + catrw(fd); + close(fd); + } + } + return 0; +} + @@ -0,0 +1,2464 @@ +/* + * cmd.c -- functions for powwow's built-in #commands + * + * (created: Finn Arne Gangstad (Ilie), Dec 25th, 1993) + * + * Copyright (C) 1998 by Massimiliano Ghilardi + * + * 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. + * + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <signal.h> +#include <ctype.h> +#include <time.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <dlfcn.h> + +#include "defines.h" +#include "main.h" +#include "utils.h" +#include "beam.h" +#include "cmd.h" +#include "cmd2.h" +#include "edit.h" +#include "list.h" +#include "map.h" +#include "tcp.h" +#include "tty.h" +#include "eval.h" +#include "log.h" + +/* local function declarations */ +#define _ __P ((char *arg)) + +static void cmd_help _, cmd_shell _, + cmd_action _, cmd_add _, cmd_alias _, cmd_at _, cmd_beep _, cmd_bind _, + cmd_cancel _, cmd_capture _, cmd_clear _, cmd_connect _, cmd_cpu _, + cmd_do _, cmd_delim _, cmd_edit _, cmd_emulate _, cmd_exe _, + cmd_file _, cmd_for _, cmd_hilite _, cmd_history _, cmd_host _, + cmd_identify _, cmd_if _, cmd_in _, cmd_init _, cmd_isprompt _, + cmd_key _, cmd_keyedit _, + cmd_load _, cmd_map _, cmd_mark _, cmd_movie _, + cmd_net _, cmd_nice _, cmd_option _, + cmd_prefix _, cmd_print _, cmd_prompt _, cmd_put _, + cmd_qui _, cmd_quit _, cmd_quote _, + cmd_rawsend _, cmd_rawprint _, cmd_rebind _, cmd_rebindall _, cmd_rebindALL _, + cmd_record _, cmd_request _, cmd_reset _, cmd_retrace _, + cmd_save _, cmd_send _, cmd_setvar _, cmd_snoop _, cmd_spawn _, cmd_stop _, + cmd_time _, cmd_var _, cmd_ver _, cmd_while _, cmd_write _, + cmd_eval _, cmd_zap _, cmd_module _, cmd_group _; + +#ifdef BUG_TELNET +static void cmd_color _; +#endif + +#undef _ + +/* This must be init'd now at runtime */ +cmdstruct *commands = NULL; + +/* The builtin commands */ +cmdstruct default_commands[] = +{ + {NULL,"help", "[keys|math|command]\tthis text, or help on specified topic", cmd_help,NULL}, + {NULL,"17", "command\t\t\trepeat `command' 17 times", (function_str)0,NULL}, +#ifndef NO_SHELL + {NULL,"!", "shell-command\t\texecute a shell command using /bin/sh", cmd_shell,NULL}, +#endif + {NULL,"action", "[[<|=|>|%][+|-]name] [{pattern|(expression)} [=[command]]]\n\t\t\t\tdelete/list/define actions", cmd_action,NULL}, + {NULL,"add", "{string|(expr)}\t\tadd the string to word completion list", cmd_add,NULL}, + {NULL,"alias", "[name[=[text]]]\t\tdelete/list/define aliases", cmd_alias,NULL}, + {NULL,"at", "[name [(time-string) [command]]\tset time of delayed label", cmd_at,NULL}, + {NULL,"beep", "\t\t\t\tmake your terminal beep (like #print (*7))", cmd_beep,NULL}, + {NULL,"bind", "[edit|name [seq][=[command]]]\tdelete/list/define key bindings", cmd_bind,NULL}, + {NULL,"cancel", "[number]\t\tcancel editing session", cmd_cancel,NULL}, + {NULL,"capture", "[filename]\t\tbegin/end of capture to file", cmd_capture,NULL}, + {NULL,"clear", "\t\t\tclear input line (use from spawned programs)", cmd_clear,NULL}, +#ifdef BUG_TELNET + {NULL,"color", "attr\t\t\tset default colors/attributes", cmd_color,NULL}, +#endif + {NULL,"connect", "[connect-id [initstr] [address port]\topen a new connection", cmd_connect,NULL}, + {NULL,"cpu", "\t\t\t\tshow CPU time used by powwow", cmd_cpu,NULL}, + {NULL,"delim", "[normal|program|{custom [chars]}]\n\t\t\t\tset word completion delimeters", cmd_delim,NULL}, + {NULL,"do", "(expr) command\t\trepeat `command' (expr) times", cmd_do,NULL}, + {NULL,"edit", "\t\t\t\tlist editing sessions", cmd_edit,NULL}, + {NULL,"emulate", "[<|!]{text|(expr)}\tprocess result as if received from host", cmd_emulate,NULL}, + {NULL,"exe", "[<|!]{text|(string-expr)}\texecute result as if typed from keyboard", cmd_exe,NULL}, + {NULL,"file", "[=[filename]]\t\tset/show powwow definition file", cmd_file,NULL}, + {NULL,"for", "([init];check;[loop]) command\twhile `check' is true exec `command'", cmd_for,NULL}, + {NULL,"group", "[name] [on|off|list]\tgroup alias/action manipulation'", cmd_group,NULL}, + {NULL,"hilite", "[attr]\t\t\thighlight your input line", cmd_hilite,NULL}, + {NULL,"history", "[{number|(expr)}]\tlist/execute commands in history", cmd_history,NULL}, + {NULL,"host", "[hostname port]]\tset/show address of default host", cmd_host,NULL}, + {NULL,"identify", "[startact [endact]]\tsend MUME client identification", cmd_identify,NULL}, + {NULL,"if", "(expr) instr1 [; #else instr2]\tif `expr' is true execute `instr1'\n\t\t\t\totherwise execute `instr2'", cmd_if,NULL}, + {NULL,"in", "[label [(delay) [command]]]\tdelete/list/define delayed labels", cmd_in,NULL}, + {NULL,"init", "[=[command]]\t\tdefine command to execute on connect to host", cmd_init,NULL}, + {NULL,"isprompt", "\t\t\trecognize a prompt as such", cmd_isprompt,NULL}, + {NULL,"key", "name\t\t\texecute the `name' key binding", cmd_key,NULL}, + {NULL,"keyedit", "editing-name\t\trun a line-editing function", cmd_keyedit,NULL}, + {NULL,"load", "[filename]\t\tload powwow settings from file", cmd_load,NULL}, + {NULL,"module","[filename]\t\tload shared library extension", cmd_module,NULL}, + {NULL,"map", "[-[number]|walksequence]\tshow/clear/edit (auto)map", cmd_map,NULL}, + {NULL,"mark", "[string[=[attr]]]\t\tdelete/list/define markers", cmd_mark,NULL}, + {NULL,"movie", "[filename]\t\tbegin/end of movie record to file", cmd_movie,NULL}, + {NULL,"net", "\t\t\t\tprint amount of data received from/sent to host", cmd_net,NULL}, + {NULL,"nice", "[{number|(expr)}[command]]\tset/show priority of new actions/marks", cmd_nice,NULL}, + {NULL,"option", "[[+|-|=]name]\t\tturn various options", cmd_option,NULL}, + {NULL,"prefix", "string\t\t\tprefix all lines with string", cmd_prefix,NULL}, + {NULL,"", "(expr)\t\t\tevaluate expression, trashing result", cmd_eval,NULL}, + {NULL,"print", "[<|!][text|(expr)]\tprint text/result on screen, appending a \\n\n\t\t\t\tif no argument, prints value of variable $0", cmd_print,NULL}, + {NULL,"prompt", "[[<|=|>|%][+|-]name] [{pattern|(expression)} [=[prompt-command]]]\n\t\t\t\tdelete/list/define actions on prompts", cmd_prompt,NULL}, + {NULL,"put", "{text|(expr)}\t\tput text/result of expression in history", cmd_put,NULL}, + {NULL,"qui", "\t\t\t\tdo nothing", cmd_qui,NULL}, + {NULL,"quit", "\t\t\t\tquit powwow", cmd_quit,NULL}, + {NULL,"quote", "[on|off]\t\t\ttoggle verbatim-flag on/off", cmd_quote,NULL}, + {NULL,"rawsend", "{string|(expr)}\t\tsend raw data to the MUD", cmd_rawsend,NULL}, + {NULL,"rawprint", "{string|(expr)}\t\tsend raw data to the screen", cmd_rawprint,NULL}, + {NULL,"rebind", "name [seq]\t\tchange sequence of a key binding", cmd_rebind,NULL}, + {NULL,"rebindall", "\t\t\trebind all key bindings", cmd_rebindall,NULL}, + {NULL,"rebindALL", "\t\t\trebind ALL key bindings, even trivial ones", cmd_rebindALL,NULL}, + {NULL,"record", "[filename]\t\tbegin/end of record to file", cmd_record,NULL}, + {NULL,"request", "[editor][prompt][all]\tsend various identification strings", cmd_request,NULL}, + {NULL,"reset", "<list-name>\t\tclear the whole defined list and reload default", cmd_reset,NULL}, + {NULL,"retrace", "[number]\t\tretrace the last number steps", cmd_retrace,NULL}, + {NULL,"save", "[filename]\t\tsave powwow settings to file", cmd_save,NULL}, + {NULL,"send", "[<|!]{text|(expr)}\teval expression, sending result to the MUD", cmd_send,NULL}, + {NULL,"setvar", "name[=text|(expr)]\tset/show internal limits and variables", cmd_setvar,NULL}, + {NULL,"snoop", "connect-id\t\ttoggle output display for connections", cmd_snoop,NULL}, + {NULL,"spawn", "connect-id command\ttalk with a shell command", cmd_spawn,NULL}, + {NULL,"stop", "\t\t\t\tremove all delayed commands from active list", cmd_stop,NULL}, + {NULL,"time", "\t\t\t\tprint current time and date", cmd_time,NULL}, + {NULL,"var", "variable [= [<|!]{string|(expr)} ]\twrite result into the variable", cmd_var,NULL}, + {NULL,"ver", "\t\t\t\tshow powwow version", cmd_ver,NULL}, + {NULL,"while", "(expr) instr\t\twhile `expr' is true execute `instr'", cmd_while,NULL}, + {NULL,"write", "[>|!](expr;name)\t\twrite result of expr to `name' file", cmd_write,NULL}, + {NULL,"zap", "connect-id\t\t\tclose a connection", cmd_zap,NULL}, + {NULL,(char *)0, (char *)0, (function_str)0,NULL} +}; + +char *_cmd_sort_name( cmdstruct *cmd ) { + if( cmd -> sortname == NULL ) + return( cmd -> name ); + else + return( cmd -> sortname ); +} + +/* Adds a cmd to commands (inserts the ptr in the list, DO NOT FREE IT) */ +void cmd_add_command( cmdstruct *cmd ) { + /* do insert/sort */ + cmdstruct *c = commands; + + /* + * make sure it doesn't override another commmand + * this is important not just because it'd be irritating, + * but if a module defined the command in the global static + * space, it would create an infinite loop because the -> next + * ptr would point at itself + * + * doing it up front because based on the sortname, we may never see + * the dup item if we do it at sort time + */ + for( c = commands; c != NULL; c = c -> next ) { + if( strcmp( cmd -> name, c -> name ) == 0 ) { + PRINTF( "#error %s is already defined\n", c -> name ); + return; + } + } + + + /* catch insertion to head of list */ + if( commands == NULL ) { + /* no commands yet */ + commands = cmd; + cmd -> next = NULL; + return; + } + + if( strcmp( _cmd_sort_name( commands ), _cmd_sort_name( cmd ) ) > 0 ) { + /* this is lower in sort than every item, so + * make it the head of the list */ + cmd -> next = commands; + commands = cmd; + return; + } + + for( c = commands; c != NULL; c = c -> next ) { + if( strcmp( _cmd_sort_name( cmd ), _cmd_sort_name( c ) ) >= 0 ) { + /* Need second check to handle empty string case */ + if( c -> next == NULL || strcmp( _cmd_sort_name( cmd ), _cmd_sort_name( c -> next ) ) <= 0 ) { + /*PRINTF( "Inserting %s after %s\n", cmd -> name, c -> name ); */ + + /* insert after this one, it is greater than this + * entry but less than the next */ + cmd -> next = c -> next; + c -> next = cmd; + return; + } + } + } + + PRINTF( "ERROR INSERTING COMMAND\n" ); +} + +/* Init the command listing, called from main */ +void _cmd_init() { + int i; + + /* Now add the default command list */ + for( i = 0; default_commands[ i ].name; i++ ) + cmd_add_command( &default_commands[ i ] ); +} + +static void cmd_module __P1 (char *,arg) { + char libname[1024]; + void *lib; + void (*func)(); + + arg = skipspace(arg); + + bzero( libname, 1024 ); + if( *arg == '.' || *arg == '/' ) { + /* No path mungling */ + strncpy( libname, arg, 1024 ); + }else{ + snprintf( libname, 1024, "/usr/local/lib/powwow/%s", arg ); + } + + /* open lib */ + lib = dlopen( libname, RTLD_LAZY ); + if( ! lib ) { + PRINTF( "#lib error: %s\n", dlerror() ); + return; + } + + func = dlsym( lib, "powwow_init" ); + if( func ) { + (*func)(); + }else{ + PRINTF( "#lib error: %s\n", dlerror() ); + } +} + +static void cmd_group __P1 (char *,arg) { + char *group; + int active; + aliasnode *p; + actionnode *a; + + arg = skipspace(arg); + + if( *arg ) { + arg = first_regular( group = arg, ' '); + *arg = '\0'; + arg = skipspace( arg + 1 ); + + if( strcmp( arg, "on" ) == 0 ) { + active = 1; + }else if( strcmp( arg, "off" ) == 0 ) { + active = 0; + }else if( strcmp( arg, "list" ) == 0 ) { + PRINTF( "#not implemented\n" ); + return; + }else{ + PRINTF( "#unknown group command, use off/on/list\n" ); + return; + } + + /* Now loop over all aliases/actions by groupname and toggle */ + for( p = sortedaliases; p; p = p -> snext ) { + if( p -> group && strcmp( p -> group, group ) == 0 ) { + p -> active = active; + } + } + + /* Same for actions */ + for( a = actions; a; a = a -> next ) { + if( a -> group && strcmp( a -> group, group ) == 0 ) { + a -> active = active; + } + } + }else{ + PRINTF( "#group name required\n" ); + } +} + +static void cmd_help __P1 (char *,arg) +{ + int i, size; + char *text, *tmp; + FILE *f; + char line[BUFSIZE]; + int len; + cmdstruct *c; + + arg = skipspace(arg); + if (*arg == '#') arg++; + if (!*arg) { + size = 25; + for( c = commands; c != NULL; c = c -> next ) + size += strlen(c -> name) + strlen(c -> help) + 5; + + text = tmp = (char *)malloc(size); + if (!text) { + errmsg("malloc"); + return; + } + + /* do not use sprintf() return value, almost every OS returns a different thing. */ + sprintf(tmp, "#help\n#commands available:\n"); + tmp += strlen(tmp); + + for( c = commands; c != NULL; c = c -> next ) { + sprintf(tmp, "#%s %s\n", c -> name, c -> help); + tmp += strlen(tmp); + } + + message_edit(text, strlen(text), 1, 1); + return; + } + + if (!strncmp(arg, "copyright", strlen(arg))) { + int fd, left, got = 0; + struct stat stbuf; + + if (stat(copyfile, &stbuf) < 0) { + errmsg("stat(copyright file)"); + return; + } + + if (!(text = (char *)malloc(left = stbuf.st_size))) { + errmsg("malloc"); + return; + } + if ((fd = open(copyfile, O_RDONLY)) < 0) { + errmsg("open(copyright file)"); + free(text); + return; + } + while (left > 0) { + while ((i = read(fd, text + got, left)) < 0 && errno == EINTR) + ; + if (i < 0 && errno == EINTR) { + errmsg("read (copyright file)"); + free(text); + close(fd); + return; + } + if (i == 0) + break; + left -= i, got += i; + } + close(fd); + message_edit(text, strlen(text), 1, 1); + return; + } + + /* !copyright */ + + f = fopen(helpfile, "r"); + if (!f) { + PRINTF("#cannot open help file `%s': %s\n", + helpfile, strerror(errno)); + return; + } + + while ((tmp = fgets(line, BUFSIZE, f)) && + (line[0] != '@' || strncmp(line + 1, arg, strlen(arg)))) + ; + + if (!tmp) { + PRINTF("#no entry for `%s' in the help file.\n", arg); + fclose(f); + return; + } + + if (!(text = (char *)malloc(size = BUFSIZE))) { + errmsg("malloc"); + fclose(f); + return; + } + + memcpy(text, line, i = strlen(line)); + + while (fgets(line, BUFSIZE, f) && line[0] == '@') + ; /* allow multiple commands to share the same help */ + + do { + if ((len = strlen(line)) >= size - i) { + /* Not enough space in current buffer */ + + if (!(tmp = (char *)malloc(size += BUFSIZE))) { + errmsg("malloc"); + free(text); + fclose(f); + return; + } else { + memcpy(tmp, text, i); + free(text); + text = tmp; + } + } + memcpy(text + i, line, len); + i += len; + } while (fgets(line, BUFSIZE, f) && line[0] != '@'); + + fclose(f); + text[i] = '\0'; /* safe, there is space */ + message_edit(text, strlen(text), 1, 1); +} + +static void cmd_clear __P1 (char *,arg) +{ + if (line_status == 0) { + clear_input_line(opt_compact); + if (!opt_compact) { + tty_putc('\n'); + col0 = 0; + } + status(1); + } +} + +#ifndef NO_SHELL +static void cmd_shell __P1 (char *,arg) +{ + if (!*arg) { + if (echo_int) { + PRINTF("#that's easy.\n"); + } + } else { + tty_quit(); + + system(arg); + + tty_start(); + tty_gotoxy(col0 = 0, line0 = lines -1); + tty_puts(tty_clreoln); + } +} +#endif + +static void cmd_alias __P1 (char *,arg) +{ + arg = skipspace(arg); + if (!*arg) + show_aliases(); + else + parse_alias(arg); +} + +static void cmd_action __P1 (char *,arg) +{ + arg = skipspace(arg); + if (!*arg) + show_actions(); + else + parse_action(arg, 0); +} + +static void cmd_prompt __P1 (char *,arg) +{ + arg = skipspace(arg); + if (!*arg) + show_prompts(); + else + parse_action(arg, 1); +} + +static void cmd_beep __P1 (char *,arg) +{ + tty_putc('\007'); +} + +/* + * create/list/edit/delete bindings + */ +static void cmd_bind __P1 (char *,arg) +{ + arg = skipspace(arg); + if (!*arg) + show_binds(0); + else if (!strcmp(arg, "edit")) + show_binds(1); + else + parse_bind(arg); +} + +static void cmd_delim __P1 (char *,arg) +{ + char buf[BUFSIZE]; + int n; + + arg = skipspace(arg); + if (!*arg) { + PRINTF("#delim: `%s' (%s)\n", delim_name[delim_mode], DELIM); + return; + } + + arg = split_first_word(buf, BUFSIZE, arg); + n = 0; + while (n < DELIM_MODES && strncmp(delim_name[n], buf, strlen(buf)) != 0) + n++; + + if (n >= DELIM_MODES) { + PRINTF("#delim [normal|program|{custom <chars>}\n"); + return; + } + + if (n == DELIM_CUSTOM) { + if (!strchr(arg, ' ')) { + my_strncpy(buf+1, arg, BUFSIZE-2); + *buf = ' '; /* force ' ' in the delims */ + arg = buf; + } + unescape(arg); + set_custom_delimeters(arg); + } else + delim_mode = n; +} + +static void cmd_do __P1 (char *,arg) +{ + int type; + long result; + + arg = skipspace(arg); + if (*arg != '(') { + PRINTF("#do: "); + print_error(error=MISMATCH_PAREN_ERROR); + return; + } + arg++; + + type = evall(&result, &arg); + if (REAL_ERROR) return; + + if (type != TYPE_NUM) { + PRINTF("#do: "); + print_error(error=NO_NUM_VALUE_ERROR); + return; + } + + if (*arg == ')') { /* skip the ')' */ + if (*++arg == ' ') + arg++; + } + else { + PRINTF("#do: "); + print_error(error=MISSING_PAREN_ERROR); + return; + } + + if (result >= 0) + while (!error && result--) + (void)parse_instruction(arg, 1, 0, 1); + else { + PRINTF("#do: bogus repeat count `%ld'\n", result); + } +} + +static void cmd_hilite __P1 (char *,arg) +{ + int attr; + + arg = skipspace(arg); + attr = parse_attributes(arg); + if (attr == -1) { + PRINTF("#attribute syntax error.\n"); + if (echo_int) + show_attr_syntax(); + } else { + attr_string(attr, edattrbeg, edattrend); + + edattrbg = ATTR(attr) & ATTR_INVERSE ? 1 + : BACKGROUND(attr) != NO_COLOR || ATTR(attr) & ATTR_BLINK; + + if (echo_int) { + PRINTF("#input highlighting is now %so%s%s.\n", + edattrbeg, (attr == NOATTRCODE) ? "ff" : "n", + edattrend); + } + } +} + +static void cmd_history __P1 (char *,arg) +{ + int num = 0; + long buf; + + arg = skipspace(arg); + + if (history_done >= MAX_HIST) { + print_error(error=HISTORY_RECURSION_ERROR); + return; + } + history_done++; + + if (*arg == '(') { + arg++; + num = evall(&buf, &arg); + if (!REAL_ERROR && num != TYPE_NUM) + error=NO_NUM_VALUE_ERROR; + if (REAL_ERROR) { + PRINTF("#history: "); + print_error(error=NO_NUM_VALUE_ERROR); + return; + } + num = (int)buf; + } else + num = atoi(arg); + + if (num > 0) + exe_history(num); + else + show_history(-num); +} + +static void cmd_host __P1 (char *,arg) +{ + char newhost[BUFSIZE]; + + arg = skipspace(arg); + if (*arg) { + arg = split_first_word(newhost, BUFSIZE, arg); + if (*arg) { + my_strncpy(hostname, newhost, BUFSIZE-1); + portnumber = atoi(arg); + if (echo_int) { + PRINTF("#host set to: %s %d\n", hostname, portnumber); + } + } else { + PRINTF("#host: missing portnumber.\n"); + } + } else if (*hostname) + sprintf(inserted_next, "#host %.*s %d", BUFSIZE-INTLEN-8, + hostname, portnumber); + else { + PRINTF("#syntax: #host hostname port\n"); + } +} + +static void cmd_request __P1 (char *,arg) +{ + char *idprompt = "~$#EP2\nG\n"; + char *ideditor = "~$#EI\n"; + char buf[256]; + int all, len; + + if (tcp_fd == -1) { + PRINTF("#not connected to a MUD!\n"); + return; + } + while (*(arg = skipspace(arg))) { + arg = split_first_word(buf, 256, arg); + if (*buf) { + all = !strcmp(buf, "all"); + len = strlen(buf); + if ((all || !strncmp(buf, "editor", len))) { + tcp_raw_write(tcp_fd, ideditor, strlen(ideditor)); + CONN_LIST(tcp_fd).flags |= IDEDITOR; + if (echo_int) { + PRINTF("#request editor: %s done!\n", ideditor); + } + } + if ((all || !strncmp(buf, "prompt", len))) { + tcp_raw_write(tcp_fd, idprompt, strlen(idprompt)); + CONN_LIST(tcp_fd).flags |= IDPROMPT; + if (echo_int) { + PRINTF("#request prompt: %s done!\n", idprompt); + } + } + } + } + +} + +static void cmd_identify __P1 (char *,arg) +{ + edit_start[0] = edit_end[0] = '\0'; + if (*arg) { + char *p = strchr(arg, ' '); + if (p) { + *(p++) = '\0'; + my_strncpy(edit_end, p, BUFSIZE-1); + } + my_strncpy(edit_start, arg, BUFSIZE-1); + } + cmd_request("editor"); +} + +static void cmd_in __P1 (char *,arg) +{ + char *name; + long millisec, buf; + int type; + delaynode **p; + + arg = skipspace(arg); + if (!*arg) { + show_delays(); + return; + } + + arg = first_regular(name = arg, ' '); + if (*arg) + *arg++ = 0; + + unescape(name); + + p = lookup_delay(name, 0); + if (!*p) p = lookup_delay(name, 1); + + if (!*arg && !*p) { + PRINTF("#unknown delay label, cannot show: `%s'\n", name); + return; + } + if (!*arg) { + show_delaynode(*p, 1); + return; + } + if (*arg != '(') { + PRINTF("#in: "); + print_error(error=MISMATCH_PAREN_ERROR); + return; + } + arg++; /* skip the '(' */ + + type = evall(&buf, &arg); + if (!REAL_ERROR) { + if (type!=TYPE_NUM) + error=NO_NUM_VALUE_ERROR; + else if (*arg != ')') + error=MISSING_PAREN_ERROR; + } + if (REAL_ERROR) { + PRINTF("#in: "); + print_error(error); + return; + } + + arg = skipspace(arg+1); + millisec = buf; + if (*p && millisec) + change_delaynode(p, arg, millisec); + else if (!*p && millisec) { + if (*arg) + new_delaynode(name, arg, millisec); + else { + PRINTF("#cannot create delay label without a command.\n"); + } + } else if (*p && !millisec) { + if (echo_int) { + PRINTF("#deleting delay label: %s %s\n", name, (*p)->command); + } + delete_delaynode(p); + } else { + PRINTF("#unknown delay label, cannot delete: `%s'\n", name); + } +} + +static void cmd_at __P1 (char *,arg) +{ + char *name, *buf = NULL; + char dayflag=0; + struct tm *twhen; + int num, hour = -1, minute = -1, second = -1; + delaynode **p; + long millisec; + ptr pbuf = (ptr)0; + + arg = skipspace(arg); + if (!*arg) { + show_delays(); + return; + } + + arg = first_regular(name = arg, ' '); + if (*arg) + *arg++ = 0; + + unescape(name); + + p = lookup_delay(name, 0); + if (!*p) p = lookup_delay(name, 1); + + if (!*arg && !*p) { + PRINTF("#unknown delay label, cannot show: `%s'\n", name); + return; + } + if (!*arg) { + show_delaynode(*p, 2); + return; + } + if (*arg != '(') { + PRINTF("#in: "); + print_error(error=MISMATCH_PAREN_ERROR); + return; + } + arg++; /* skip the '(' */ + + (void)evalp(&pbuf, &arg); + if (REAL_ERROR) { + print_error(error); + ptrdel(pbuf); + return; + } + if (pbuf) { + /* convert time-string into hour, minute, second */ + buf = skipspace(ptrdata(pbuf)); + if (!*buf || !isdigit(*buf)) { + PRINTF("#at: "); + print_error(error=NO_NUM_VALUE_ERROR); + ptrdel(pbuf); + return; + } + num = atoi(buf); + second = num % 100; + minute = (num /= 100) % 100; + hour = num / 100; + } + if (hour < 0 || hour>23 || minute < 0 || minute>59 + || second < 0 || second>59) { + + PRINTF("#at: #error: invalid time `%s'\n", + pbuf && buf ? buf : (char *)""); + error=OUT_RANGE_ERROR; + ptrdel(pbuf); + return; + } + ptrdel(pbuf); + + if (*arg == ')') { /* skip the ')' */ + if (*++arg == ' ') + arg++; + } + else { + PRINTF("#at: "); + print_error(error=MISSING_PAREN_ERROR); + return; + } + + arg = skipspace(arg); + update_now(); + twhen = localtime((time_t *)&now.tv_sec); + /* put current year, month, day in calendar struct */ + + if (hour < twhen->tm_hour || + (hour == twhen->tm_hour && + (minute < twhen->tm_min || + (minute == twhen->tm_min && + second <= twhen->tm_sec)))) { + dayflag = 1; + /* it is NOT possible to define an #at refering to the past */ + } + + /* if you use a time smaller than the current, it refers to tomorrow */ + + millisec = (hour - twhen->tm_hour) * 3600 + (minute - twhen->tm_min) * 60 + + second - twhen->tm_sec + (dayflag ? 24*60*60 : 0); + millisec *= mSEC_PER_SEC; /* Comparing time with current calendar, + we finally got the delay */ + millisec -= now.tv_usec / uSEC_PER_mSEC; + + if (*p) + change_delaynode(p, arg, millisec); + else + if (*arg) + new_delaynode(name, arg, millisec); + else { + PRINTF("#cannot create delay label without a command.\n"); + } +} + +static void cmd_init __P1 (char *,arg) +{ + arg = skipspace(arg); + + if (*arg == '=') { + if (*++arg) { + my_strncpy(initstr, arg, BUFSIZE-1); + if (echo_int) { + PRINTF("#init: %s\n", initstr); + } + } else { + *initstr = '\0'; + if (echo_int) { + PRINTF("#init cleared.\n"); + } + } + } else + sprintf(inserted_next, "#init =%.*s", BUFSIZE-8, initstr); +} + +static void cmd_isprompt __P1 (char *,arg) +{ + if (tcp_fd == tcp_main_fd) { + int i; + long l; + arg = skipspace(arg); + if (*arg == '(') { + arg++; + i = evall(&l, &arg); + if (!REAL_ERROR) { + if (i!=TYPE_NUM) + error=NO_NUM_VALUE_ERROR; + else if (*arg != ')') + error=MISSING_PAREN_ERROR; + } + if (REAL_ERROR) { + PRINTF("#isprompt: "); + print_error(error); + return; + } + i = (int)l; + } else + i = atoi(arg); + + if (i == 0) + surely_isprompt = -1; + else if (i < 0) { + if (i > -NUMPARAM && *VAR[-i].str) + ptrtrunc(prompt->str, surely_isprompt = ptrlen(*VAR[-i].str)); + } else + ptrtrunc(prompt->str, surely_isprompt = i); + } +} + +static void cmd_key __P1 (char *,arg) +{ + keynode *q=NULL; + + arg = skipspace(arg); + if (!*arg) + return; + + if ((q = *lookup_key(arg))) + q->funct(q->call_data); + else { + PRINTF("#no such key: `%s'\n", arg); + } +} + +static void cmd_keyedit __P1 (char *,arg) +{ + int function; + char *param; + + arg = skipspace(arg); + if (!*arg) + return; + + if ((function = lookup_edit_name(arg, ¶m))) + internal_functions[function].funct(param); + else { + PRINTF("#no such editing function: `%s'\n", arg); + } +} + +static void cmd_map __P1 (char *,arg) +{ + arg = skipspace(arg); + if (!*arg) /* show map */ + map_show(); + else if (*arg == '-') /* retrace steps without walking */ + map_retrace(atoi(arg + 1), 0); + else + map_walk(arg, 1, 1); +} + +static void cmd_retrace __P1 (char *,arg) +{ + map_retrace(atoi(arg), 1); +} + +static void cmd_mark __P1 (char *,arg) +{ + if (!*arg) + show_marks(); + else + parse_mark(arg); +} + +static void cmd_nice __P1 (char *,arg) +{ + int nnice = a_nice; + arg = skipspace(arg); + if (!*arg) { + PRINTF("#nice: %d\n", a_nice); + return; + } + if (isdigit(*arg)) { + a_nice = 0; + while (isdigit(*arg)) { + a_nice *= 10; + a_nice += *arg++ - '0'; + } + } + else if (*arg++=='(') { + long buf; + int type; + + type = evall(&buf, &arg); + if (!REAL_ERROR && type!=TYPE_NUM) + error=NO_NUM_VALUE_ERROR; + else if (!REAL_ERROR && *arg++ != ')') + error=MISSING_PAREN_ERROR; + if (REAL_ERROR) { + PRINTF("#nice: "); + print_error(error); + return; + } + a_nice = (int)buf; + if (a_nice<0) + a_nice = 0; + } + arg = skipspace(arg); + if (*arg) { + parse_instruction(arg, 0, 0, 1); + a_nice = nnice; + } +} + +static void cmd_prefix __P1 (char *,arg) +{ + strcpy(prefixstr, arg); + if (echo_int) { + PRINTF("#prefix %s.\n", *arg ? "set" : "cleared"); + } +} + +static void cmd_quote __P1 (char *,arg) +{ + arg = skipspace(arg); + if (!*arg) + verbatim ^= 1; + else if (!strcmp(arg, "on")) + verbatim = 1; + else if (!strcmp(arg, "off")) + verbatim = 0; + if (echo_int) { + PRINTF("#%s mode.\n", verbatim ? "verbatim" : "normal"); + } +} + +/* + * change the escape sequence of an existing binding + */ +static void cmd_rebind __P1 (char *,arg) +{ + parse_rebind(arg); +} + +static void cmd_rebindall __P1 (char *,arg) +{ + keynode *kp; + char *seq; + + for (kp = keydefs; kp; kp = kp->next) { + seq = kp->sequence; + if (kp->seqlen == 1 && seq[0] < ' ') + ; + else if (kp->seqlen == 2 && seq[0] == '\033' && isalnum(seq[1])) + ; + else { + parse_rebind(kp->name); + if (error) + break; + } + } +} + +static void cmd_rebindALL __P1 (char *,arg) +{ + keynode *kp; + + for (kp = keydefs; kp; kp = kp->next) { + parse_rebind(kp->name); + if (error) + break; + } +} + +static void cmd_reset __P1 (char *,arg) +{ + char all = 0; + arg = skipspace(arg); + if (!*arg) { + PRINTF("#reset: must specify one of:\n"); + tty_puts(" alias, action, bind, in (or at), mark, prompt, var, all.\n"); + return; + } + all = !strcmp(arg, "all"); + if (all || !strcmp(arg, "alias")) { + int n; + for (n = 0; n < MAX_HASH; n++) { + while (aliases[n]) + delete_aliasnode(&aliases[n]); + } + if (!all) + return; + } + if (all || !strcmp(arg, "action")) { + while (actions) + delete_actionnode(&actions); + if (!all) + return; + } + if (all || !strcmp(arg, "bind")) { + while (keydefs) + delete_keynode(&keydefs); + tty_add_initial_binds(); + tty_add_walk_binds(); + if (!all) + return; + } + if (all || !strcmp(arg, "in") || !strcmp(arg, "at")) { + while (delays) + delete_delaynode(&delays); + while (dead_delays) + delete_delaynode(&dead_delays); + if (!all) + return; + } + if (all || !strcmp(arg, "mark")) { + while (markers) + delete_marknode(&markers); + if (!all) + return; + } + if (all || !strcmp(arg, "prompt")) { + while (prompts) + delete_promptnode(&prompts); + if (!all) + return; + } + if (all || !strcmp(arg, "var")) { + int n; + varnode **first; + + for (n = 0; n < MAX_HASH; n++) { + while (named_vars[0][n]) + delete_varnode(&named_vars[0][n], 0); + first = &named_vars[1][n]; + while (*first) { + if (is_permanent_variable(*first)) + first = &(*first)->next; + else + delete_varnode(first, 1); + } + } + + for (n = 0; n < NUMVAR; n++) { + *var[n].num = 0; + ptrdel(*var[n].str); + *var[n].str = NULL; + } + if (!all) + return; + } +} + +static void cmd_snoop __P1 (char *,arg) +{ + if (!*arg) { + PRINTF("#snoop: which connection?\n"); + } else + tcp_togglesnoop(arg); +} + +static void cmd_stop __P1 (char *,arg) +{ + delaynode *dying; + + if (delays) + update_now(); + + while (delays) { + dying = delays; + delays = dying->next; + dying->when.tv_sec = now.tv_sec; + dying->when.tv_usec = now.tv_usec; + dying->next = dead_delays; + dead_delays = dying; + } + if (echo_int) { + PRINTF("#all delayed labels are now disabled.\n"); + } +} + +static void cmd_time __P1 (char *,arg) +{ + struct tm *s; + char buf[BUFSIZE]; + + update_now(); + s = localtime((time_t *)&now.tv_sec); + (void)strftime(buf, BUFSIZE - 1, "%a, %d %b %Y %H:%M:%S", s); + PRINTF("#current time is %s\n", buf); +} + +static void cmd_ver __P1 (char *,arg) +{ + printver(); +} + +static void cmd_emulate __P1 (char *,arg) +{ + char kind; + FILE *fp; + long start, end, i = 1; + int len; + ptr pbuf = (ptr)0; + + arg = redirect(arg, &pbuf, &kind, "emulate", 0, &start, &end); + if (REAL_ERROR || !arg) + return; + + if (kind) { + char buf[BUFSIZE]; + + fp = (kind == '!') ? popen(arg, "r") : fopen(arg, "r"); + if (!fp) { + PRINTF("#emulate: #error opening `%s'\n", arg); + print_error(error=SYNTAX_ERROR); + ptrdel(pbuf); + return; + } + status(-1); /* we're pretending we got something from the MUD */ + while (!error && (!start || i<=end) && fgets(buf, BUFSIZE, fp)) + if (!start || i++>=start) + process_remote_input(buf, strlen(buf)); + + if (kind == '!') pclose(fp); else fclose(fp); + } else { + status(-1); /* idem */ + /* WARNING: no guarantee there is space! */ + arg[len = strlen(arg)] = '\n'; + arg[++len] = '\0'; + process_remote_input(arg, len); + } + ptrdel(pbuf); +} + +static void cmd_eval __P1 (char *,arg) +{ + arg = skipspace(arg); + if (*arg=='(') { + arg++; + (void)evaln(&arg); + if (*arg != ')') { + PRINTF("#(): "); + print_error(error=MISSING_PAREN_ERROR); + } + } + else { + PRINTF("#(): "); + print_error(error=MISMATCH_PAREN_ERROR); + } +} + +static void cmd_exe __P1 (char *,arg) +{ + char kind; + long start, end, i = 1; + FILE *fp; + ptr pbuf = (ptr)0; + + arg = redirect(arg, &pbuf, &kind, "exe", 0, &start, &end); + if (REAL_ERROR || !arg) + return; + + if (kind) { + char buf[BUFSIZE]; + + fp = (kind == '!') ? popen(arg, "r") : fopen(arg, "r"); + if (!fp) { + PRINTF("#exe: #error opening `%s'\n", arg); + error = SYNTAX_ERROR; + ptrdel(pbuf); + return; + } + while (!error && (!start || i<=end) && fgets(buf, BUFSIZE, fp)) + if (!start || i++>=start) { + buf[strlen(buf)-1] = '\0'; + parse_user_input(buf, 0); + } + + if (kind == '!') pclose(fp); else fclose(fp); + } else + parse_user_input(arg, 0); + ptrdel(pbuf); +} + +static void cmd_print __P1 (char *,arg) +{ + char kind; + long start, end, i = 1; + FILE *fp; + ptr pbuf = (ptr)0; + + clear_input_line(opt_compact); + + if (!*arg) { + smart_print(*VAR[0].str ? ptrdata(*VAR[0].str) : (char *)"", 1); + return; + } + + arg = redirect(arg, &pbuf, &kind, "print", 1, &start, &end); + if (REAL_ERROR || !arg) + return; + + if (kind) { + char buf[BUFSIZE]; + fp = (kind == '!') ? popen(arg, "r") : fopen(arg, "r"); + if (!fp) { + PRINTF("#print: #error opening `%s'\n", arg); + error=SYNTAX_ERROR; + ptrdel(pbuf); + return; + } + while (!error && (!start || i <= end) && fgets(buf, BUFSIZE, fp)) + if (!start || i++>=start) + tty_puts(buf); + tty_putc('\n'); + + if (kind == '!') pclose(fp); else fclose(fp); + } else + smart_print(arg, 1); + ptrdel(pbuf); +} + +static void cmd_send __P1 (char *,arg) +{ + char *newline, kind; + long start, end, i = 1; + FILE *fp; + ptr pbuf = (ptr)0; + + arg = redirect(arg, &pbuf, &kind, "send", 0, &start, &end); + if (REAL_ERROR ||!arg) + return; + + if (kind) { + char buf[BUFSIZE]; + fp = (kind == '!') ? popen(arg, "r") : fopen(arg, "r"); + if (!fp) { + PRINTF("#send: #error opening `%s'\n", arg); + error = SYNTAX_ERROR; + ptrdel(pbuf); + return; + } + while (!error && (!start || i<=end) && fgets(buf, BUFSIZE, fp)) { + if ((newline = strchr(buf, '\n'))) + *newline = '\0'; + + if (!start || i++>=start) { + if (echo_ext) { + PRINTF("[%s]\n", buf); + } + tcp_write(tcp_fd, buf); + } + } + if (kind == '!') pclose(fp); else fclose(fp); + } else { + if (echo_ext) { + PRINTF("[%s]\n", arg); + } + tcp_write(tcp_fd, arg); + } + ptrdel(pbuf); +} + +static void cmd_rawsend __P1 (char *,arg) +{ + char *tmp = skipspace(arg); + + if (*tmp=='(') { + ptr pbuf = (ptr)0; + arg = tmp + 1; + (void)evalp(&pbuf, &arg); + if (REAL_ERROR) { + print_error(error); + ptrdel(pbuf); + } else if (pbuf) + tcp_raw_write(tcp_fd, ptrdata(pbuf), ptrlen(pbuf)); + } else { + int len; + if ((len = memunescape(arg, strlen(arg)))) + tcp_raw_write(tcp_fd, arg, len); + } +} + +static void cmd_rawprint __P1 (char *,arg) +{ + char *tmp = skipspace(arg); + + if (*tmp=='(') { + ptr pbuf = (ptr)0; + arg = tmp + 1; + (void)evalp(&pbuf, &arg); + if (REAL_ERROR) { + print_error(error); + ptrdel(pbuf); + } else if (pbuf) + tty_raw_write(ptrdata(pbuf), ptrlen(pbuf)); + } else { + int len; + if ((len = memunescape(arg, strlen(arg)))) + tty_raw_write(arg, len); + } +} + + +static void cmd_write __P1 (char *,arg) +{ + ptr p1 = (ptr)0, p2 = (ptr)0; + char *tmp = skipspace(arg), kind; + FILE *fp; + + kind = *tmp; + if (kind == '!' || kind == '>') + arg = ++tmp; + else + kind = 0; + + if (*tmp=='(') { + arg = tmp + 1; + (void)evalp(&p1, &arg); + if (REAL_ERROR) + goto write_cleanup; + + if (*arg == CMDSEP) { + arg++; + (void)evalp(&p2, &arg); + if (!REAL_ERROR && !p2) + error = NO_STRING_ERROR; + if (REAL_ERROR) + goto write_cleanup; + } else { + PRINTF("#write: "); + error=SYNTAX_ERROR; + goto write_cleanup; + } + if (*arg != ')') { + PRINTF("#write: "); + error=MISSING_PAREN_ERROR; + goto write_cleanup; + } + arg = ptrdata(p2); + + fp = (kind == '!') ? popen(arg, "w") : fopen(arg, kind ? "w" : "a"); + if (!fp) { + PRINTF("#write: #error opening `%s'\n", arg); + error=SYNTAX_ERROR; + goto write_cleanup2; + } + fprintf(fp, "%s\n", p1 ? ptrdata(p1) : (char *)""); + fflush(fp); + if (kind == '!') pclose(fp); else fclose(fp); + } else { + PRINTF("#write: "); + error=MISMATCH_PAREN_ERROR; + } + +write_cleanup: + if (REAL_ERROR) + print_error(error); +write_cleanup2: + ptrdel(p1); + ptrdel(p2); +} + +static void cmd_var __P1 (char *,arg) +{ + char *buf, *expr, *tmp, kind, type, right = 0, deleting = 0; + varnode **p_named_var = NULL, *named_var = NULL; + FILE *fp; + long start, end, i = 1; + int len, idx; + ptr pbuf = (ptr)0; + + arg = skipspace(arg); + expr = first_regular(arg, '='); + + if (*expr) { + *expr++ = '\0'; /* skip the = */ + if (!*expr) + deleting = 1; + else { + right = 1; + if (*expr == ' ') + expr++; + } + } + + if (*arg == '$') + type = TYPE_TXT_VAR; + else if (*arg == '@') + type = TYPE_NUM_VAR; + else if (*arg) { + print_error(error=INVALID_NAME_ERROR); + return; + } else { + show_vars(); + return; + } + + kind = *++arg; + if (isalpha(kind) || kind == '_') { + /* found a named variable */ + tmp = arg; + while (*tmp && (isalnum(*tmp) || *tmp == '_')) + tmp++; + if (*tmp) { + print_error(error=INVALID_NAME_ERROR); + return; + } + kind = type==TYPE_TXT_VAR ? 1 : 0; + p_named_var = lookup_varnode(arg, kind); + if (!*p_named_var) { + /* it doesn't (yet) exist */ + if (!deleting) { + /* so create it */ + named_var = add_varnode(arg, kind); + if (REAL_ERROR) + return; + if (echo_int) { + PRINTF("#new variable: `%s'\n", arg - 1); + } + } else { + print_error(error=UNDEFINED_VARIABLE_ERROR); + return; + } + } else + /* it exists, hold on */ + named_var = *p_named_var; + + idx = named_var->index; + } else { + /* not a named variable, may be + * an unnamed variable or an expression */ + kind = type==TYPE_TXT_VAR ? 1 : 0; + tmp = skipspace(arg); + if (*tmp == '(') { + /* an expression */ + arg = tmp+1; + idx = evalp(&pbuf, &arg); + if (!REAL_ERROR && idx != TYPE_TXT) + error=NO_STRING_ERROR; + if (REAL_ERROR) { + PRINTF("#var: "); + print_error(error); + ptrdel(pbuf); + return; + } + if (pbuf) + buf = ptrdata(pbuf); + else + buf = ""; + if (isdigit(*buf)) { + idx = atoi(buf); + if (idx < -NUMVAR || idx >= NUMPARAM) { + print_error(error=OUT_RANGE_ERROR); + ptrdel(pbuf); + return; + } + } else { + if (!(named_var = *lookup_varnode(buf, kind))) { + if (!deleting) { + named_var = add_varnode(buf, kind); + if (REAL_ERROR) { + print_error(error); + ptrdel(pbuf); + return; + } + if (echo_int) { + PRINTF("#new variable: %c%s\n", kind + ? '$' : '@', buf); + } + } else { + print_error(error=UNDEFINED_VARIABLE_ERROR); + ptrdel(pbuf); + return; + } + } + idx = named_var->index; + } + } else { + /* an unnamed var */ + long buf2; + + idx = evall(&buf2, &arg); + if (!REAL_ERROR && idx != TYPE_NUM) + error=NO_STRING_ERROR; + if (REAL_ERROR) { + PRINTF("#var: "); + print_error(error); + return; + } + idx = (int)buf2; + if (idx < -NUMVAR || idx >= NUMPARAM) { + print_error(error=OUT_RANGE_ERROR); + return; + } + /* ok, it's an unnamed var */ + } + } + + + if (type == TYPE_TXT_VAR && right && !*VAR[idx].str) { + /* create it */ + *VAR[idx].str = ptrnew(PARAMLEN); + if (MEM_ERROR) { + print_error(error); + ptrdel(pbuf); + return; + } + } + + if (deleting) { + /* R.I.P. named variables */ + if (named_var) { + if (is_permanent_variable(named_var)) { + PRINTF("#cannot delete variable: `%s'\n", arg - 1); + } else { + delete_varnode(p_named_var, kind); + if (echo_int) { + PRINTF("#deleted variable: `%s'\n", arg - 1); + } + } + } else if ((type = TYPE_TXT_VAR)) { + /* R.I.P. unnamed variables */ + if (*VAR[idx].str) { + if (idx < 0) { + ptrdel(*VAR[idx].str); + *VAR[idx].str = 0; + } else + ptrzero(*VAR[idx].str); + } + } else + *VAR[idx].num = 0; + ptrdel(pbuf); + return; + } else if (!right) { + /* no right-hand expression, just show */ + if (named_var) { + if (type == TYPE_TXT_VAR) { + pbuf = ptrescape(pbuf, *VAR[idx].str, 0); + if (REAL_ERROR) { + print_error(error); + ptrdel(pbuf); + return; + } + sprintf(inserted_next, "#($%.*s = \"%.*s\")", + BUFSIZE - 10, named_var->name, + BUFSIZE - (int)strlen(named_var->name) - 10, + pbuf ? ptrdata(pbuf) : (char *)""); + } else { + sprintf(inserted_next, "#(@%.*s = %ld)", + BUFSIZE - 8, named_var->name, + *VAR[idx].num); + } + } else { + if (type == TYPE_TXT_VAR) { + pbuf = ptrescape(pbuf, *VAR[idx].str, 0); + sprintf(inserted_next, "#($%d = \"%.*s\")", idx, + BUFSIZE - INTLEN - 10, + pbuf ? ptrdata(pbuf) : (char *)""); + } else { + sprintf(inserted_next, "#(@%d = %ld)", idx, + *VAR[idx].num); + } + } + ptrdel(pbuf); + return; + } + + /* only case left: assign a value to a variable */ + arg = redirect(expr, &pbuf, &kind, "var", 1, &start, &end); + if (REAL_ERROR || !arg) + return; + + if (kind) { + char buf2[BUFSIZE]; + fp = (kind == '!') ? popen(arg, "r") : fopen(arg, "r"); + if (!fp) { + PRINTF("#var: #error opening `%s'\n", arg); + error=SYNTAX_ERROR; + ptrdel(pbuf); + return; + } + len = 0; + i = 1; + while (!error && (!start || i<=end) && fgets(buf2+len, BUFSIZE-len, fp)) + if (!start || i++>=start) + len += strlen(buf2 + len); + + if (kind == '!') pclose(fp); else fclose(fp); + if (len>PARAMLEN) + len = PARAMLEN; + buf2[len] = '\0'; + arg = buf2; + } + + if (type == TYPE_NUM_VAR) { + arg = skipspace(arg); + type = 1; + len = 0; + + if (*arg == '-') + arg++, type = -1; + else if (*arg == '+') + arg++; + + if (isdigit(kind=*arg)) while (isdigit(kind)) { + len*=10; + len+=(kind-'0'); + kind=*++arg; + } + else { + PRINTF("#var: "); + print_error(error=NO_NUM_VALUE_ERROR); + } + *VAR[idx].num = len * type; + } + else { + *VAR[idx].str = ptrmcpy(*VAR[idx].str, arg, strlen(arg)); + if (MEM_ERROR) + print_error(error); + } + ptrdel(pbuf); +} + +static void cmd_setvar __P1 (char *,arg) +{ + char *name; + int i, func = 0; /* show */ + long buf; + + name = arg = skipspace(arg); + arg = first_regular(arg, '='); + if (*arg) { + *arg++ = '\0'; + if (*arg) { + func = 1; /* set */ + if (*arg == '(') { + arg++; + i = evall(&buf, &arg); + if (!REAL_ERROR && i != TYPE_NUM) + error=NO_NUM_VALUE_ERROR; + else if (!REAL_ERROR && *arg != ')') + error=MISSING_PAREN_ERROR; + } else + buf = strtol(arg, NULL, 0); + } else + buf = 0; + + if (REAL_ERROR) { + PRINTF("#setvar: "); + print_error(error); + return; + } + } + + i = strlen(name); + if (i && !strncmp(name, "timer", i)) { + vtime t; + update_now(); + if (func == 0) + sprintf(inserted_next, "#setvar timer=%ld", + diff_vtime(&now, &ref_time)); + else { + t.tv_usec = ((-buf) % mSEC_PER_SEC) * uSEC_PER_mSEC; + t.tv_sec = (-buf) / mSEC_PER_SEC; + ref_time.tv_usec = now.tv_usec; + ref_time.tv_sec = now.tv_sec; + add_vtime(&ref_time, &t); + } + } + else if (i && !strncmp(name, "lines", i)) { + if (func == 0) + sprintf(inserted_next, "#setvar lines=%d", lines); + else { + if (buf > 0) + lines = (int)buf; + if (echo_int) { + PRINTF("#setvar: lines=%d\n", lines); + } + } + } + else if (i && !strncmp(name, "mem", i)) { + if (func == 0) + sprintf(inserted_next, "#setvar mem=%d", limit_mem); + else { + if (buf == 0 || buf >= PARAMLEN) + limit_mem = buf <= INT_MAX ? (int)buf : INT_MAX; + if (echo_int) { + PRINTF("#setvar: mem=%d%s\n", limit_mem, + limit_mem ? "" : " (unlimited)"); + } + } + } + else if (i && !strncmp(name, "buffer", i)) { + if (func == 0) + sprintf(inserted_next, "#setvar buffer=%d", log_getsize()); + else + log_resize(buf); + } else { + update_now(); + PRINTF("#setvar buffer=%d\n#setvar lines=%d\n#setvar mem=%d\n#setvar timer=%ld\n", + log_getsize(), lines, limit_mem, diff_vtime(&now, &ref_time)); + } +} + +static void cmd_if __P1 (char *,arg) +{ + long buf; + int type; + + arg = skipspace(arg); + if (*arg!='(') { + PRINTF("#if: "); + print_error(error=MISMATCH_PAREN_ERROR); + return; + } + arg++; /* skip the '(' */ + + type = evall(&buf, &arg); + if (!REAL_ERROR) { + if (type!=TYPE_NUM) + error=NO_NUM_VALUE_ERROR; + if (*arg != ')') + error=MISSING_PAREN_ERROR; + else { /* skip the ')' */ + if (*++arg == ' ') + arg++; + } + } + if (REAL_ERROR) { + PRINTF("#if: "); + print_error(error); + return; + } + + if (buf) + (void)parse_instruction(arg, 0, 0, 1); + else { + arg = get_next_instr(arg); + if (!strncmp(arg = skipspace(arg), "#else ", 6)) + (void)parse_instruction(arg + 6, 0, 0, 1); + } +} + +static void cmd_for __P1 (char *,arg) +{ + int type = TYPE_NUM, loop=MAX_LOOP; + long buf; + char *check, *tmp, *increm = 0; + + arg = skipspace(arg); + if (*arg != '(') { + PRINTF("#for: "); + print_error(error=MISMATCH_PAREN_ERROR); + return; + } + push_params(); + if (REAL_ERROR) + return; + + arg = skipspace(arg + 1); /* skip the '(' */ + if (*arg != CMDSEP) + (void)evaln(&arg); /* execute <init> */ + + check = arg + 1; + + if (REAL_ERROR) + ; + else if (*arg != CMDSEP) { + PRINTF("#for: "); + print_error(error=MISSING_SEPARATOR_ERROR); + } + else while (!error && loop + && (increm=check, (type = evall(&buf, &increm)) == TYPE_NUM + && !error && *increm == CMDSEP && buf)) { + + tmp = first_regular(increm + 1, ')'); + if (*tmp) + (void)parse_instruction(tmp + 1, 1, 1, 1); + else { + PRINTF("#for: "); + print_error(error=MISSING_PAREN_ERROR); + } + + if (!error) { + tmp = increm + 1; + if (*tmp != ')') + (void)evaln(&tmp); + } + + loop--; + } + if (REAL_ERROR) + ; + else if (increm && *increm != CMDSEP) + error=MISSING_SEPARATOR_ERROR; + else if (!loop) + error=MAX_LOOP_ERROR; + else if (type != TYPE_NUM) + error=NO_NUM_VALUE_ERROR; + if (REAL_ERROR) { + PRINTF("#for: "); + print_error(error); + } + if (error!=DYN_STACK_UND_ERROR && error!=DYN_STACK_OV_ERROR) + pop_params(); +} + +static void cmd_while __P1 (char *,arg) +{ + int type = TYPE_NUM, loop=MAX_LOOP; + long buf; + char *check, *tmp; + + arg = skipspace(arg); + if (!*arg) { + PRINTF("#while: "); + print_error(error=MISMATCH_PAREN_ERROR); + return; + } + push_params(); + + check = ++arg; /* skip the '(' */ + while (!error && loop + && (arg=check, (type = evall(&buf, &arg)) == TYPE_NUM && + !error && *arg == ')' && buf)) { + + if (*(tmp = arg + 1) == ' ') /* skip the ')' */ + tmp++; + if (*tmp) + (void)parse_instruction(tmp, 1, 1, 1); + loop--; + } + if (REAL_ERROR) + ; + else if (*arg != ')') + error=MISSING_PAREN_ERROR; + else if (!loop) + error=MAX_LOOP_ERROR; + else if (type != TYPE_NUM) + error=NO_NUM_VALUE_ERROR; + if (REAL_ERROR) { + PRINTF("#while: "); + print_error(error); + } + if (error!=DYN_STACK_UND_ERROR && error!=DYN_STACK_OV_ERROR) + pop_params(); +} + +static void cmd_capture __P1 (char *,arg) +{ + arg = skipspace(arg); + + if (!*arg) { + if (capturefile) { + log_flush(); + fclose(capturefile); + capturefile = NULL; + if (echo_int) { + PRINTF("#end of capture to file.\n"); + } + } else { + PRINTF("#capture to what file?\n"); + } + } else { + if (capturefile) { + PRINTF("#capture already active.\n"); + } else { + short append = 0; + /* Append to log file, if the name starts with '>' */ + if (*arg == '>') { + arg++; + append = 1; + } + if ((capturefile = fopen(arg, (append) ? "a" : "w")) == NULL) { + PRINTF("#error writing file `%s'\n", arg); + } else if (echo_int) { + PRINTF("#capture to `%s' active, `#capture' ends.\n", arg); + } + } + } +} + +static void cmd_movie __P1 (char *,arg) +{ + arg = skipspace(arg); + + if (!*arg) { + if (moviefile) { + log_flush(); + fclose(moviefile); + moviefile = NULL; + if (echo_int) { + PRINTF("#end of movie to file.\n"); + } + } else { + PRINTF("#movie to what file?\n"); + } + } else { + if (moviefile) { + PRINTF("#movie already active.\n"); + } else { + if ((moviefile = fopen(arg, "w")) == NULL) { + PRINTF("#error writing file `%s'\n", arg); + } else { + if (echo_int) { + PRINTF("#movie to `%s' active, `#movie' ends.\n", arg); + } + update_now(); + movie_last = now; + log_clearsleep(); + } + } + } +} + +static void cmd_record __P1 (char *,arg) +{ + arg = skipspace(arg); + + if (!*arg) { + if (recordfile) { + fclose(recordfile); + recordfile = NULL; + if (echo_int) { + PRINTF("#end of record to file.\n"); + } + } else { + PRINTF("#record to what file?\n"); + } + } else { + if (recordfile) { + PRINTF("#record already active.\n"); + } else { + if ((recordfile = fopen(arg, "w")) == NULL) { + PRINTF("#error writing file `%s'\n", arg); + } else if (echo_int) { + PRINTF("#record to `%s' active, `#record' ends.\n", arg); + } + } + } +} + +static void cmd_edit __P1 (char *,arg) +{ + editsess *sp; + + if (edit_sess) { + for (sp = edit_sess; sp; sp = sp->next) { + PRINTF("# %s (%u)\n", sp->descr, sp->key); + } + } else { + PRINTF("#no active editors.\n"); + } +} + +static void cmd_cancel __P1 (char *,arg) +{ + editsess *sp; + + if (!edit_sess) { + PRINTF("#no editing sessions to cancel.\n"); + } else { + if (*arg) { + for (sp = edit_sess; sp; sp = sp->next) + if (strtoul(arg, NULL, 10) == sp->key) { + cancel_edit(sp); + break; + } + if (!sp) { + PRINTF("#unknown editing session %d\n", atoi(arg)); + } + } else { + if (edit_sess->next) { + PRINTF("#several editing sessions active, use #cancel <number>\n"); + } else + cancel_edit(edit_sess); + } + } +} + +static void cmd_net __P1 (char *,arg) +{ + PRINTF("#received from host: %ld chars, sent to host: %ld chars.\n", + received, sent); +} + + +#ifndef CLOCKS_PER_SEC +# define CLOCKS_PER_SEC uSEC_PER_SEC +#endif +/* hope it works.... */ + +static void cmd_cpu __P1 (char *,arg) +{ + float f, l; + update_now(); + f = (float)((cpu_clock = clock()) - start_clock) / (float)CLOCKS_PER_SEC; + l = (float)(diff_vtime(&now, &start_time)) / (float)mSEC_PER_SEC; + PRINTF("#CPU time used: %.3f sec. (%.2f%%)\n", f, + (l > 0 && l > f) ? f * 100.0 / l : 100.0); +} + +void show_stat __P0 (void) +{ + cmd_net(NULL); + cmd_cpu(NULL); +} + +#ifdef BUG_TELNET +static void cmd_color __P1 (char *,arg) +{ + int attrcode; + + arg = skipspace(arg); + if (!*arg) { + strcpy(tty_modenorm, tty_modenormbackup); + tty_puts(tty_modenorm); + if (echo_int) { + PRINTF("#standard color cleared.\n"); + } + return; + } + + attrcode = parse_attributes(arg); + if (attrcode == -1) { + PRINTF("#invalid attribute syntax.\n"); + if (echo_int) + show_attr_syntax(); + } else { + int bg = BACKGROUND(attrcode), fg = FOREGROUND(attrcode); + if (fg >= COLORS || bg >= COLORS) { + PRINTF("#please specify foreground and background colors.\n"); + } else { + sprintf(tty_modenorm, "\033[;%c%d;%s%dm", + fg<LOWCOLORS ? '3' : '9', fg % LOWCOLORS, + bg<LOWCOLORS ? "4" :"10", bg % LOWCOLORS); + tty_puts(tty_modenorm); + if (echo_int) { + PRINTF("#standard colour set.\n"); + } + } + } +} +#endif + +static void cmd_connect __P1 (char *,arg) +{ +#ifdef TERM + PRINTF("#connect: multiple connections not supported in term version.\n"); +#else + char *s1, *s2, *s3 = NULL, *s4 = NULL; + int argc = 1; + + if (!*skipspace(arg)) { + tcp_show(); + return; + } + else { + s1 = strtok(arg, " "); + s2 = strtok(NULL, " "); + if (s2 && *s2) { + argc++; + s3 = strtok(NULL, " "); + if (s3 && *s3) { + argc++; + s4 = strtok(NULL, " "); + if (s4 && *s4) + argc++; + } + } + } + + if (argc <= 2) { + if (*hostname) + tcp_open(s1, s2, hostname, portnumber); + else { + PRINTF("#connect: no host defined!\n#syntax: #connect session-id [[init-str] [hostname] [port]]\n"); + } + } else if (argc == 3) { + if (!*hostname) { + my_strncpy(hostname, s2, BUFSIZE-1); + portnumber = atoi(s3); + } + tcp_open(s1, NULL, s2, atoi(s3)); + } else { + if (!*hostname) { + my_strncpy(hostname, s3, BUFSIZE-1); + portnumber = atoi(s4); + } + tcp_open(s1, s2, s3, atoi(s4)); + } +#endif /* TERM */ +} + + +static void cmd_spawn __P1 (char *,arg) +{ + char s[BUFSIZE]; + if (*(arg = skipspace(arg))) { + arg = split_first_word(s, BUFSIZE, arg); + if (*arg && *s) { + tcp_spawn(s, arg); + return; + } + } + PRINTF("#syntax: #spawn connect-id command\n"); +} + +static void cmd_zap __P1 (char *,arg) +{ + if (!*arg) { + PRINTF("#zap: no connection name.\n"); + } else + tcp_close(arg); +} + +static void cmd_qui __P1 (char *,arg) +{ + PRINTF("#you have to write '#quit' - no less, to quit!\n"); +} + +static void cmd_quit __P1 (char *,arg) +{ + if (*arg) { /* no skipspace() here! */ + PRINTF("#quit: spurious argument?\n"); + } else + exit_powwow(); +} + +char *full_options_string = "#option %cexit %chistory %cwords %ccompact %cdebug %cecho %cinfo %ckeyecho %cspeedwalk\n#option %cwrap %cautoprint %creprint %csendsize %cautoclear%s"; + +static void cmd_option __P1 (char *,arg) +{ + if (*(arg = skipspace(arg))) { + int len, i, count = 0; + static char *str[] = { "exit", "history", "words", + "compact", "debug", "echo", "info", "keyecho", + "speedwalk", "wrap", "autoprint", "reprint", + "sendsize", "autoclear", 0 }; + static char *varptr[] = { &opt_exit, &opt_history, &opt_words, + &opt_compact, &opt_debug, &echo_ext, &echo_int, &echo_key, + &opt_speedwalk, &opt_wrap, &opt_autoprint, &opt_reprint, + &opt_sendsize, &opt_autoclear, 0 }; + enum { MODE_ON, MODE_OFF, MODE_TOGGLE, MODE_REP } mode; + char buf[BUFSIZE], *p, *varp, c; + while ((arg = skipspace(split_first_word(buf, BUFSIZE, arg))), *buf) { + c = *(p = buf); + switch (c) { + case '=': mode = MODE_REP; p++; break; + case '+': mode = MODE_ON; p++; break; + case '-': mode = MODE_OFF; p++; break; + default: mode = MODE_TOGGLE; break; + } + len = strlen(p); + varp = 0; + count++; + for (i=0; str[i]; i++) { + if (strncmp(str[i], p, len) == 0) { + varp = varptr[i]; + break; + } + } + if (!str[i]) { + if (strncmp("none", p, len) == 0) + continue; + else { + PRINTF("#syntax: #option [[+|-|=]<name>]\t\twhere <name> is one of:\n\ +exit history words compact debug echo info\n\ +keyecho speedwalk wrap autoprint reprint sendsize autoclear\n"); + return; + } + } + if (varp) { + switch (mode) { + case MODE_REP: + sprintf(inserted_next, "#option %c", *varp ? '+' : '-'); + strcat(inserted_next, p); + break; + case MODE_ON: *varp = 1; break; + case MODE_OFF: *varp = 0; break; + default: *varp ^= 1; break; + } + /* + * reset the reprint buffer if changing its status + */ + if (varp == &opt_reprint) + reprint_clear(); + + /* as above, but always print status if + * `#option info' alone was typed */ + if (mode != MODE_REP && !*arg && count==1 && + (echo_int || (mode == MODE_TOGGLE && varp==&echo_int))) { + PRINTF("#option %s is now o%s.\n", str[i], + *varp ? "n" : "ff"); + } + } + } + } else { + PRINTF(full_options_string, + opt_exit ? '+' : '-', + opt_history ? '+' : '-', + opt_words ? '+' : '-', + opt_compact ? '+' : '-', + opt_debug ? '+' : '-', + echo_ext ? '+' : '-', + echo_int ? '+' : '-', + echo_key ? '+' : '-', + opt_speedwalk ? '+' : '-', + opt_wrap ? '+' : '-', + opt_autoprint ? '+' : '-', + opt_reprint ? '+' : '-', + opt_sendsize ? '+' : '-', + opt_autoclear ? '+' : '-', + "\n"); + } +} + +static void cmd_file __P1 (char *,arg) +{ + arg = skipspace(arg); + if (*arg == '=') { + set_deffile(++arg); + if (echo_int) { + if (*arg) { + PRINTF("#save-file set to `%s'\n", deffile); + } else { + PRINTF("#save-file is now undefined.\n"); + } + } + } else if (*deffile) { + sprintf(inserted_next, "#file =%.*s", BUFSIZE-8, deffile); + } else { + PRINTF("#save-file not defined.\n"); + } +} + +static void cmd_save __P1 (char *,arg) +{ + arg = skipspace(arg); + if (*arg) { + set_deffile(arg); + if (echo_int) { + PRINTF("#save-file set to `%s'\n", deffile); + } + } else if (!*deffile) { + PRINTF("#save-file not defined.\n"); + return; + } + + if (*deffile && save_settings() > 0 && echo_int) { + PRINTF("#settings saved to file.\n"); + } +} + +static void cmd_load __P1 (char *,arg) +{ + int res; + + arg = skipspace(arg); + if (*arg) { + set_deffile(arg); + if (echo_int) { + PRINTF("#save-file set to `%s'\n", deffile); + } + } + else if (!*deffile) { + PRINTF("#save-file not defined.\n"); + return; + } + + res = read_settings(); + + if (res > 0) { + /* success */ + if (echo_int) { + PRINTF("#settings loaded from file.\n"); + } + } else if (res < 0) { + /* critical error */ + while (keydefs) + delete_keynode(&keydefs); + tty_add_initial_binds(); + tty_add_walk_binds(); + limit_mem = 1048576; + PRINTF("#emergency loaded default settings.\n"); + } +} + +static char *trivial_eval __P3 (ptr *,pbuf, char *,arg, char *,name) +{ + char *tmp = skipspace(arg); + + if (!pbuf) + return NULL; + + if (*tmp=='(') { + arg = tmp + 1; + (void)evalp(pbuf, &arg); + if (!REAL_ERROR && *arg != ')') + error=MISSING_PAREN_ERROR; + if (REAL_ERROR) { + PRINTF("#%s: ", name); + print_error(error); + return NULL; + } + if (*pbuf) + arg = ptrdata(*pbuf); + else + arg = ""; + } + else + unescape(arg); + + return arg; +} + +static void cmd_add __P1 (char *,arg) +{ + ptr pbuf = (ptr)0; + char buf[BUFSIZE]; + + arg = trivial_eval(&pbuf, arg, "add"); + if (!REAL_ERROR) + while (*arg) { + arg = split_first_word(buf, BUFSIZE, arg); + if (strlen(buf) >= MIN_WORDLEN) + put_word(buf); + } + ptrdel(pbuf); +} + +static void cmd_put __P1 (char *,arg) +{ + ptr pbuf = (ptr)0; + arg = trivial_eval(&pbuf, arg, "put"); + if (!REAL_ERROR && *arg) + put_history(arg); + ptrdel(pbuf); +} + + @@ -0,0 +1,21 @@ +/* public things from cmd.c */ + +#ifndef _CMD_H_ +#define _CMD_H_ + +typedef struct cmdstruct { + char *sortname; /* set to NULL if you want to sort by command name */ + char *name; /* command name */ + char *help; /* short help */ + function_str funct; /* function to call */ + struct cmdstruct *next; +} cmdstruct; + +extern cmdstruct *commands; + +void show_stat __P ((void)); + +void cmd_add_command( cmdstruct *cmd ); + +#endif /* _CMD_H_ */ + @@ -0,0 +1,1665 @@ +/* + * cmd2.c -- back-end for the various #commands + * + * (created: Massimiliano Ghilardi (Cosmos), Aug 14th, 1998) + * + * Copyright (C) 1998 by Massimiliano Ghilardi + * + * 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. + * + */ + + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <signal.h> +#include <ctype.h> +#include <time.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <unistd.h> +#include <errno.h> + +#ifdef USE_REGEXP +# include "malloc.h" +# include <regex.h> +#endif + +int strcasecmp(); +int select(); + +#include "defines.h" +#include "main.h" +#include "utils.h" +#include "beam.h" +#include "edit.h" +#include "list.h" +#include "map.h" +#include "tcp.h" +#include "tty.h" +#include "eval.h" + +/* anyone knows if ANSI 6429 talks about more than 8 colors? */ +static char *colornames[] = { + "black", "red", "green", "yellow", "blue", "magenta", "cyan", "white", + "BLACK", "RED", "GREEN", "YELLOW", "BLUE", "MAGENTA", "CYAN", "WHITE", "none" +}; + +/* + * show defined aliases + */ +void show_aliases __P0 (void) +{ + aliasnode *p; + char buf[BUFSIZE]; + + PRINTF("#%s alias%s defined%c\n", sortedaliases ? "the following" : "no", + (sortedaliases && !sortedaliases->snext) ? " is" : "es are", + sortedaliases ? ':' : '.'); + reverse_sortedlist((sortednode **)&sortedaliases); + for (p = sortedaliases; p; p = p->snext) { + escape_specials(buf, p->name); + tty_printf("#alias %s%s@%s=%s\n", + p->active ? "" : "(disabled) ", + buf,p->group == NULL ? "*" : p->group, p->subst); + } + reverse_sortedlist((sortednode **)&sortedaliases); +} + +/* + * check if an alias name contains dangerous things. + * return 1 if illegal name (and print reason). + * if valid, print a warning for unbalanced () {} and "" + */ +static int check_alias __P1 (char *,name) +{ + char *p = name, c; + enum { NORM, ESCAPE } state = NORM; + int quotes=0, paren=0, braces=0, ok = 1; + + if (!*p) { + PRINTF("#illegal alias name: is empty!\n"); + error = INVALID_NAME_ERROR; + return 1; + } + if (*p == '{') { + PRINTF("#illegal beginning '{' in alias name: `%s'\n", name); + error = INVALID_NAME_ERROR; + return 1; + } + if (strchr(name, ' ')) { + PRINTF("#illegal spaces in alias name: `%s'\n", name); + error = INVALID_NAME_ERROR; + return 1; + } + + for (; ok && (c = *p); p++) switch (state) { + case NORM: + if (c == ESC) + state = ESCAPE; + else if (quotes) { + if (c == '\"') + quotes = 0; + } + else if (c == '\"') + quotes = 1; + else if (c == ')') + paren--; + else if (c == '(') + paren++; + else if (c == '}') + braces--; + else if (c == '{') + braces++; + else if (c == CMDSEP && !paren && !braces) + ok = 0; + break; + case ESCAPE: + if (c == ESC) + state = ESCAPE; + else /* if (c == ESC2 || c != ESC2) */ + state = NORM; + default: + break; + } + + if (!ok) { + PRINTF("#illegal non-escaped `;' in alias name: `%s'\n", name); + error = INVALID_NAME_ERROR; + return 1; + } + + if (quotes || paren || braces) { + PRINTF("#warning: unbalanced%s%s%s in alias name `%s' may cause problems\n", + quotes ? " \"\"" : "", paren ? " ()" : "", braces ? " {}" : "", name); + } + + return 0; +} + + +/* + * parse the #alias command + */ +void parse_alias __P1 (char *,str) +{ + char *left, *right, *group; + aliasnode **np, *p; + + left = str = skipspace(str); + + str = first_valid(str, '='); + + if (*str == '=') { + *str = '\0'; + right = ++str; + unescape(left); + + /* break out group name (if present) */ + group = strchr( left, '@' ); + if( group ) { + *group = 0; + group++; + } + + if (check_alias(left)) + return; + p = *(np = lookup_alias(left)); + if (!*str) { + /* delete alias */ + if (p) { + if (echo_int) { + PRINTF("#deleting alias: %s=%s\n", left, p->subst); + } + delete_aliasnode(np); + } else { + PRINTF("#unknown alias, cannot delete: `%s'\n", left); + } + } else { + /* add/redefine alias */ + + /* direct recursion is supported (alias CAN be defined by itself) */ + if (p) { + free(p->subst); + p->subst = my_strdup(right); + } else + add_aliasnode(left, right); + + /* get alias again to add group (if needed) + * don't take the lookup penalty though if not changing groups */ + if( group != NULL && *group != '\0' ) { + np = lookup_alias(left); + if( (*np)->group != NULL ) + free((*np)->group); + + (*np)->group = my_strdup(group); + } + + if (echo_int) { + PRINTF("#%s alias in group '%s': %s=%s\n", p ? "changed" : "new", + group == NULL ? "*" : group, left, right); + } + } + } else { + /* show alias */ + + *str = '\0'; + unescape(left); + if (check_alias(left)) + return; + np = lookup_alias(left); + if (*np) { + char buf[BUFSIZE]; + escape_specials(buf, left); + sprintf(inserted_next, "#alias %s%.*s@%s=%.*s", + BUFSIZE-9, buf, + (*np)->group == NULL ? "*" : (*np)->group, + BUFSIZE-(int)strlen(buf)-9, (*np)->subst); + } else { + PRINTF("#unknown alias, cannot show: `%s'\n", left); + } + } +} + +/* + * delete an action node + */ +static void delete_action __P1 (actionnode **,nodep) +{ + if (echo_int) { + PRINTF("#deleting action: >%c%s %s\n", (*nodep)->active ? + '+' : '-', (*nodep)->label, (*nodep)->pattern); + } + delete_actionnode(nodep); +} + +/* + * delete a prompt node + */ +static void delete_prompt __P1 (actionnode **,nodep) +{ + if (echo_int) { + PRINTF("#deleting prompt: >%c%s %s\n", (*nodep)->active ? + '+' : '-', (*nodep)->label, (*nodep)->pattern); + } + delete_promptnode(nodep); +} + +/* + * create new action + */ +static void add_new_action __P6 (char *,label, char *,pattern, char *,command, int,active, int,type, void *,q) +{ + add_actionnode(pattern, command, label, active, type, q); + if (echo_int) { + PRINTF("#new action: %c%c%s %s=%s\n", + action_chars[type], + active ? '+' : '-', label, + pattern, command); + } +} + +/* + * create new prompt + */ +static void add_new_prompt __P6 (char *,label, char *,pattern, char *,command, int,active, int,type, void *,q) +{ + add_promptnode(pattern, command, label, active, type, q); + if (echo_int) { + PRINTF("#new prompt: %c%c%s %s=%s\n", + action_chars[type], + active ? '+' : '-', label, + pattern, command); + } +} + +/* + * add an action with numbered label + */ +static void add_anonymous_action __P4 (char *,pattern, char *,command, int,type, void *,q) +{ + static int last = 0; + char label[16]; + do { + sprintf(label, "%d", ++last); + } while (*lookup_action(label)); + add_new_action(label, pattern, command, 1, type, q); +} + +#define ONPROMPT (onprompt ? "prompt" : "action") + +/* + * change fields of an existing action node + * pattern or commands can be NULL if no change + */ +static void change_actionorprompt __P6 (actionnode *,node, char *,pattern, char *,command, int,type, void *,q, int,onprompt) +{ +#ifdef USE_REGEXP + if (node->type == ACTION_REGEXP && node->regexp) { + regfree((regex_t *)(node->regexp)); + free(node->regexp); + } + node->regexp = q; +#endif + if (pattern) { + free(node->pattern); + node->pattern = my_strdup(pattern); + node->type = type; + } + if (command) { + free(node->command); + node->command = my_strdup(command); + } + + if (echo_int) { + PRINTF("#changed %s %c%c%s %s=%s\n", ONPROMPT, + action_chars[node->type], + node->active ? '+' : '-', + node->label, node->pattern, node->command); + } +} + +/* + * show defined actions + */ +void show_actions __P0 (void) +{ + actionnode *p; + + PRINTF("#%s action%s defined%c\n", actions ? "the following" : "no", + (actions && !actions->next) ? " is" : "s are", actions ? ':' : '.'); + for (p = actions; p; p = p->next) + tty_printf("#action %c%c%s@%s %s=%s\n", + action_chars[p->type], + p->active ? '+' : '-', p->label, + p->group == NULL ? "*" : p->group, + p->pattern, + p->command); +} + +/* + * show defined prompts + */ +void show_prompts __P0 (void) +{ + promptnode *p; + + PRINTF("#%s prompt%s defined%c\n", prompts ? "the following" : "no", + (prompts && !prompts->next) ? " is" : "s are", prompts ? ':' : '.'); + for (p = prompts; p; p = p->next) + tty_printf("#prompt %c%c%s %s=%s\n", + action_chars[p->type], + p->active ? '+' : '-', p->label, + p->pattern, p->command); +} + +/* + * parse the #action and #prompt commands + * this function is too damn complex because of the hairy syntax. it should be + * split up or rewritten as an fsm instead. + */ +void parse_action __P2 (char *,str, int,onprompt) +{ + char *p, label[BUFSIZE], pattern[BUFSIZE], *command, *group; + actionnode **np = NULL; + char sign, assign, hastail; + char active, type = ACTION_WEAK, kind; + void *regexp = 0; + + sign = *(p = skipspace(str)); + if (!sign) { + PRINTF("%s: no arguments given\n", ONPROMPT); + return; + } + + str = p + 1; + + switch (sign) { + case '+': + case '-': /* edit */ + case '<': /* delete */ + case '=': /* list */ + assign = sign; + break; + case '%': /* action_chars[ACTION_REGEXP] */ + type = ACTION_REGEXP; + /* falltrough */ + case '>': /* action_chars[ACTION_WEAK] */ + + /* define/edit */ + assign = '>'; + sign = *(p + 1); + if (!sign) { + PRINTF("#%s: label expected\n", ONPROMPT); + return; + } else if (sign == '+' || sign == '-') + str++; + else + sign = '+'; + break; + default: + assign = 0; /* anonymous action */ + str = p; + break; + } + + /* labelled action: */ + if (assign != 0) { + p = first_regular(str, ' '); + if ((hastail = *p)) + *p = '\0'; + + /* break out group name (if present) */ + group = strchr( str, '@' ); + if( group ) { + *group = 0; + group++; + } + + my_strncpy(label, str, BUFSIZE-1); + if (hastail) + *p++ = ' '; /* p points to start of pattern, or to \0 */ + + if (!*label) { + PRINTF("#%s: label expected\n", ONPROMPT); + return; + } + + + if (onprompt) + np = lookup_prompt(label); + else + np = lookup_action(label); + + /* '<' : remove action */ + if (assign == '<') { + if (!np || !*np) { + PRINTF("#no %s, cannot delete label: `%s'\n", + ONPROMPT, label); + } + else { + if (onprompt) + delete_prompt(np); + else + delete_action(np); + } + + /* '>' : define action */ + } else if (assign == '>') { +#ifndef USE_REGEXP + if (type == ACTION_REGEXP) { + PRINTF("#error: regexp not allowed\n"); + return; + } +#endif + + if (sign == '+') + active = 1; + else + active = 0; + + if (!*label) { + PRINTF("#%s: label expected\n", ONPROMPT); + return; + } + + p = skipspace(p); + if (*p == '(') { + ptr pbuf = (ptr)0; + p++; + kind = evalp(&pbuf, &p); + if (!REAL_ERROR && kind != TYPE_TXT) + error=NO_STRING_ERROR; + if (REAL_ERROR) { + PRINTF("#%s: ", ONPROMPT); + print_error(error=NO_STRING_ERROR); + ptrdel(pbuf); + return; + } + if (pbuf) { + my_strncpy(pattern, ptrdata(pbuf), BUFSIZE-1); + ptrdel(pbuf); + } else + pattern[0] = '\0'; + if (*p) + p = skipspace(++p); + if ((hastail = *p == '=')) + p++; + } + else { + p = first_regular(command = p, '='); + if ((hastail = *p)) + *p = '\0'; + my_strncpy(pattern, command, BUFSIZE-1); + + if (hastail) + *p++ = '='; + } + + if (!*pattern) { + PRINTF("#error: pattern of #%ss must be non-empty.\n", ONPROMPT); + return; + } + +#ifdef USE_REGEXP + if (type == ACTION_REGEXP && hastail) { + int errcode; + char unesc_pat[BUFSIZE]; + + /* + * HACK WARNING: + * we unescape regexp patterns now, instead of doing + * jit+unescape at runtime, as for weak actions. + */ + strcpy(unesc_pat, pattern); + unescape(unesc_pat); + + regexp = malloc(sizeof(regex_t)); + if (!regexp) { + errmsg("malloc"); + return; + } + + if ((errcode = regcomp((regex_t *)regexp, unesc_pat, REG_EXTENDED))) { + int n; + char *tmp; + n = regerror(errcode, (regex_t *)regexp, NULL, 0); + tmp = (char *)malloc(n); + if (tmp) { + if (!regerror(errcode, (regex_t *)regexp, tmp, n)) + errmsg("regerror"); + else { + PRINTF("#regexp error: %s\n", tmp); + } + free(tmp); + } else { + error = NO_MEM_ERROR; + errmsg("malloc"); + } + regfree((regex_t *)regexp); + free(regexp); + return; + } + } +#endif + command = p; + + if (hastail) { + if (np && *np) { + change_actionorprompt(*np, pattern, command, type, regexp, onprompt); + (*np)->active = active; + } else { + if (onprompt) + add_new_prompt(label, pattern, command, active, + type, regexp); + else + add_new_action(label, pattern, command, active, + type, regexp); + } + + if( group != NULL && *group != '\0' ) { + /* I don't know why but we need to clip this because somehow + * the original string is restored to *p at some point instead + * of the null-clipped one we used waaaay at the top. */ + p = first_regular(group, ' '); + *p = '\0'; + np = lookup_action(label); + if( (*np)->group != NULL ) + free( (*np)->group ); + (*np) -> group = my_strdup( group ); + } + } + + /* '=': list action */ + } else if (assign == '='){ + if (np && *np) { + int len = (int)strlen((*np)->label); + sprintf(inserted_next, "#%s %c%c%.*s %.*s=%.*s", ONPROMPT, + action_chars[(*np)->type], (*np)->active ? '+' : '-', + BUFSIZE - 6 /*strlen(ONPROMPT)*/ - 7, (*np)->label, + BUFSIZE - 6 /*strlen(ONPROMPT)*/ - 7 - len, (*np)->pattern, + BUFSIZE - 6 /*strlen(ONPROMPT)*/ - 7 - len - (int)strlen((*np)->pattern), + (*np)->command); + } else { + PRINTF("#no %s, cannot list label: `%s'\n", ONPROMPT, label); + } + + /* '+', '-': turn action on/off */ + } else { + if (np && *np) { + (*np)->active = (sign == '+'); + if (echo_int) { + PRINTF("#%s %c%s %s is now o%s.\n", ONPROMPT, + action_chars[(*np)->type], + label, + (*np)->pattern, (sign == '+') ? "n" : "ff"); + } + } else { + PRINTF("#no %s, cannot turn o%s label: `%s'\n", ONPROMPT, + (sign == '+') ? "n" : "ff", label); + } + } + + /* anonymous action, cannot be regexp */ + } else { + + if (onprompt) { + PRINTF("#anonymous prompts not supported.\n#please use labelled prompts.\n"); + return; + } + + command = first_regular(str, '='); + + if (*command == '=') { + *command = '\0'; + + my_strncpy(pattern, str, BUFSIZE-1); + *command++ = '='; + np = lookup_action_pattern(pattern); + if (*command) + if (np && *np) + change_actionorprompt(*np, NULL, command, ACTION_WEAK, NULL, 0); + else + add_anonymous_action(pattern, command, ACTION_WEAK, NULL); + else if (np && *np) + delete_action(np); + else { + PRINTF("#no action, cannot delete pattern: `%s'\n", + pattern); + return; + } + } else { + np = lookup_action_pattern(str); + if (np && *np) { + sprintf(inserted_next, "#action %.*s=%.*s", + BUFSIZE - 10, (*np)->pattern, + BUFSIZE - (int)strlen((*np)->pattern) - 10, + (*np)->command); + } else { + PRINTF("#no action, cannot show pattern: `%s'\n", pattern); + } + } + } +} + +#undef ONPROMPT + +/* + * display attribute syntax + */ +void show_attr_syntax __P0 (void) +{ + int i; + PRINTF("#attribute syntax:\n\tOne or more of:\tbold, blink, underline, inverse\n\tand/or\t[foreground] [ON background]\n\tColors: "); + for (i = 0; i < COLORS; i++) + tty_printf("%s%s", colornames[i], + (i == LOWCOLORS - 1 || i == COLORS - 1) ? "\n\t\t" : ","); + tty_printf("%s\n", colornames[i]); +} + +/* + * put escape sequences to turn on/off an attribute in given buffers + */ +void attr_string __P3 (int,attrcode, char *,begin, char *,end) +{ + int fg = FOREGROUND(attrcode), bg = BACKGROUND(attrcode), + tok = ATTR(attrcode); + char need_end = 0; + *begin = *end = '\0'; + + if (tok > (ATTR_BOLD | ATTR_BLINK | ATTR_UNDERLINE | ATTR_INVERSE) + || fg > COLORS || bg > COLORS || attrcode == NOATTRCODE) + return; /* do nothing */ + + if (fg < COLORS) { + if (bg < COLORS) { + sprintf(begin, "\033[%c%d;%s%dm", + fg<LOWCOLORS ? '3' : '9', fg % LOWCOLORS, + bg<LOWCOLORS ? "4" :"10", bg % LOWCOLORS); +#ifdef TERM_LINUX + strcpy(end, "\033[39;49m"); +#endif + } else { + sprintf(begin, "\033[%c%dm", + fg<LOWCOLORS ? '3' : '9', fg % LOWCOLORS); +#ifdef TERM_LINUX + strcpy(end, "\033[39m"); +#endif + } + } else if (bg < COLORS) { + sprintf(begin, "\033[%s%dm", + bg<LOWCOLORS ? "4" : "10", bg % LOWCOLORS); +#ifdef TERM_LINUX + strcpy(end, "\033[49m"); +#endif + } + +#ifndef TERM_LINUX + if (fg < COLORS || bg < COLORS) + need_end = 1; +#endif + + if (tok & ATTR_BOLD) { + if (tty_modebold[0]) { + strcat(begin, tty_modebold); +#ifdef TERM_LINUX + strcat(end, "\033[21m"); +#else + need_end = 1; +#endif + } else { + strcat(begin, tty_modestandon); + strcpy(end, tty_modestandoff); + } + } + + if (tok & ATTR_BLINK) { + if (tty_modeblink[0]) { + strcat(begin, tty_modeblink); +#ifdef TERM_LINUX + strcat(end, "\033[25m"); +#else + need_end = 1; +#endif + } else { + strcat(begin, tty_modestandon); + strcpy(end, tty_modestandoff); + } + } + + if (tok & ATTR_UNDERLINE) { + if (tty_modeuline[0]) { + strcat(begin, tty_modeuline); +#ifdef TERM_LINUX + strcat(end, "\033[24m"); +#else + need_end = 1; +#endif + } else { + strcat(begin, tty_modestandon); + strcpy(end, tty_modestandoff); + } + } + + if (tok & ATTR_INVERSE) { + if (tty_modeinv[0]) { + strcat(begin, tty_modeinv); +#ifdef TERM_LINUX + strcat(end, "\033[27m"); +#else + need_end = 1; +#endif + } else { + strcat(begin, tty_modestandon); + strcpy(end, tty_modestandoff); + } + } + +#ifndef TERM_LINUX + if (need_end) + strcpy(end, tty_modenorm); +#endif +} + +/* + * parse attribute description in line. + * Return attribute if successful, -1 otherwise. + */ +int parse_attributes __P1 (char *,line) +{ + char *p; + int tok = 0, fg, bg, t = -1; + + if (!(p = strtok(line, " "))) + return NOATTRCODE; + + fg = bg = NO_COLOR; + + while (t && p) { + if (!strcasecmp(p, "bold")) + t = ATTR_BOLD; + else if (!strcasecmp(p, "blink")) + t = ATTR_BLINK; + else if (!strcasecmp(p, "underline")) + t = ATTR_UNDERLINE; + else if (!strcasecmp(p, "inverse") || !strcasecmp(p, "reverse")) + t = ATTR_INVERSE; + else + t = 0; + + if (t) { + tok |= t; + p = strtok(NULL, " "); + } + } + + if (!p) + return ATTRCODE(tok, fg, bg); + + for (t = 0; t <= COLORS && strcmp(p, colornames[t]); t++) + ; + if (t <= COLORS) { + fg = t; + p = strtok(NULL, " "); + } + + if (!p) + return ATTRCODE(tok, fg, bg); + + if (strcasecmp(p, "on")) + return -1; /* invalid attribute */ + + if (!(p = strtok(NULL, " "))) + return -1; + + for (t = 0; t <= COLORS && strcmp(p, colornames[t]); t++) + ; + if (t <= COLORS) + bg = t; + else + return -1; + + return ATTRCODE(tok, fg, bg); +} + + +/* + * return a static pointer to name of given attribute code + */ +char *attr_name __P1 (int,attrcode) +{ + static char name[BUFSIZE]; + int fg = FOREGROUND(attrcode), bg = BACKGROUND(attrcode), tok = ATTR(attrcode); + + name[0] = 0; + if (tok > (ATTR_BOLD | ATTR_BLINK | ATTR_UNDERLINE | ATTR_INVERSE) || fg > COLORS || bg > COLORS) + return name; /* error! */ + + if (tok & ATTR_BOLD) + strcat(name, "bold "); + if (tok & ATTR_BLINK) + strcat(name, "blink "); + if (tok & ATTR_UNDERLINE) + strcat(name, "underline "); + if (tok & ATTR_INVERSE) + strcat(name, "inverse "); + + if (fg < COLORS || (fg == bg && fg == COLORS && !tok)) + strcat(name, colornames[fg]); + + if (bg < COLORS) { + strcat(name, " on "); + strcat(name, colornames[bg]); + } + + if (!*name) + strcpy(name, "none"); + + return name; +} + +/* + * show defined marks + */ +void show_marks __P0 (void) +{ + marknode *p; + PRINTF("#%s marker%s defined%c\n", markers ? "the following" : "no", + (markers && !markers->next) ? " is" : "s are", + markers ? ':' : '.'); + for (p = markers; p; p = p->next) + tty_printf("#mark %s%s=%s\n", p->mbeg ? "^" : "", + p->pattern, attr_name(p->attrcode)); +} + + +/* + * parse arguments to the #mark command + */ +void parse_mark __P1 (char *,str) +{ + char *p; + marknode **np, *n; + char mbeg = 0; + + if (*str == '=') { + PRINTF("#marker must be non-null.\n"); + return; + } + p = first_regular(str, '='); + if (!*p) { + if (*str == '^') + mbeg = 1, str++; + unescape(str); + np = lookup_marker(str, mbeg); + if ((n = *np)) { + ptr pbuf = (ptr)0; + char *name; + pbuf = ptrmescape(pbuf, n->pattern, strlen(n->pattern), 0); + if (MEM_ERROR) { ptrdel(pbuf); return; } + name = attr_name(n->attrcode); + sprintf(inserted_next, "#mark %s%.*s=%.*s", n->mbeg ? "^" : "", + BUFSIZE-(int)strlen(name)-9, pbuf ? ptrdata(pbuf) : "", + BUFSIZE-9, name); + ptrdel(pbuf); + } else { + PRINTF("#unknown marker, cannot show: `%s'\n", str); + } + + } else { + int attrcode, wild = 0; + char pattern[BUFSIZE], *p2; + + *(p++) = '\0'; + p = skipspace(p); + if (*str == '^') + mbeg = 1, str++; + my_strncpy(pattern, str, BUFSIZE-1); + unescape(pattern); + p2 = pattern; + while (*p2) { + if (ISMARKWILDCARD(*p2)) { + wild = 1; + if (ISMARKWILDCARD(*(p2 + 1))) { + error=SYNTAX_ERROR; + PRINTF("#error: two wildcards (& or $) may not be next to eachother\n"); + return; + } + } + p2++; + } + + np = lookup_marker(pattern, mbeg); + attrcode = parse_attributes(p); + if (attrcode == -1) { + PRINTF("#invalid attribute syntax.\n"); + error=SYNTAX_ERROR; + if (echo_int) show_attr_syntax(); + } else if (!*p) + if ((n = *np)) { + if (echo_int) { + PRINTF("#deleting mark: %s%s=%s\n", n->mbeg ? "^" : "", + n->pattern, attr_name(n->attrcode)); + } + delete_marknode(np); + } else { + PRINTF("#unknown marker, cannot delete: `%s%s'\n", + mbeg ? "^" : "", pattern); + } + else { + if (*np) { + (*np)->attrcode = attrcode; + if (echo_int) { + PRINTF("#changed"); + } + } else { + add_marknode(pattern, attrcode, mbeg, wild); + if (echo_int) { + PRINTF("#new"); + } + } + if (echo_int) + tty_printf(" mark: %s%s=%s\n", mbeg ? "^" : "", + pattern, attr_name(attrcode)); + } + } +} + +/* + * turn ASCII description of a sequence + * into raw escape sequence + * return pointer to end of ASCII description + */ +static char *unescape_seq __P3 (char *,buf, char *,seq, int *,seqlen) +{ + char c, *start = buf; + enum { NORM, ESCSINGLE, ESCAPE, CARET, DONE } state = NORM; + + for (; (c = *seq); seq++) { + switch (state) { + case NORM: + if (c == '^') + state = CARET; + else if (c == ESC) + state = ESCSINGLE; + else if (c == '=') + state = DONE; + else + *(buf++) = c; + break; + case CARET: + /* + * handle ^@ ^A ... ^_ as expected: + * ^@ == 0x00, ^A == 0x01, ... , ^_ == 0x1f + */ + if (c > 0x40 && c < 0x60) + *(buf++) = c & 0x1f; + /* special case: ^? == 0x7f */ + else if (c == '?') + *(buf++) = 0x7f; + state = NORM; + break; + case ESCSINGLE: + case ESCAPE: + /* + * GH: \012 ==> octal number + */ + if (state == ESCSINGLE && + ISODIGIT(seq[0]) && ISODIGIT(seq[1]) && ISODIGIT(seq[2])) { + *(buf++) =(((seq[0] - '0') << 6) | + ((seq[1] - '0') << 3) | + (seq[2] - '0')); + seq += 2; + } else { + *(buf++) = c; + if (c == ESC) + state = ESCAPE; + else + state = NORM; + } + break; + default: + break; + } + if (state == DONE) + break; + } + *buf = '\0'; + *seqlen = buf - start; + return seq; +} + +/* + * read a single character from tty, with timeout in milliseconds. + * timeout == 0 means wait indefinitely (no timeout). + * return char or -1 if timeout was reached. + */ +static int get_one_char __P1 (int,timeout) +{ + extern int errno; + int err; + fd_set fds; + char c; + struct timeval timeoutbuf; + + FD_ZERO(&fds); + FD_SET(tty_read_fd, &fds); + timeoutbuf.tv_sec = 0; + timeoutbuf.tv_usec = timeout * uSEC_PER_mSEC; + err = select(tty_read_fd+1, &fds, NULL, NULL, + timeout ? &timeoutbuf : NULL); + if (err == 0 || (err == -1 && errno == EINTR)) + return -1; + if (err == -1) { + errmsg("select"); + return -1; + } + while ((err = tty_read(tty_read_fd, &c, 1)) < 0 && errno == EINTR) + ; + if (err != 1) { + errmsg("read from tty"); + return -1; + } + return (int)c; +} + +/* + * print an escape sequence in human-readably form. + */ +void print_seq __P2 (char *,seq, int,len) +{ + char ch; + + while (len--) { + ch = *(seq++); + if (ch == '\033') { + tty_puts("esc "); + continue; + } + if (ch < ' ') { + tty_putc('^'); + ch |= '@'; + } + if (ch == ' ') + tty_puts("space "); + else if (ch == 0x7f) + tty_puts("del "); + else if (ch & 0x80) + tty_printf("\\%03o ", ch); + else + tty_printf("%c ", ch); + } +} + +/* + * return a static pointer to escape sequence made printable, for use in + * definition-files + */ +char *seq_name __P2 (char *,seq, int,len) +{ + static char buf[CAPLEN*4]; + char *p = buf; + char c; + /* + * rules: control chars are written as ^X, where + * X is char | 64 + * + * GH: codes > 0x80 ==> octal \012 + * + * special case: 0x7f is written ^? + */ + while (len--) { + c = *seq++; + if (c == '^' || (c && strchr(SPECIAL_CHARS, c))) + *(p++) = ESC; + + if (c < ' ') { + *(p++) = '^'; + *(p++) = c | '@'; + } else if (c == 0x7f) { + *(p++) = '^'; + *(p++) = '?'; + } else if (c & 0x80) { + /* GH: save chars with high bit set in octal */ + sprintf(p, "\\%03o", (int)c); + p += strlen(p); + } else + *(p++) = c; + } + *p = '\0'; + return buf; +} + +/* + * read a single escape sequence from the keyboard + * prompting user for it; return static pointer + */ +char *read_seq __P2 (char *,name, int *,len) +{ + static char seq[CAPLEN]; + int i = 1, tmp; + + PRINTF("#please press the key `%s' : ", name); + tty_flush(); + + if ((tmp = get_one_char(0)) >= 0) + seq[0] = tmp; + else { + tty_puts("#unable to get key. Giving up.\n"); + return NULL; + } + + while (i < CAPLEN - 1 && + (tmp = get_one_char(KBD_TIMEOUT)) >= 0) + seq[i++] = tmp; + *len = i; + print_seq(seq, i); + + tty_putc('\n'); + if (seq[0] >= ' ' && seq[0] <= '~') { + PRINTF("#that is not a redefinable key.\n"); + return NULL; + } + return seq; +} + +/* + * show full definition of one binding, + * with custom message + */ +static void show_single_bind __P2 (char *,msg, keynode *,p) +{ + if (p->funct == key_run_command) { + PRINTF("#%s %s %s=%s\n", msg, p->name, + seq_name(p->sequence, p->seqlen), p->call_data); + } else { + PRINTF("#%s %s %s=%s%s%s\n", msg, p->name, + seq_name(p->sequence, p->seqlen), + internal_functions[lookup_edit_function(p->funct)].name, + p->call_data ? " " : "", + p->call_data ? p->call_data : ""); + } +} + +/* + * list keyboard bindings + */ +void show_binds __P1 (char,edit) +{ + keynode *p; + int count = 0; + for (p = keydefs; p; p = p->next) { + if (edit != (p->funct == key_run_command)) { + if (!count) { + if (edit) { + PRINTF("#line-editing keys:\n"); + } else { + PRINTF("#user-defined keys:\n"); + } + } + show_single_bind("bind", p); + ++count; + } + } + if (!count) { + PRINTF("#no key bindings defined right now.\n"); + } +} + + +/* + * interactively create a new keybinding + */ +static void define_new_key __P2 (char *,name, char *,command) +{ + char *seq, *arg; + keynode *p; + int seqlen, function; + + seq = read_seq(name, &seqlen); + if (!seq) return; + + for (p = keydefs; p; p = p->next) + /* GH: don't allow binding of supersets of another bind */ + if (!memcmp(p->sequence, seq, MIN2(p->seqlen, seqlen))) { + show_single_bind("key already bound as:", p); + return; + } + + function = lookup_edit_name(command, &arg); + if (function) + add_keynode(name, seq, seqlen, + internal_functions[function].funct, arg); + else + add_keynode(name, seq, seqlen, key_run_command, command); + + if (echo_int) { + PRINTF("#new key binding: %s %s=%s\n", + name, seq_name(seq, seqlen), command); + } +} + +/* + * parse the #bind command non-interactively. + */ +static void parse_bind_noninteractive __P1 (char *,arg) +{ + char rawseq[CAPLEN], *p, *seq, *params; + int function, seqlen; + keynode **kp; + + p = strchr(arg, ' '); + if (!p) { + PRINTF("#syntax error: `#bind %s'\n", arg); + return; + } + *(p++) = '\0'; + seq = p = skipspace(p); + + p = unescape_seq(rawseq, p, &seqlen); + if (!p[0] || !p[1]) { + PRINTF("#syntax error: `#bind %s %s'\n", arg, seq); + return; + } + *p++ = '\0'; + + kp = lookup_key(arg); + if (kp && *kp) + delete_keynode(kp); + + if ((function = lookup_edit_name(p, ¶ms))) + add_keynode(arg, rawseq, seqlen, + internal_functions[function].funct, params); + else + add_keynode(arg, rawseq, seqlen, key_run_command, p); + + if (echo_int) { + PRINTF("#%s: %s %s=%s\n", (kp && *kp) ? + "redefined key" : "new key binding", arg, seq, p); + } +} + +/* + * parse the argument of the #bind command (interactive) + */ +void parse_bind __P1 (char *,arg) +{ + char *p, *q, *command, *params; + char *name = arg; + keynode **npp, *np; + int function; + + p = first_valid(arg, '='); + q = first_valid(arg, ' '); + q = skipspace(q); + + if (*p && *q && p > q) { + parse_bind_noninteractive(arg); + return; + } + + if (*p) { + *(p++) = '\0'; + np = *(npp = lookup_key(name)); + if (*p) { + command = p; + if (np) { + if (np->funct == key_run_command) + free(np->call_data); + if ((function = lookup_edit_name(command, ¶ms))) { + np->call_data = my_strdup(params); + np->funct = internal_functions[function].funct; + } else { + np->call_data = my_strdup(command); + np->funct = key_run_command; + } + if (echo_int) { + PRINTF("#redefined key: %s %s=%s\n", name, + seq_name(np->sequence, np->seqlen), + command); + } + } else + define_new_key(name, command); + } else { + if (np) { + if (echo_int) + show_single_bind("deleting key binding:", np); + delete_keynode(npp); + } else { + PRINTF("#no such key: `%s'\n", name); + } + } + } else { + np = *(npp = lookup_key(name)); + if (np) { + char *seqname; + int seqlen; + seqname = seq_name(np->sequence, np->seqlen); + seqlen = strlen(seqname); + + if (np->funct == key_run_command) + sprintf(inserted_next, "#bind %.*s %s=%.*s", + BUFSIZE-seqlen-9, name, seqname, + BUFSIZE-seqlen-(int)strlen(name)-9, + np->call_data); + else { + p = internal_functions[lookup_edit_function(np->funct)].name; + sprintf(inserted_next, "#bind %.*s %s=%s%s%.*s", + BUFSIZE-seqlen-10, name, seqname, p, + np->call_data ? " " : "", + BUFSIZE-seqlen-(int)strlen(name)-(int)strlen(p)-10, + np->call_data ? np->call_data : ""); + } + } else { + PRINTF("#no such key: `%s'\n", name); + } + } +} + +void parse_rebind __P1 (char *,arg) +{ + char rawseq[CAPLEN], *seq, **old; + keynode **kp, *p; + int seqlen; + + arg = skipspace(arg); + if (!*arg) { + PRINTF("#rebind: missing key.\n"); + return; + } + + seq = first_valid(arg, ' '); + if (*seq) { + *seq++ = '\0'; + seq = skipspace(seq); + } + + kp = lookup_key(arg); + if (!kp || !*kp) { + PRINTF("#no such key: `%s'\n", arg); + return; + } + + if (!*seq) { + seq = read_seq(arg, &seqlen); + if (!seq) + return; + } else { + (void)unescape_seq(rawseq, seq, &seqlen); + seq = rawseq; + } + + for (p = keydefs; p; p = p->next) { + if (p == *kp) + continue; + if (seqlen == p->seqlen && !memcmp(p->sequence, seq, seqlen)) { + show_single_bind("key already bound as:", p); + return; + } + } + + old = &((*kp)->sequence); + if (*old) + free(*old); + *old = (char *)malloc((*kp)->seqlen = seqlen); + memmove(*old, seq, seqlen); + + if (echo_int) + show_single_bind("redefined key:", *kp); +} + +/* + * evaluate an expression, or unescape a text. + * set value of start and end line if <(expression...) or !(expression...) + * if needed, use/malloc `pbuf' as buffer (on error, also free pbuf) + * return resulting char * + */ +char *redirect __P7 (char *,arg, ptr *,pbuf, char *,kind, char *,name, int,also_num, long *,start, long *,end) +{ + char *tmp = skipspace(arg), k; + int type, i; + + if (!pbuf) { + print_error(error=INTERNAL_ERROR); + return NULL; + } + + k = *tmp; + if (k == '!' || k == '<') + arg = ++tmp; + else + k = 0; + + *start = *end = 0; + + if (*tmp=='(') { + + arg = tmp + 1; + type = evalp(pbuf, &arg); + if (!REAL_ERROR && type!=TYPE_TXT && !also_num) + error=NO_STRING_ERROR; + if (REAL_ERROR) { + PRINTF("#%s: ", name); + print_error(error); + ptrdel(*pbuf); + return NULL; + } + for (i=0; i<2; i++) if (*arg == CMDSEP) { + long buf; + + arg++; + if (!i && *arg == CMDSEP) { + *start = 1; + continue; + } + else if (i && *arg == ')') { + *end = LONG_MAX; + continue; + } + + type = evall(&buf, &arg); + if (!REAL_ERROR && type != TYPE_NUM) + error=NO_NUM_VALUE_ERROR; + if (REAL_ERROR) { + PRINTF("#%s: ", name); + print_error(error); + ptrdel(*pbuf); + return NULL; + } + if (i) + *end = buf; + else + *start = buf; + } + if (*arg != ')') { + PRINTF("#%s: ", name); + print_error(error=MISSING_PAREN_ERROR); + ptrdel(*pbuf); + return NULL; + } + if (!*pbuf) { + /* make space to add a final \n */ + *pbuf = ptrsetlen(*pbuf, 1); + ptrzero(*pbuf); + if (REAL_ERROR) { + print_error(error); + ptrdel(*pbuf); + return NULL; + } + } + arg = ptrdata(*pbuf); + if (!*start && *end) + *start = 1; + } else + unescape(arg); + + *kind = k; + return arg; +} + +void show_vars __P0 (void) +{ + varnode *v; + int i, type; + ptr p = (ptr)0; + + PRINTF("#the following variables are defined:\n"); + + for (type = 0; !REAL_ERROR && type < 2; type++) { + reverse_sortedlist((sortednode **)&sortednamed_vars[type]); + v = sortednamed_vars[type]; + while (v) { + if (type == 0) { + tty_printf("#(@%s = %ld)\n", v->name, v->num); + } else { + p = ptrescape(p, v->str, 0); + if (REAL_ERROR) { + print_error(error); + break; + } + tty_printf("#($%s = \"%s\")\n", v->name, + p ? ptrdata(p) : ""); + } + v = v->snext; + } + reverse_sortedlist((sortednode **)&sortednamed_vars[type]); + } + for (i = -NUMVAR; !REAL_ERROR && i < NUMPARAM; i++) { + if (*VAR[i].num) + tty_printf("#(@%d = %ld)\n", i, *VAR[i].num); + } + for (i = -NUMVAR; !REAL_ERROR && i < NUMPARAM; i++) { + if (*VAR[i].str && ptrlen(*VAR[i].str)) { + p = ptrescape(p, *VAR[i].str, 0); + if (p && ptrlen(p)) + tty_printf("#($%d = \"%s\")\n", i, ptrdata(p)); + } + } + ptrdel(p); +} + +void show_delaynode __P2 (delaynode *,p, int,in_or_at) +{ + long d; + struct tm *s; + char buf[BUFSIZE]; + + update_now(); + d = diff_vtime(&p->when, &now); + s = localtime((time_t *)&p->when.tv_sec); + /* s now points to a calendar struct */ + if (in_or_at) { + + if (in_or_at == 2) { + /* write time in buf */ + (void)strftime(buf, BUFSIZE - 1, "%H%M%S", s); + sprintf(inserted_next, "#at %.*s (%s) %.*s", + BUFSIZE - 15, p->name, buf, + BUFSIZE - 15 - (int)strlen(p->name), p->command); + } + else + sprintf(inserted_next, "#in %.*s (%ld) %.*s", + BUFSIZE - LONGLEN - 9, p->name, d, + BUFSIZE - LONGLEN - 9 - (int)strlen(p->name), p->command); + } else { + (void)strftime(buf, BUFSIZE - 1, "%H:%M:%S", s); + PRINTF("#at (%s) #in (%ld) `%s' %s\n", buf, d, p->name, p->command); + } +} + +void show_delays __P0 (void) +{ + delaynode *p; + int n = (delays ? delays->next ? 2 : 1 : 0) + + (dead_delays ? dead_delays->next ? 2 : 1 : 0); + + PRINTF("#%s delay label%s defined%c\n", n ? "the following" : "no", + n == 1 ? " is" : "s are", n ? ':' : '.'); + for (p = delays; p; p = p->next) + show_delaynode(p, 0); + for (p = dead_delays; p; p = p->next) + show_delaynode(p, 0); +} + +void change_delaynode __P3 (delaynode **,p, char *,command, long,millisec) +{ + delaynode *m=*p; + + *p = m->next; + m->when.tv_usec = (millisec % mSEC_PER_SEC) * uSEC_PER_mSEC; + m->when.tv_sec = millisec / mSEC_PER_SEC; + update_now(); + add_vtime(&m->when, &now); + if (*command) { + if (strlen(command) > strlen(m->command)) { + free((void*)m->command); + m->command = my_strdup(command); + } + else + strcpy(m->command, command); + } + if (millisec < 0) + add_node((defnode*)m, (defnode**)&dead_delays, rev_time_sort); + else + add_node((defnode*)m, (defnode**)&delays, time_sort); + if (echo_int) { + PRINTF("#changed "); + show_delaynode(m, 0); + } +} + +void new_delaynode __P3 (char *,name, char *,command, long,millisec) +{ + vtime t; + delaynode *node; + + t.tv_usec = (millisec % mSEC_PER_SEC) * uSEC_PER_mSEC; + t.tv_sec = millisec / mSEC_PER_SEC; + update_now(); + add_vtime(&t, &now); + node = add_delaynode(name, command, &t, millisec < 0); + if (echo_int && node) { + PRINTF("#new "); + show_delaynode(node, 0); + } +} + +void show_history __P1 (int,count) +{ + int i = curline; + + if (!count) count = lines - 1; + if (count >= MAX_HIST) count = MAX_HIST - 1; + i -= count; + if (i < 0) i += MAX_HIST; + + while (count) { + if (hist[i]) { + PRINTF("#%2d: %s\n", count, hist[i]); + } + count--; + if (++i == MAX_HIST) i = 0; + } +} + +void exe_history __P1 (int,count) +{ + int i = curline; + char buf[BUFSIZE]; + + if (count >= MAX_HIST) + count = MAX_HIST - 1; + i -= count; + if (i < 0) + i += MAX_HIST; + if (hist[i]) { + strcpy(buf, hist[i]); + parse_user_input(buf, 0); + } +} + @@ -0,0 +1,32 @@ +/* public things from cmd2.c */ + +void show_aliases __P ((void)); +void parse_alias __P ((char *str)); + +void show_actions __P ((void)); +void show_prompts __P ((void)); +void parse_action __P ((char *str, int onprompt)); + +void show_attr_syntax __P ((void)); +void attr_string __P ((int attrcode, char *begin, char *end)); +int parse_attributes __P ((char *line)); +char *attr_name __P ((int attrcode)); +void show_marks __P ((void)); +void parse_mark __P ((char *str)); + +char *seq_name __P ((char *seq, int len)); +void show_binds __P ((char edit)); +void parse_bind __P ((char *arg)); +void parse_rebind __P ((char *arg)); + +char *redirect __P ((char *arg, ptr *pbuf, char *kind, char *name, int also_num, long *start, long *end)); + +void show_vars __P ((void)); +void show_delaynode __P ((delaynode *p, int in_or_at)); +void show_delays __P ((void)); +void change_delaynode __P ((delaynode **p, char *command, long millisec)); +void new_delaynode __P ((char *name, char *command, long millisec)); + +void show_history __P ((int count)); +void exe_history __P ((int count)); + diff --git a/configure b/configure new file mode 100755 index 0000000..664cccf --- /dev/null +++ b/configure @@ -0,0 +1,5415 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.59. +# +# Copyright (C) 2003 Free Software Foundation, Inc. +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi +DUALCASE=1; export DUALCASE # for MKS sh + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2 + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH + + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +exec 6>&1 + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_config_libobj_dir=. +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} + +# Maximum number of lines to put in a shell here document. +# This variable seems obsolete. It should probably be removed, and +# only ac_max_sed_lines should be used. +: ${ac_max_here_lines=38} + +# Identity of this package. +PACKAGE_NAME= +PACKAGE_TARNAME= +PACKAGE_VERSION= +PACKAGE_STRING= +PACKAGE_BUGREPORT= + +# Factoring default headers for most tests. +ac_includes_default="\ +#include <stdio.h> +#if HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif +#if HAVE_SYS_STAT_H +# include <sys/stat.h> +#endif +#if STDC_HEADERS +# include <stdlib.h> +# include <stddef.h> +#else +# if HAVE_STDLIB_H +# include <stdlib.h> +# endif +#endif +#if HAVE_STRING_H +# if !STDC_HEADERS && HAVE_MEMORY_H +# include <memory.h> +# endif +# include <string.h> +#endif +#if HAVE_STRINGS_H +# include <strings.h> +#endif +#if HAVE_INTTYPES_H +# include <inttypes.h> +#else +# if HAVE_STDINT_H +# include <stdint.h> +# endif +#endif +#if HAVE_UNISTD_H +# include <unistd.h> +#endif" + +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CPP EGREP LIBOBJS LTLIBOBJS' +ac_subst_files='' + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +ac_prev= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'` + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_option in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + eval "enable_$ac_feature=no" ;; + + -enable-* | --enable-*) + ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "enable_$ac_feature='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package| sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "with_$ac_package='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/-/_/g'` + eval "with_$ac_package=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) { echo "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` + eval "$ac_envvar='$ac_optarg'" + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + { echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +# Be sure to have absolute paths. +for ac_var in exec_prefix prefix +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* | NONE | '' ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# Be sure to have absolute paths. +for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \ + localstatedir libdir includedir oldincludedir infodir mandir +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_confdir=`(dirname "$0") 2>/dev/null || +$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$0" : 'X\(//\)[^/]' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$0" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2 + { (exit 1); exit 1; }; } + else + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 + { (exit 1); exit 1; }; } + fi +fi +(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null || + { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2 + { (exit 1); exit 1; }; } +srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'` +ac_env_build_alias_set=${build_alias+set} +ac_env_build_alias_value=$build_alias +ac_cv_env_build_alias_set=${build_alias+set} +ac_cv_env_build_alias_value=$build_alias +ac_env_host_alias_set=${host_alias+set} +ac_env_host_alias_value=$host_alias +ac_cv_env_host_alias_set=${host_alias+set} +ac_cv_env_host_alias_value=$host_alias +ac_env_target_alias_set=${target_alias+set} +ac_env_target_alias_value=$target_alias +ac_cv_env_target_alias_set=${target_alias+set} +ac_cv_env_target_alias_value=$target_alias +ac_env_CC_set=${CC+set} +ac_env_CC_value=$CC +ac_cv_env_CC_set=${CC+set} +ac_cv_env_CC_value=$CC +ac_env_CFLAGS_set=${CFLAGS+set} +ac_env_CFLAGS_value=$CFLAGS +ac_cv_env_CFLAGS_set=${CFLAGS+set} +ac_cv_env_CFLAGS_value=$CFLAGS +ac_env_LDFLAGS_set=${LDFLAGS+set} +ac_env_LDFLAGS_value=$LDFLAGS +ac_cv_env_LDFLAGS_set=${LDFLAGS+set} +ac_cv_env_LDFLAGS_value=$LDFLAGS +ac_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_env_CPPFLAGS_value=$CPPFLAGS +ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_cv_env_CPPFLAGS_value=$CPPFLAGS +ac_env_CPP_set=${CPP+set} +ac_env_CPP_value=$CPP +ac_cv_env_CPP_set=${CPP+set} +ac_cv_env_CPP_value=$CPP + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures this package to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +_ACEOF + + cat <<_ACEOF +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data [PREFIX/share] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --infodir=DIR info documentation [PREFIX/info] + --mandir=DIR man documentation [PREFIX/man] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names +_ACEOF +fi + +if test -n "$ac_init_help"; then + + cat <<\_ACEOF + +Optional Features: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-vt100 Hard code vt100 escape sequences, use if you have no + termcap + --enable-sort Sort aliases and actions + --enable-noshell Disables the "#!" command + --enable-ansibug enables fixes for "#mark" ansi bugs on some + terminals + --enable-bsd Needed for BSD systems, in powwow this was USE_SGTTY + and BSD_LIKE + --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a + nonstandard directory <lib dir> + CPPFLAGS C/C++ preprocessor flags, e.g. -I<include dir> if you have + headers in a nonstandard directory <include dir> + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +_ACEOF +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + ac_popdir=`pwd` + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d $ac_dir || continue + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + cd $ac_dir + # Check for guested configure; otherwise get Cygnus style configure. + if test -f $ac_srcdir/configure.gnu; then + echo + $SHELL $ac_srcdir/configure.gnu --help=recursive + elif test -f $ac_srcdir/configure; then + echo + $SHELL $ac_srcdir/configure --help=recursive + elif test -f $ac_srcdir/configure.ac || + test -f $ac_srcdir/configure.in; then + echo + $ac_configure --help + else + echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi + cd "$ac_popdir" + done +fi + +test -n "$ac_init_help" && exit 0 +if $ac_init_version; then + cat <<\_ACEOF + +Copyright (C) 2003 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit 0 +fi +exec 5>config.log +cat >&5 <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by $as_me, which was +generated by GNU Autoconf 2.59. Invocation command line was + + $ $0 $@ + +_ACEOF +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +hostinfo = `(hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + echo "PATH: $as_dir" +done + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_sep= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 2) + ac_configure_args1="$ac_configure_args1 '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" + # Get rid of the leading space. + ac_sep=" " + ;; + esac + done +done +$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } +$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Be sure not to use single quotes in there, as some shells, +# such as our DU 5.0 friend, will then `close' the trap. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +{ + (set) 2>&1 | + case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in + *ac_space=\ *) + sed -n \ + "s/'"'"'/'"'"'\\\\'"'"''"'"'/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p" + ;; + *) + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=$`echo $ac_var` + echo "$ac_var='"'"'$ac_val'"'"'" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------- ## +## Output files. ## +## ------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=$`echo $ac_var` + echo "$ac_var='"'"'$ac_val'"'"'" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + sed "/^$/d" confdefs.h | sort + echo + fi + test "$ac_signal" != 0 && + echo "$as_me: caught signal $ac_signal" + echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core && + rm -rf conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status + ' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo >confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 +echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { echo "$as_me:$LINENO: loading cache $cache_file" >&5 +echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . $cache_file;; + *) . ./$cache_file;; + esac + fi +else + { echo "$as_me:$LINENO: creating cache $cache_file" >&5 +echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in `(set) 2>&1 | + sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val="\$ac_cv_env_${ac_var}_value" + eval ac_new_val="\$ac_env_${ac_var}_value" + case $ac_old_set,$ac_new_set in + set,) + { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 +echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 +echo "$as_me: former value: $ac_old_val" >&2;} + { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 +echo "$as_me: current value: $ac_new_val" >&2;} + ac_cache_corrupted=: + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 +echo "$as_me: error: changes in the environment can compromise the build" >&2;} + { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + + + + + + + + + + + + + + +am__api_version="1.9" +ac_aux_dir= +for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f $ac_dir/shtool; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5 +echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;} + { (exit 1); exit 1; }; } +fi +ac_config_guess="$SHELL $ac_aux_dir/config.guess" +ac_config_sub="$SHELL $ac_aux_dir/config.sub" +ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure. + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6 +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in + ./ | .// | /cC/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + done + done + ;; +esac +done + + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL=$ac_install_sh + fi +fi +echo "$as_me:$LINENO: result: $INSTALL" >&5 +echo "${ECHO_T}$INSTALL" >&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +echo "$as_me:$LINENO: checking whether build environment is sane" >&5 +echo $ECHO_N "checking whether build environment is sane... $ECHO_C" >&6 +# Just in case +sleep 1 +echo timestamp > conftest.file +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftest.file` + fi + rm -f conftest.file + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + { { echo "$as_me:$LINENO: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&5 +echo "$as_me: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&2;} + { (exit 1); exit 1; }; } + fi + + test "$2" = conftest.file + ) +then + # Ok. + : +else + { { echo "$as_me:$LINENO: error: newly created file is older than distributed files! +Check your system clock" >&5 +echo "$as_me: error: newly created file is older than distributed files! +Check your system clock" >&2;} + { (exit 1); exit 1; }; } +fi +echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 +test "$program_prefix" != NONE && + program_transform_name="s,^,$program_prefix,;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s,\$,$program_suffix,;$program_transform_name" +# Double any \ or $. echo might interpret backslashes. +# By default was `s,x,x', remove it if useless. +cat <<\_ACEOF >conftest.sed +s/[\\$]/&&/g;s/;s,x,x,$// +_ACEOF +program_transform_name=`echo $program_transform_name | sed -f conftest.sed` +rm conftest.sed + +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` + +test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + { echo "$as_me:$LINENO: WARNING: \`missing' script is too old or missing" >&5 +echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} +fi + +if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then + # We used to keeping the `.' as first argument, in order to + # allow $(mkdir_p) to be used without argument. As in + # $(mkdir_p) $(somedir) + # where $(somedir) is conditionally defined. However this is wrong + # for two reasons: + # 1. if the package is installed by a user who cannot write `.' + # make install will fail, + # 2. the above comment should most certainly read + # $(mkdir_p) $(DESTDIR)$(somedir) + # so it does not work when $(somedir) is undefined and + # $(DESTDIR) is not. + # To support the latter case, we have to write + # test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir), + # so the `.' trick is pointless. + mkdir_p='mkdir -p --' +else + # On NextStep and OpenStep, the `mkdir' command does not + # recognize any option. It will interpret all options as + # directories to create, and then abort because `.' already + # exists. + for d in ./-p ./--version; + do + test -d $d && rmdir $d + done + # $(mkinstalldirs) is defined by Automake if mkinstalldirs exists. + if test -f "$ac_aux_dir/mkinstalldirs"; then + mkdir_p='$(mkinstalldirs)' + else + mkdir_p='$(install_sh) -d' + fi +fi + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_AWK+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AWK="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + echo "$as_me:$LINENO: result: $AWK" >&5 +echo "${ECHO_T}$AWK" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$AWK" && break +done + +echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,:./+-,___p_,'` +if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.make <<\_ACEOF +all: + @echo 'ac_maketemp="$(MAKE)"' +_ACEOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftest.make +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + SET_MAKE= +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + +rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null + +# test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && + test -f $srcdir/config.status; then + { { echo "$as_me:$LINENO: error: source directory already configured; run \"make distclean\" there first" >&5 +echo "$as_me: error: source directory already configured; run \"make distclean\" there first" >&2;} + { (exit 1); exit 1; }; } +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi + + +# Define the identity of the package. + PACKAGE=powwow + VERSION=1.2.7 + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE "$PACKAGE" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define VERSION "$VERSION" +_ACEOF + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + +install_sh=${install_sh-"$am_aux_dir/install-sh"} + +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + echo "$as_me:$LINENO: result: $STRIP" >&5 +echo "${ECHO_T}$STRIP" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_STRIP="strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_ac_ct_STRIP" && ac_cv_prog_ac_ct_STRIP=":" +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 +echo "${ECHO_T}$ac_ct_STRIP" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + STRIP=$ac_ct_STRIP +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" + +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +# Always define AMTAR for backward compatibility. + +AMTAR=${AMTAR-"${am_missing_run}tar"} + +am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -' + + + + + + +# Check whether --enable-vt100 or --disable-vt100 was given. +if test "${enable_vt100+set}" = set; then + enableval="$enable_vt100" + cat >>confdefs.h <<\_ACEOF +#define VT100 1 +_ACEOF + +fi; + +# Check whether --enable-sort or --disable-sort was given. +if test "${enable_sort+set}" = set; then + enableval="$enable_sort" + cat >>confdefs.h <<\_ACEOF +#define DO_SORT 1 +_ACEOF + +fi; + +# Check whether --enable-noshell or --disable-noshell was given. +if test "${enable_noshell+set}" = set; then + enableval="$enable_noshell" + cat >>confdefs.h <<\_ACEOF +#define NO_SHELL 1 +_ACEOF + +fi; + +# Check whether --enable-ansibug or --disable-ansibug was given. +if test "${enable_ansibug+set}" = set; then + enableval="$enable_ansibug" + cat >>confdefs.h <<\_ACEOF +#define BUG_ANSI 1 +_ACEOF + +fi; + +# Check whether --enable-bsd or --disable-bsd was given. +if test "${enable_bsd+set}" = set; then + enableval="$enable_bsd" + cat >>confdefs.h <<\_ACEOF +#define USE_SGTTY 1 +_ACEOF + + cat >>confdefs.h <<\_ACEOF +#define BSD_LIKE 1 +_ACEOF + +fi; + +# Checks for programs. +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$ac_ct_CC" && break +done + + CC=$ac_ct_CC +fi + +fi + + +test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&5 +echo "$as_me: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + +# Provide some information about the compiler. +echo "$as_me:$LINENO:" \ + "checking for C compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5 + (eval $ac_compiler --version </dev/null >&5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v </dev/null >&5\"") >&5 + (eval $ac_compiler -v </dev/null >&5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V </dev/null >&5\"") >&5 + (eval $ac_compiler -V </dev/null >&5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 +echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6 +ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5 + (eval $ac_link_default) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Find the output, starting from the most likely. This scheme is +# not robust to junk in `.', hence go to wildcards (a.*) only as a last +# resort. + +# Be careful to initialize this variable, since it used to be cached. +# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile. +ac_cv_exeext= +# b.out is created by i960 compilers. +for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) + ;; + conftest.$ac_ext ) + # This is the source file. + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + # FIXME: I believe we export ac_cv_exeext for Libtool, + # but it would be cool to find out if it's true. Does anybody + # maintain Libtool? --akim. + export ac_cv_exeext + break;; + * ) + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: C compiler cannot create executables +See \`config.log' for more details." >&5 +echo "$as_me: error: C compiler cannot create executables +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } +fi + +ac_exeext=$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_file" >&5 +echo "${ECHO_T}$ac_file" >&6 + +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether the C compiler works" >&5 +echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6 +# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { echo "$as_me:$LINENO: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + fi + fi +fi +echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +rm -f a.out a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 +echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6 +echo "$as_me:$LINENO: result: $cross_compiling" >&5 +echo "${ECHO_T}$cross_compiling" >&6 + +echo "$as_me:$LINENO: checking for suffix of executables" >&5 +echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6 +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + export ac_cv_exeext + break;; + * ) break;; + esac +done +else + { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 +echo "${ECHO_T}$ac_cv_exeext" >&6 + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +echo "$as_me:$LINENO: checking for suffix of object files" >&5 +echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6 +if test "${ac_cv_objext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 +echo "${ECHO_T}$ac_cv_objext" >&6 +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6 +if test "${ac_cv_c_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_compiler_gnu=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6 +GCC=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +CFLAGS="-g" +echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_prog_cc_g=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_g" >&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5 +echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_prog_cc_stdc=no +ac_save_CC=$CC +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <stdarg.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std1 is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std1. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +# Don't try gcc -ansi; that turns off useful extensions and +# breaks some systems' header files. +# AIX -qlanglvl=ansi +# Ultrix and OSF/1 -std1 +# HP-UX 10.20 and later -Ae +# HP-UX older versions -Aa -D_HPUX_SOURCE +# SVR4 -Xc -D__EXTENSIONS__ +for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_stdc=$ac_arg +break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext +done +rm -f conftest.$ac_ext conftest.$ac_objext +CC=$ac_save_CC + +fi + +case "x$ac_cv_prog_cc_stdc" in + x|xno) + echo "$as_me:$LINENO: result: none needed" >&5 +echo "${ECHO_T}none needed" >&6 ;; + *) + echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6 + CC="$CC $ac_cv_prog_cc_stdc" ;; +esac + +# Some people use a C++ compiler to compile C. Since we use `exit', +# in C++ we need to declare it. In case someone uses the same compiler +# for both compiling C and C++ we need to have the C++ compiler decide +# the declaration of exit, since it's the most demanding environment. +cat >conftest.$ac_ext <<_ACEOF +#ifndef __cplusplus + choke me +#endif +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + for ac_declaration in \ + '' \ + 'extern "C" void std::exit (int) throw (); using std::exit;' \ + 'extern "C" void std::exit (int); using std::exit;' \ + 'extern "C" void exit (int) throw ();' \ + 'extern "C" void exit (int);' \ + 'void exit (int);' +do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +#include <stdlib.h> +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +continue +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +done +rm -f conftest* +if test -n "$ac_declaration"; then + echo '#ifdef __cplusplus' >>confdefs.h + echo $ac_declaration >>confdefs.h + echo '#endif' >>confdefs.h +fi + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +DEPDIR="${am__leading_dot}deps" + + ac_config_commands="$ac_config_commands depfiles" + + +am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo done +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +echo "$as_me:$LINENO: checking for style of include used by $am_make" >&5 +echo $ECHO_N "checking for style of include used by $am_make... $ECHO_C" >&6 +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# We grep out `Entering directory' and `Leaving directory' +# messages which can occur if `w' ends up in MAKEFLAGS. +# In particular we don't look at `^make:' because GNU make might +# be invoked under some other name (usually "gmake"), in which +# case it prints its new name instead of `make'. +if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then + am__include=include + am__quote= + _am_result=GNU +fi +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then + am__include=.include + am__quote="\"" + _am_result=BSD + fi +fi + + +echo "$as_me:$LINENO: result: $_am_result" >&5 +echo "${ECHO_T}$_am_result" >&6 +rm -f confinc confmf + +# Check whether --enable-dependency-tracking or --disable-dependency-tracking was given. +if test "${enable_dependency_tracking+set}" = set; then + enableval="$enable_dependency_tracking" + +fi; +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi + + +if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +fi + + + + +depcc="$CC" am_compiler_list= + +echo "$as_me:$LINENO: checking dependency style of $depcc" >&5 +echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6 +if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +echo "$as_me:$LINENO: result: $am_cv_CC_dependencies_compiler_type" >&5 +echo "${ECHO_T}$am_cv_CC_dependencies_compiler_type" >&6 +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + + +if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then + am__fastdepCC_TRUE= + am__fastdepCC_FALSE='#' +else + am__fastdepCC_TRUE='#' + am__fastdepCC_FALSE= +fi + + + +# Checks for libraries. + + +echo "$as_me:$LINENO: checking for initscr in -lcurses" >&5 +echo $ECHO_N "checking for initscr in -lcurses... $ECHO_C" >&6 +if test "${ac_cv_lib_curses_initscr+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lcurses $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char initscr (); +int +main () +{ +initscr (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_curses_initscr=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_curses_initscr=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_curses_initscr" >&5 +echo "${ECHO_T}$ac_cv_lib_curses_initscr" >&6 +if test $ac_cv_lib_curses_initscr = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBCURSES 1 +_ACEOF + + LIBS="-lcurses $LIBS" + +fi + +echo "$as_me:$LINENO: checking for regcomp" >&5 +echo $ECHO_N "checking for regcomp... $ECHO_C" >&6 +if test "${ac_cv_func_regcomp+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define regcomp to an innocuous variant, in case <limits.h> declares regcomp. + For example, HP-UX 11i <limits.h> declares gettimeofday. */ +#define regcomp innocuous_regcomp + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char regcomp (); below. + Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + <limits.h> exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + +#undef regcomp + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char regcomp (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_regcomp) || defined (__stub___regcomp) +choke me +#else +char (*f) () = regcomp; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != regcomp; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_regcomp=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_func_regcomp=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_func_regcomp" >&5 +echo "${ECHO_T}$ac_cv_func_regcomp" >&6 +if test $ac_cv_func_regcomp = yes; then + cat >>confdefs.h <<\_ACEOF +#define USE_REGEXP 1 +_ACEOF + +fi + +echo "$as_me:$LINENO: checking for lrand48" >&5 +echo $ECHO_N "checking for lrand48... $ECHO_C" >&6 +if test "${ac_cv_func_lrand48+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define lrand48 to an innocuous variant, in case <limits.h> declares lrand48. + For example, HP-UX 11i <limits.h> declares gettimeofday. */ +#define lrand48 innocuous_lrand48 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char lrand48 (); below. + Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + <limits.h> exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + +#undef lrand48 + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char lrand48 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_lrand48) || defined (__stub___lrand48) +choke me +#else +char (*f) () = lrand48; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != lrand48; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_lrand48=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_func_lrand48=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_func_lrand48" >&5 +echo "${ECHO_T}$ac_cv_func_lrand48" >&6 +if test $ac_cv_func_lrand48 = yes; then + : +else + cat >>confdefs.h <<\_ACEOF +#define USE_RANDOM 1 +_ACEOF + +fi + + +# Checks for header files. +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 +echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +echo "$as_me:$LINENO: result: $CPP" >&5 +echo "${ECHO_T}$CPP" >&6 +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&5 +echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +echo "$as_me:$LINENO: checking for egrep" >&5 +echo $ECHO_N "checking for egrep... $ECHO_C" >&6 +if test "${ac_cv_prog_egrep+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if echo a | (grep -E '(a|b)') >/dev/null 2>&1 + then ac_cv_prog_egrep='grep -E' + else ac_cv_prog_egrep='egrep' + fi +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5 +echo "${ECHO_T}$ac_cv_prog_egrep" >&6 + EGREP=$ac_cv_prog_egrep + + +echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <float.h> + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_header_stdc=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <string.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <stdlib.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <ctype.h> +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + exit(2); + exit (0); +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6 +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. + + + + + + + + + +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_Header=no" +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + + +for ac_header in stdlib.h unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------------ ## +## Report this to the AC_PACKAGE_NAME lists. ## +## ------------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +# Checks for typedefs, structures, and compiler characteristics. +echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5 +echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6 +if test "${ac_cv_c_const+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +/* FIXME: Include the comments suggested by Paul. */ +#ifndef __cplusplus + /* Ultrix mips cc rejects this. */ + typedef int charset[2]; + const charset x; + /* SunOS 4.1.1 cc rejects this. */ + char const *const *ccp; + char **p; + /* NEC SVR4.0.2 mips cc rejects this. */ + struct point {int x, y;}; + static struct point const zero = {0,0}; + /* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in + an arm of an if-expression whose if-part is not a constant + expression */ + const char *g = "string"; + ccp = &g + (g ? g-g : 0); + /* HPUX 7.0 cc rejects these. */ + ++ccp; + p = (char**) ccp; + ccp = (char const *const *) p; + { /* SCO 3.2v4 cc rejects this. */ + char *t; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; + } + { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; + } + { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; + } + { /* AIX XL C 1.02.0.0 rejects this saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; b->j = 5; + } + { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; + } +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_c_const=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_c_const=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5 +echo "${ECHO_T}$ac_cv_c_const" >&6 +if test $ac_cv_c_const = no; then + +cat >>confdefs.h <<\_ACEOF +#define const +_ACEOF + +fi + + +# Checks for library functions. + +for ac_header in stdlib.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------------ ## +## Report this to the AC_PACKAGE_NAME lists. ## +## ------------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +echo "$as_me:$LINENO: checking for GNU libc compatible malloc" >&5 +echo $ECHO_N "checking for GNU libc compatible malloc... $ECHO_C" >&6 +if test "${ac_cv_func_malloc_0_nonnull+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then + ac_cv_func_malloc_0_nonnull=no +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#if STDC_HEADERS || HAVE_STDLIB_H +# include <stdlib.h> +#else +char *malloc (); +#endif + +int +main () +{ +exit (malloc (0) ? 0 : 1); + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_malloc_0_nonnull=yes +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_func_malloc_0_nonnull=no +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_func_malloc_0_nonnull" >&5 +echo "${ECHO_T}$ac_cv_func_malloc_0_nonnull" >&6 +if test $ac_cv_func_malloc_0_nonnull = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_MALLOC 1 +_ACEOF + +else + cat >>confdefs.h <<\_ACEOF +#define HAVE_MALLOC 0 +_ACEOF + + case $LIBOBJS in + "malloc.$ac_objext" | \ + *" malloc.$ac_objext" | \ + "malloc.$ac_objext "* | \ + *" malloc.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS malloc.$ac_objext" ;; +esac + + +cat >>confdefs.h <<\_ACEOF +#define malloc rpl_malloc +_ACEOF + +fi + + + + +for ac_func in bzero +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func. + For example, HP-UX 11i <limits.h> declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + <limits.h> exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + +#undef $ac_func + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + + ac_config_files="$ac_config_files Makefile" +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +{ + (set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} | + sed ' + t clear + : clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + : end' >>confcache +if diff $cache_file confcache >/dev/null 2>&1; then :; else + if test -w $cache_file; then + test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" + cat confcache >$cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/; +s/:*\${srcdir}:*/:/; +s/:*@srcdir@:*/:/; +s/^\([^=]*=[ ]*\):*/\1/; +s/:*$//; +s/^[^=]*=[ ]*$//; +}' +fi + +# Transform confdefs.h into DEFS. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +# +# If the first sed substitution is executed (which looks for macros that +# take arguments), then we branch to the quote section. Otherwise, +# look for a macro that doesn't take arguments. +cat >confdef2opt.sed <<\_ACEOF +t clear +: clear +s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\),-D\1=\2,g +t quote +s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\),-D\1=\2,g +t quote +d +: quote +s,[ `~#$^&*(){}\\|;'"<>?],\\&,g +s,\[,\\&,g +s,\],\\&,g +s,\$,$$,g +p +_ACEOF +# We use echo to avoid assuming a particular line-breaking character. +# The extra dot is to prevent the shell from consuming trailing +# line-breaks from the sub-command output. A line-break within +# single-quotes doesn't work because, if this script is created in a +# platform that uses two characters for line-breaks (e.g., DOS), tr +# would break. +ac_LF_and_DOT=`echo; echo .` +DEFS=`sed -n -f confdef2opt.sed confdefs.h | tr "$ac_LF_and_DOT" ' .'` +rm -f confdef2opt.sed + + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_i=`echo "$ac_i" | + sed 's/\$U\././;s/\.o$//;s/\.obj$//'` + # 2. Add them. + ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext" + ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + +if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi + +: ${CONFIG_STATUS=./config.status} +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi +DUALCASE=1; export DUALCASE # for MKS sh + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5 +echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;} + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5 +echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;} + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH + +exec 6>&1 + +# Open the log real soon, to keep \$[0] and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. Logging --version etc. is OK. +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX +} >&5 +cat >&5 <<_CSEOF + +This file was extended by $as_me, which was +generated by GNU Autoconf 2.59. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +_CSEOF +echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5 +echo >&5 +_ACEOF + +# Files that config.status was made for. +if test -n "$ac_config_files"; then + echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_headers"; then + echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_links"; then + echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_commands"; then + echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS +fi + +cat >>$CONFIG_STATUS <<\_ACEOF + +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTIONS] [FILE]... + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + +Configuration files: +$config_files + +Configuration commands: +$config_commands + +Report bugs to <bug-autoconf@gnu.org>." +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +ac_cs_version="\\ +config.status +configured by $0, generated by GNU Autoconf 2.59, + with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" + +Copyright (C) 2003 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." +srcdir=$srcdir +INSTALL="$INSTALL" +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If no file are specified by the user, then we need to provide default +# value. By we need to know if files were specified by the user. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "x$1" : 'x\([^=]*\)='` + ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` + ac_shift=: + ;; + -*) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + *) # This is not an option, so the user has probably given explicit + # arguments. + ac_option=$1 + ac_need_defaults=false;; + esac + + case $ac_option in + # Handling of the options. +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --vers* | -V ) + echo "$ac_cs_version"; exit 0 ;; + --he | --h) + # Conflict between --help and --header + { { echo "$as_me:$LINENO: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; };; + --help | --hel | -h ) + echo "$ac_cs_usage"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + CONFIG_FILES="$CONFIG_FILES $ac_optarg" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" + ac_need_defaults=false;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +if \$ac_cs_recheck; then + echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 + exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion +fi + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +# +# INIT-COMMANDS section. +# + +AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" + +_ACEOF + + + +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_config_target in $ac_config_targets +do + case "$ac_config_target" in + # Handling of arguments. + "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "depfiles" ) CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + esac +done + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason to put it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Create a temporary directory, and hook for its removal unless debugging. +$debug || +{ + trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} + +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./confstat$$-$RANDOM + (umask 077 && mkdir $tmp) +} || +{ + echo "$me: cannot create a temporary directory in ." >&2 + { (exit 1); exit 1; } +} + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF + +# +# CONFIG_FILES section. +# + +# No need to generate the scripts if there are no CONFIG_FILES. +# This happens for instance when ./config.status config.h +if test -n "\$CONFIG_FILES"; then + # Protect against being on the right side of a sed subst in config.status. + sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g; + s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF +s,@SHELL@,$SHELL,;t t +s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t +s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t +s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t +s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t +s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t +s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t +s,@exec_prefix@,$exec_prefix,;t t +s,@prefix@,$prefix,;t t +s,@program_transform_name@,$program_transform_name,;t t +s,@bindir@,$bindir,;t t +s,@sbindir@,$sbindir,;t t +s,@libexecdir@,$libexecdir,;t t +s,@datadir@,$datadir,;t t +s,@sysconfdir@,$sysconfdir,;t t +s,@sharedstatedir@,$sharedstatedir,;t t +s,@localstatedir@,$localstatedir,;t t +s,@libdir@,$libdir,;t t +s,@includedir@,$includedir,;t t +s,@oldincludedir@,$oldincludedir,;t t +s,@infodir@,$infodir,;t t +s,@mandir@,$mandir,;t t +s,@build_alias@,$build_alias,;t t +s,@host_alias@,$host_alias,;t t +s,@target_alias@,$target_alias,;t t +s,@DEFS@,$DEFS,;t t +s,@ECHO_C@,$ECHO_C,;t t +s,@ECHO_N@,$ECHO_N,;t t +s,@ECHO_T@,$ECHO_T,;t t +s,@LIBS@,$LIBS,;t t +s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t +s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t +s,@INSTALL_DATA@,$INSTALL_DATA,;t t +s,@CYGPATH_W@,$CYGPATH_W,;t t +s,@PACKAGE@,$PACKAGE,;t t +s,@VERSION@,$VERSION,;t t +s,@ACLOCAL@,$ACLOCAL,;t t +s,@AUTOCONF@,$AUTOCONF,;t t +s,@AUTOMAKE@,$AUTOMAKE,;t t +s,@AUTOHEADER@,$AUTOHEADER,;t t +s,@MAKEINFO@,$MAKEINFO,;t t +s,@install_sh@,$install_sh,;t t +s,@STRIP@,$STRIP,;t t +s,@ac_ct_STRIP@,$ac_ct_STRIP,;t t +s,@INSTALL_STRIP_PROGRAM@,$INSTALL_STRIP_PROGRAM,;t t +s,@mkdir_p@,$mkdir_p,;t t +s,@AWK@,$AWK,;t t +s,@SET_MAKE@,$SET_MAKE,;t t +s,@am__leading_dot@,$am__leading_dot,;t t +s,@AMTAR@,$AMTAR,;t t +s,@am__tar@,$am__tar,;t t +s,@am__untar@,$am__untar,;t t +s,@CC@,$CC,;t t +s,@CFLAGS@,$CFLAGS,;t t +s,@LDFLAGS@,$LDFLAGS,;t t +s,@CPPFLAGS@,$CPPFLAGS,;t t +s,@ac_ct_CC@,$ac_ct_CC,;t t +s,@EXEEXT@,$EXEEXT,;t t +s,@OBJEXT@,$OBJEXT,;t t +s,@DEPDIR@,$DEPDIR,;t t +s,@am__include@,$am__include,;t t +s,@am__quote@,$am__quote,;t t +s,@AMDEP_TRUE@,$AMDEP_TRUE,;t t +s,@AMDEP_FALSE@,$AMDEP_FALSE,;t t +s,@AMDEPBACKSLASH@,$AMDEPBACKSLASH,;t t +s,@CCDEPMODE@,$CCDEPMODE,;t t +s,@am__fastdepCC_TRUE@,$am__fastdepCC_TRUE,;t t +s,@am__fastdepCC_FALSE@,$am__fastdepCC_FALSE,;t t +s,@CPP@,$CPP,;t t +s,@EGREP@,$EGREP,;t t +s,@LIBOBJS@,$LIBOBJS,;t t +s,@LTLIBOBJS@,$LTLIBOBJS,;t t +CEOF + +_ACEOF + + cat >>$CONFIG_STATUS <<\_ACEOF + # Split the substitutions into bite-sized pieces for seds with + # small command number limits, like on Digital OSF/1 and HP-UX. + ac_max_sed_lines=48 + ac_sed_frag=1 # Number of current file. + ac_beg=1 # First line for current file. + ac_end=$ac_max_sed_lines # Line after last line for current file. + ac_more_lines=: + ac_sed_cmds= + while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + else + sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + fi + if test ! -s $tmp/subs.frag; then + ac_more_lines=false + else + # The purpose of the label and of the branching condition is to + # speed up the sed processing (if there are no `@' at all, there + # is no need to browse any of the substitutions). + # These are the two extra sed commands mentioned above. + (echo ':t + /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed" + else + ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed" + fi + ac_sed_frag=`expr $ac_sed_frag + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_lines` + fi + done + if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat + fi +fi # test -n "$CONFIG_FILES" + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories. + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_builddir$INSTALL ;; + esac + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + if test x"$ac_file" = x-; then + configure_input= + else + configure_input="$ac_file. " + fi + configure_input=$configure_input"Generated from `echo $ac_file_in | + sed 's,.*/,,'` by configure." + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + echo "$f";; + *) # Relative + if test -f "$f"; then + # Build tree + echo "$f" + elif test -f "$srcdir/$f"; then + # Source tree + echo "$srcdir/$f" + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } + + if test x"$ac_file" != x-; then + { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + rm -f "$ac_file" + fi +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF + sed "$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s,@configure_input@,$configure_input,;t t +s,@srcdir@,$ac_srcdir,;t t +s,@abs_srcdir@,$ac_abs_srcdir,;t t +s,@top_srcdir@,$ac_top_srcdir,;t t +s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t +s,@builddir@,$ac_builddir,;t t +s,@abs_builddir@,$ac_abs_builddir,;t t +s,@top_builddir@,$ac_top_builddir,;t t +s,@abs_top_builddir@,$ac_abs_top_builddir,;t t +s,@INSTALL@,$ac_INSTALL,;t t +" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out + rm -f $tmp/stdin + if test x"$ac_file" != x-; then + mv $tmp/out $ac_file + else + cat $tmp/out + rm -f $tmp/out + fi + +done +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + +# +# CONFIG_COMMANDS section. +# +for ac_file in : $CONFIG_COMMANDS; do test "x$ac_file" = x: && continue + ac_dest=`echo "$ac_file" | sed 's,:.*,,'` + ac_source=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_dir=`(dirname "$ac_dest") 2>/dev/null || +$as_expr X"$ac_dest" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_dest" : 'X\(//\)[^/]' \| \ + X"$ac_dest" : 'X\(//\)$' \| \ + X"$ac_dest" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_dest" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + + { echo "$as_me:$LINENO: executing $ac_dest commands" >&5 +echo "$as_me: executing $ac_dest commands" >&6;} + case $ac_dest in + depfiles ) test x"$AMDEP_TRUE" != x"" || for mf in $CONFIG_FILES; do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # So let's grep whole file. + if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then + dirpart=`(dirname "$mf") 2>/dev/null || +$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$mf" : 'X\(//\)[^/]' \| \ + X"$mf" : 'X\(//\)$' \| \ + X"$mf" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`(dirname "$file") 2>/dev/null || +$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$file" : 'X\(//\)[^/]' \| \ + X"$file" : 'X\(//\)$' \| \ + X"$file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p $dirpart/$fdir + else + as_dir=$dirpart/$fdir + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory $dirpart/$fdir" >&5 +echo "$as_me: error: cannot create directory $dirpart/$fdir" >&2;} + { (exit 1); exit 1; }; }; } + + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done +done + ;; + esac +done +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF + +{ (exit 0); exit 0; } +_ACEOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || { (exit 1); exit 1; } +fi + diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..3fb7cda --- /dev/null +++ b/configure.in @@ -0,0 +1,49 @@ +# Process this file with autoconf to produce a configure script. +AC_INIT +AM_INIT_AUTOMAKE(powwow, 1.2.7) + +AC_ARG_ENABLE(vt100, + AC_HELP_STRING([--enable-vt100], + [Hard code vt100 escape sequences, use if you have no termcap ]), + AC_DEFINE(VT100)) + +AC_ARG_ENABLE(sort, + AC_HELP_STRING([--enable-sort], + [Sort aliases and actions]), + AC_DEFINE(DO_SORT)) + +AC_ARG_ENABLE(noshell, + AC_HELP_STRING([--enable-noshell], + [Disables the "#!" command]), + AC_DEFINE(NO_SHELL)) + +AC_ARG_ENABLE(ansibug, + AC_HELP_STRING([--enable-ansibug], + [enables fixes for "#mark" ansi bugs on some terminals]), + AC_DEFINE(BUG_ANSI)) + +AC_ARG_ENABLE(bsd, + AC_HELP_STRING([--enable-bsd], + [Needed for BSD systems, in powwow this was USE_SGTTY and BSD_LIKE]), + AC_DEFINE(USE_SGTTY) + AC_DEFINE(BSD_LIKE)) + +# Checks for programs. +AC_PROG_CC + +# Checks for libraries. +AC_CHECK_LIB(curses, initscr) +AC_CHECK_FUNC(regcomp,AC_DEFINE(USE_REGEXP)) +AC_CHECK_FUNC(lrand48,,AC_DEFINE(USE_RANDOM)) + +# Checks for header files. +AC_CHECK_HEADERS([stdlib.h unistd.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST + +# Checks for library functions. +AC_FUNC_MALLOC +AC_CHECK_FUNCS([bzero]) + +AC_OUTPUT(Makefile) diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..fee7716 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,9 @@ +powwow (1.2.7) unstable; urgency=low + + * First release. + + -- Your Name <your@email.address> Mon, 20 Mar 2000 17:58:49 +0000 + +Local variables: +mode: debian-changelog +End: diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..e685d2a --- /dev/null +++ b/debian/control @@ -0,0 +1,12 @@ +Source: powwow +Section: misc +Priority: optional +Standards-Version: 3.0.1 + +Package: powwow +Version: 1.2.7 +Description: a powerful and extensible curses based mud client + powwow is a powerful mud client that supports triggers, aliases, + multiple connections, and more. It is extensible through a plugin + interface. Currently there are plugins to add javascript and perl + language support. diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..68ec697 --- /dev/null +++ b/debian/rules @@ -0,0 +1,78 @@ +#!/usr/bin/make -f +# Sample debian/rules that uses debhelper. +# This file is public domain software, originally written by Joey Hess. + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +# This is the debhelper compatability version to use. +export DH_COMPAT=1 + +build: build-stamp +build-stamp: + dh_testdir + + # Add here commands to compile the package. + ./configure --prefix=/usr + $(MAKE) + + touch build-stamp + +clean: + dh_testdir + dh_testroot + rm -f build-stamp + + # Add here commands to clean up after the build process. + #$(MAKE) clean + #$(MAKE) distclean + + dh_clean + +install: build + dh_testdir + dh_testroot + dh_clean -k + dh_installdirs + + # Add here commands to install the package into debian/tmp. + $(MAKE) prefix=`pwd`/debian/tmp/usr install + +# Build architecture-independent files here. +binary-indep: build install +# We have nothing to do by default. + +# Build architecture-dependent files here. +binary-arch: build install +# dh_testversion + dh_testdir + dh_testroot +# dh_installdebconf + dh_installdocs + dh_installexamples + dh_installmenu +# dh_installemacsen +# dh_installpam +# dh_installmime +# dh_installinit + dh_installcron + dh_installmanpages + dh_installinfo +# dh_undocumented + dh_installchangelogs + dh_link + dh_strip + dh_compress + dh_fixperms + # You may want to make some executables suid here. + dh_suidregister +# dh_makeshlibs + dh_installdeb +# dh_perl + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install diff --git a/defines.h b/defines.h new file mode 100644 index 0000000..493d8a1 --- /dev/null +++ b/defines.h @@ -0,0 +1,367 @@ +/* + * common definition and typedefs + */ + +#ifndef _DEFINES_H_ +#define _DEFINES_H_ + +#include "malloc.h" + +#if !defined(SYS_TIME_H) && !defined(_H_SYS_TIME) +# include <sys/time.h> +#endif + +#ifdef AIX +# include <sys/select.h> +#endif + +#define memzero(a,b) memset((a), 0, (b)) + +#ifdef USE_RANDOM +# define get_random random +# define init_random srandom +#else +# define get_random lrand48 +# define init_random srand48 +#endif + +#ifdef __STDC__ + +# define VOLATILE volatile +# ifndef __P +# define __P(args) args +# endif +# define __P0(dummy) (void) +# define __P1(t1,a1) (t1 a1) +# define __P2(t1,a1,t2,a2) (t1 a1, t2 a2) +# define __P3(t1,a1,t2,a2,t3,a3) (t1 a1, t2 a2, t3 a3) +# define __P4(t1,a1,t2,a2,t3,a3,t4,a4) (t1 a1, t2 a2, t3 a3, t4 a4) +# define __P5(t1,a1,t2,a2,t3,a3,t4,a4,t5,a5) (t1 a1, t2 a2, t3 a3, t4 a4, t5 a5) +# define __P6(t1,a1,t2,a2,t3,a3,t4,a4,t5,a5,t6,a6) (t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, t6 a6) +# define __P7(t1,a1,t2,a2,t3,a3,t4,a4,t5,a5,t6,a6,t7,a7) (t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, t6 a6, t7 a7) + +#else /* ! __STDC__ */ + +# define VOLATILE +# ifndef __P +# define __P(args) () +# endif +# define __P0(dummy) () +# define __P1(t1,a1) (a1) t1 a1; +# define __P2(t1,a1,t2,a2) (a1, a2) t1 a1; t2 a2; +# define __P3(t1,a1,t2,a2,t3,a3) (a1, a2, a3) t1 a1; t2 a2; t3 a3; +# define __P4(t1,a1,t2,a2,t3,a3,t4,a4) (a1, a2, a3, a4) t1 a1; t2 a2; t3 a3; t4 a4; +# define __P5(t1,a1,t2,a2,t3,a3,t4,a4,t5,a5) (a1, a2, a3, a4, a5) t1 a1; t2 a2; t3 a3; t4 a4; t5 a5; +# define __P6(t1,a1,t2,a2,t3,a3,t4,a4,t5,a5,t6,a6) (a1, a2, a3, a4, a5, a6) t1 a1; t2 a2; t3 a3; t4 a4; t5 a5; t6 a6; +# define __P7(t1,a1,t2,a2,t3,a3,t4,a4,t5,a5,t6,a6,t7,a7) (a1, a2, a3, a4, a5, a6, a7) t1 a1; t2 a2; t3 a3; t4 a4; t5 a5; t6 a6; t7 a7; + +#endif /* __STDC__ */ + +#ifdef __GNUC__ +# define INLINE static inline +#else +# define INLINE static +#endif + +#ifndef NULL +# define NULL ((void *)0) +#endif + +#ifndef LONG_MAX +# define LONG_MAX ( (long) ((~(unsigned long)0) >> 1) ) +#endif + +#ifndef LONG_MIN +# define LONG_MIN ( (long) (((~(unsigned long)0) >> 1) + 1) ) +#endif + +#ifndef INT_MAX +# define INT_MAX ( (int) ((~(unsigned int)0) >> 1) ) +#endif + +#ifndef INT_MIN +# define INT_MIN ( (int) (((~(unsigned int)0) >> 1) + 1) ) +#endif + +#define uSEC_PER_SEC ((long)1000000) /* microseconds in a second */ +#define mSEC_PER_SEC ((long)1000) /* milliseconds in a second */ +#define uSEC_PER_mSEC ((long)1000) /* microseconds in a millisecond */ + +#undef MIN2 +#undef MAX2 +#undef ABS +#undef SIGN +#undef SWAP2 +#define MIN2(a,b) ((a)<(b) ? (a) : (b)) +#define MAX2(a,b) ((a)>(b) ? (a) : (b)) +#define ABS(a) ((a)> 0 ? (a) :(-a)) +#define SIGN(a) ((a)> 0 ? 1 : (a) ? -1 : 0) +#define SWAP2(a,b,c) ((c)=(b), (b)=(a), (a)=(c)) + +/* macros to match parentheses */ +#define ISRPAREN(c) ((c) == ')' || (c) == ']' || (c) == '}') +#define ISLPAREN(c) ((c) == '(' || (c) == '[' || (c) == '{') +#define LPAREN(c) ((c) == ')' ? '(' : ((c) == ']' ? '[' : '{')) + +#define ISODIGIT(c) ((c) >= '0' && (c) <= '7') + +#define PRINTF status(1), tty_printf + +#define INTLEN (3*(1+(int)sizeof(int))) + /* max length of a string representation + * of an int */ +#define LONGLEN (3*(1+(int)sizeof(long))) + /* max length of a string representation + * of a long */ +#define ESC '\\' /* special escape char */ +#define STRESC "\\" +#define ESC2 '`' /* other special escape char */ +#define STRESC2 "`" +#define CMDSEP ';' /* command separator character */ +#define SPECIAL_CHARS "{}();\"=" /* specials chars needing escape */ +#define MPI "~$#E" /* MUME protocol introducer */ +#define MPILEN 4 /* strlen(MPI) */ + +#ifdef NR_OPEN +# define MAX_FDSCAN NR_OPEN +#else +# define MAX_FDSCAN 256 /* max number of fds */ +#endif + +#define MAX_CONNECTS 32 /* max number of open connections. must fit in a byte */ + +#define CAPLEN 20 /* max length of a terminal capability */ +#define BUFSIZE 4096 /* general buffer size */ +#define SOCKBUFSIZE BUFSIZE /* socket buffer size for read */ +#define PARAMLEN 99 /* initial length of text strings */ +#define MAX_MAPLEN 1000 /* maximum length of automapped path */ +#define MIN_WORDLEN 3 /* the minimum length for history words */ +#define MAX_WORDS 512 /* number of words kept for TAB-completion */ +#define MAX_HIST 128 /* number of history lines kept */ +#define LOG_MAX_HASH 7 +#define MAX_HASH (1<<LOG_MAX_HASH) /* max hash value, must be a power of 2 */ +#define NUMPARAM 10 /* number of local unnamed params allowed + * (hardcoded, don't change) */ +#define NUMVAR 50 /* number of global unnamed variables */ +#define NUMTOT (NUMVAR+NUMPARAM) +#define MAX_SUBOPT 256 /* max length of suboption string */ +#define MAX_ARGS 16 /* max number of arguments to editor */ +#define FLASHDELAY 500 /* time of parentheses flash in millisecs */ +#define KBD_TIMEOUT 100 /* timeout for keyboard read in millisecs; + * hope it's enough also for very slow lines */ + +#define MAX_STACK 100 /* maximum number of nested + * action, alias, #for or #while */ +#define MAX_LOOP 10000 /* maximum number of iterations in + * #for or #while */ + +#define ACTION_WEAK 0 /* GH: normal junk */ +#define ACTION_REGEXP 1 /* oh-so-mighty regexp */ +#define ACTION_TYPES (ACTION_REGEXP + 1) + +/* GH: the redefinable delimeters */ +#define DELIM (delim_list[delim_mode]) +#define DELIM_LEN (delim_len[delim_mode]) +#define IS_DELIM(c) (strchr(DELIM, (c))) + +#define DELIM_NORMAL 0 /* GH: normal word delimeters */ +#define DELIM_PROGRAM 1 /* ()[]{}.,;"'+/-*% */ +#define DELIM_CUSTOM 2 /* user-defined */ +#define DELIM_MODES (DELIM_CUSTOM + 1) + + +/* macros to find cursor position from input buffer position */ +#define CURLINE(pos) (((pos) + col0) / cols_1 + line0) +#define CURCOL(pos) (((pos) + col0) % cols_1) + +#define CLIP(a, min, max) ((a)=(a)<(min) ? (min) : (a)>(max) ? (max) : (a)) + +#define ISMARKWILDCARD(c) ((c) == '&' || (c) == '$') + +/* + * Attribute codes: bit 0-4 for foreground color, 5-9 for + * background color, 10-13 for effects. + * Color #16 is "none", so 0x0210 is "no attribute". + */ +#define COLORS 16 /* number of colors on HFT terminal */ +#define LOWCOLORS 8 /* number of ANSI colors */ +#define NO_COLOR COLORS /* no color change, use default */ +#define BITS_COLOR 5 /* bits used for a color entry + (16==none is a valid color) */ +#define BITS_2COLOR 10 /* bits used for 2 color entries */ +#define COLOR_MASK 0x1F /* 5 (BITS_COLOR) bits set to 1, others 0 */ + +#define ATTR_BOLD 0x01 +#define ATTR_BLINK 0x02 +#define ATTR_UNDERLINE 0x04 +#define ATTR_INVERSE 0x08 + +/* + * WARNING: colors and attributes are currently using 14 bits: + * 4 for attributes, 5 for foreground color and 5 for background. + * type used is int and -1 is used as 'invalid attribute' + * so in case ints are 16 bits, there is only 1 bit left unused. + * In case ints are 32 bits, no problem. + */ + +/* constructors / accessors for attribute codes */ +#define ATTRCODE(attr, fg, bg) \ + (((attr) << BITS_2COLOR) | ((bg) << BITS_COLOR) | (fg)) +#define FOREGROUND(attrcode) ((attrcode) & COLOR_MASK) +#define BACKGROUND(attrcode) (((attrcode) >> BITS_COLOR) & COLOR_MASK) +#define ATTR(attrcode) ((attrcode) >> BITS_2COLOR) + +#define NOATTRCODE ATTRCODE(0, NO_COLOR, NO_COLOR) + +/* + * NCSA telnet 2.2 doesn't reset the color when it receives "esc [ m", + * so we must know what the normal colors are in order to reset it. + * These colors can be changed with the #color command. + */ +#ifdef BUG_TELNET +# define DEFAULTFG 7 /* make default white text */ +# define DEFAULTBG 4 /* on blue background */ +#endif + +#define LM_NOECHO 1 /* no local echo */ +#define LM_CHAR 2 /* char-by-char mode (no line editing) */ + + + + + +typedef unsigned char byte; + +typedef void (*function_any) (); /* generic function pointer */ + +typedef void (*function_int) __P ((int i)); + +typedef function_int function_signal; + +typedef void (*function_str) __P ((char *arg)); + +typedef struct timeval vtime; /* needs #include <sys/tyme.h> */ + +#include "ptr.h" + + + + +/* generic linked list node (never actually created) */ +typedef struct defnode { + struct defnode *next; + char *sortfield; +} defnode; + +/* + * twin linked list node: used to build pair of parallel lists, + * one sorted and one not, with the same nodes + */ +typedef struct sortednode { + struct sortednode *next; + char *sortfield; + struct sortednode *snext; +} sortednode; + +/* + * linked list nodes: keep `next' first, then string to sort by, + * then (eventually) `snext' + */ +typedef struct aliasnode { + struct aliasnode *next; + char *name; + struct aliasnode *snext; + char *subst; + char *group; + int active; +} aliasnode; + +typedef struct marknode { + struct marknode *next; + char *pattern; + int attrcode; + char *start, *end; + char mbeg; + char wild; +} marknode; + +typedef struct triggernode { + struct triggernode *next; + char *command, *label; + int active; + int type; /* GH: allow regexp */ + char *pattern; +#ifdef USE_REGEXP + void *regexp; /* 0 if type == ACTION_WEAK */ +#endif + char *group; +} triggernode; + +/* + * HACK WARNING : + * actionnode and promptnode must be the same type + * or search_action_or_prompt() in main.c won't work. + */ +typedef triggernode actionnode; +typedef triggernode promptnode; + +typedef int (*function_sort) __P ((defnode *node1, defnode *node2)); + +typedef struct keynode { + struct keynode *next; + char *name; /* key name */ + char *sequence; /* escape sequence sent by terminal */ + int seqlen; /* GH: length of esc seq to allow \0 in seq */ + function_str funct; /* function called when key pressed */ + char *call_data; /* data passed to function */ +} keynode; + +typedef struct delaynode { + struct delaynode *next; + char *name; + char *command; + vtime when; /* structure containing time when */ + /* command must be executed */ +} delaynode; + +/* Variable struct definitions */ + +typedef struct varnode { /* for named variables */ + struct varnode *next; + char *name; + struct varnode *snext; + int index; + long num; + ptr str; +} varnode; + +typedef struct { /* for unnamed vars */ + long num; + ptr str; +} unnamedvar; + +typedef struct { /* stack of local vars */ + unnamedvar p[MAX_STACK][NUMPARAM]; + int curr; +} param_stack; + +typedef struct { /* pointers to all variables */ + long *num; + ptr *str; +} vars; + +/* editing session control */ +typedef struct editsess { + struct editsess *next; + unsigned int key; /* session identifier */ + int pid; /* pid of child */ + int fd; /* MUD socket to talk with (-1 if non-MUD text) */ + char *descr; /* short description of what we are editing */ + char *file; /* name of temporary file */ + time_t ctime; /* time when temp file was created (upper bound) */ + long oldsize; /* original file size */ + char cancel; /* 1 if cancelled */ +} editsess; + +#endif /* _DEFINES_H_ */ + @@ -0,0 +1,464 @@ +#! /bin/sh + +# depcomp - compile a program generating dependencies as side-effects +# Copyright 1999, 2000 Free Software Foundation, Inc. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>. + +if test -z "$depmode" || test -z "$source" || test -z "$object"; then + echo "depcomp: Variables source, object and depmode must be set" 1>&2 + exit 1 +fi +# `libtool' can also be set to `yes' or `no'. + +if test -z "$depfile"; then + base=`echo "$object" | sed -e 's,^.*/,,' -e 's,\.\([^.]*\)$,.P\1,'` + dir=`echo "$object" | sed 's,/.*$,/,'` + if test "$dir" = "$object"; then + dir= + fi + # FIXME: should be _deps on DOS. + depfile="$dir.deps/$base" +fi + +tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} + +rm -f "$tmpdepfile" + +# Some modes work just like other modes, but use different flags. We +# parameterize here, but still list the modes in the big case below, +# to make depend.m4 easier to write. Note that we *cannot* use a case +# here, because this file can only contain one case statement. +if test "$depmode" = hp; then + # HP compiler uses -M and no extra arg. + gccflag=-M + depmode=gcc +fi + +if test "$depmode" = dashXmstdout; then + # This is just like dashmstdout with a different argument. + dashmflag=-xM + depmode=dashmstdout +fi + +case "$depmode" in +gcc3) +## gcc 3 implements dependency tracking that does exactly what +## we want. Yay! Note: for some reason libtool 1.4 doesn't like +## it if -MD -MP comes after the -MF stuff. Hmm. + "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + mv "$tmpdepfile" "$depfile" + ;; + +gcc) +## There are various ways to get dependency output from gcc. Here's +## why we pick this rather obscure method: +## - Don't want to use -MD because we'd like the dependencies to end +## up in a subdir. Having to rename by hand is ugly. +## (We might end up doing this anyway to support other compilers.) +## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like +## -MM, not -M (despite what the docs say). +## - Using -M directly means running the compiler twice (even worse +## than renaming). + if test -z "$gccflag"; then + gccflag=-MD, + fi + "$@" -Wp,"$gccflag$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz +## The second -e expression handles DOS-style file names with drive letters. + sed -e 's/^[^:]*: / /' \ + -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" +## This next piece of magic avoids the `deleted header file' problem. +## The problem is that when a header file which appears in a .P file +## is deleted, the dependency causes make to die (because there is +## typically no way to rebuild the header). We avoid this by adding +## dummy dependencies for each header file. Too bad gcc doesn't do +## this for us directly. + tr ' ' ' +' < "$tmpdepfile" | +## Some versions of gcc put a space before the `:'. On the theory +## that the space means something, we add a space to the output as +## well. +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +sgi) + if test "$libtool" = yes; then + "$@" "-Wp,-MDupdate,$tmpdepfile" + else + "$@" -MDupdate "$tmpdepfile" + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + + if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files + echo "$object : \\" > "$depfile" + + # Clip off the initial element (the dependent). Don't try to be + # clever and replace this with sed code, as IRIX sed won't handle + # lines with more than a fixed number of characters (4096 in + # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; + # the IRIX cc adds comments like `#:fec' to the end of the + # dependency line. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ + tr ' +' ' ' >> $depfile + echo >> $depfile + + # The second pass generates a dummy entry for each header file. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ + >> $depfile + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +aix) + # The C for AIX Compiler uses -M and outputs the dependencies + # in a .u file. This file always lives in the current directory. + # Also, the AIX compiler puts `$object:' at the start of each line; + # $object doesn't have directory information. + stripped=`echo "$object" | sed -e 's,^.*/,,' -e 's/\(.*\)\..*$/\1/'` + tmpdepfile="$stripped.u" + outname="$stripped.o" + if test "$libtool" = yes; then + "$@" -Wc,-M + else + "$@" -M + fi + + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + + if test -f "$tmpdepfile"; then + # Each line is of the form `foo.o: dependent.h'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile" + sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +icc) + # Must come before tru64. + + # Intel's C compiler understands `-MD -MF file'. However + # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c + # will fill foo.d with something like + # foo.o: sub/foo.c + # foo.o: sub/foo.h + # which is wrong. We want: + # sub/foo.o: sub/foo.c + # sub/foo.o: sub/foo.h + # sub/foo.c: + # sub/foo.h: + + "$@" -MD -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + # Each line is of the form `foo.o: dependent.h'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed -e "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" + sed -e "s,^[^:]*: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile" + rm -f "$tmpdepfile" + ;; + +tru64) + # The Tru64 compiler uses -MD to generate dependencies as a side + # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. + # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put + # dependencies in `foo.d' instead, so we check for that too. + # Subdirectories are respected. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + + if test "$libtool" = yes; then + tmpdepfile1="$dir.libs/$base.lo.d" + tmpdepfile2="$dir.libs/$base.d" + "$@" -Wc,-MD + else + tmpdepfile1="$dir$base.o.d" + tmpdepfile2="$dir$base.d" + "$@" -MD + fi + + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" + exit $stat + fi + + if test -f "$tmpdepfile1"; then + tmpdepfile="$tmpdepfile1" + else + tmpdepfile="$tmpdepfile2" + fi + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + # That's a space and a tab in the []. + sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +#nosideeffect) + # This comment above is used by automake to tell side-effect + # dependency tracking mechanisms from slower ones. + +dashmstdout) + # Important note: in order to support this mode, a compiler *must* + # always write the proprocessed file to stdout, regardless of -o. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + test -z "$dashmflag" && dashmflag=-M + # Require at least two characters before searching for `:' + # in the target name. This is to cope with DOS-style filenames: + # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise. + "$@" $dashmflag | + sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + tr ' ' ' +' < "$tmpdepfile" | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +dashXmstdout) + # This case only exists to satisfy depend.m4. It is never actually + # run, as this mode is specially recognized in the preamble. + exit 1 + ;; + +makedepend) + "$@" || exit $? + # Remove any Libtool call + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + # X makedepend + shift + cleared=no + for arg in "$@"; do + case $cleared in + no) + set ""; shift + cleared=yes ;; + esac + case "$arg" in + -D*|-I*) + set fnord "$@" "$arg"; shift ;; + # Strip any option that makedepend may not understand. Remove + # the object too, otherwise makedepend will parse it as a source file. + -*|$object) + ;; + *) + set fnord "$@" "$arg"; shift ;; + esac + done + obj_suffix="`echo $object | sed 's/^.*\././'`" + touch "$tmpdepfile" + ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + sed '1,2d' "$tmpdepfile" | tr ' ' ' +' | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" "$tmpdepfile".bak + ;; + +cpp) + # Important note: in order to support this mode, a compiler *must* + # always write the proprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + "$@" -E | + sed -n '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | + sed '$ s: \\$::' > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + cat < "$tmpdepfile" >> "$depfile" + sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvisualcpp) + # Important note: in order to support this mode, a compiler *must* + # always write the proprocessed file to stdout, regardless of -o, + # because we must use -o when running libtool. + "$@" || exit $? + IFS=" " + for arg + do + case "$arg" in + "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") + set fnord "$@" + shift + shift + ;; + *) + set fnord "$@" "$arg" + shift + shift + ;; + esac + done + "$@" -E | + sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" + echo " " >> "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +none) + exec "$@" + ;; + +*) + echo "Unknown depmode $depmode" 1>&2 + exit 1 + ;; +esac + +exit 0 @@ -0,0 +1,886 @@ +/* + * edit.c -- line editing functions for powwow + * + * Copyright (C) 1998 by Massimiliano Ghilardi + * + * 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. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <ctype.h> +#include <time.h> +#include <sys/types.h> +#include <sys/time.h> + +#include "defines.h" +#include "main.h" +#include "utils.h" +#include "cmd.h" +#include "edit.h" +#include "tcp.h" +#include "tty.h" +#include "eval.h" +#include "log.h" + +static void insert_string __P ((char *arg)); + +/* history buffer */ +char *hist[MAX_HIST]; /* saved history lines */ +int curline = 0; /* current history line */ +int pickline = 0; /* line to pick history from */ + +/* word completion list */ +wordnode words[MAX_WORDS]; +int wordindex = 0; + +edit_function internal_functions[] = { + {(char *)0, (function_str)0, }, + {"&enter-line", enter_line, }, + {"&complete-word", complete_word, }, + {"&complete-line", complete_line, }, + {"&del-char-left", del_char_left, }, + {"&del-char-right", del_char_right, }, + {"&prev-char", prev_char, }, + {"&prev-line", prev_line, }, + {"&next-char", next_char, }, + {"&next-line", next_line, }, + {"&to-history", to_history, }, + {"&clear-line", clear_line, }, + {"&redraw-line", redraw_line, }, + {"&redraw-line-noprompt", redraw_line_noprompt, }, + {"&begin-of-line", begin_of_line, }, + {"&end-of-line", end_of_line, }, + {"&kill-to-eol", kill_to_eol, }, + {"&transpose", transpose_chars, }, + {"&transpose-words", transpose_words, }, + {"&suspend", (function_str)suspend_powwow, }, /* yep, it's an hack */ + {"&del-word-left", del_word_left, }, + {"&del-word-right", del_word_right, }, + {"&prev-word", prev_word, }, + {"&upcase-word", upcase_word, }, + {"&downcase-word", downcase_word, }, + {"&next-word", next_word, }, + {"&insert-string", insert_string, }, + {(char *)0, (function_str)0 } +}; + +int lookup_edit_name __P2 (char *,name, char **,arg) +{ + int i, len, flen; + char *fname, *extra = NULL; + + if ((fname = strchr(name, ' '))) + len = fname - name; + else + len = strlen(name); + + for (i=1; (fname = internal_functions[i].name); i++) { + flen = strlen(fname); + if (flen == len && !strncmp(name, fname, flen)) { + extra = name + flen; + if (*extra == ' ') extra++; + if (!*extra) extra = NULL; + *arg = extra; + return i; + } + } + *arg = extra; + return 0; +} + +int lookup_edit_function __P1 (function_str,funct) +{ + int i; + function_str ffunct; + + for (i = 1; (ffunct = internal_functions[i].funct); i++) + if (funct == ffunct) + return i; + + return 0; +} + +/* + * redisplay the prompt + * assume cursor is at beginning of line + */ +void draw_prompt __P0 (void) +{ + if (promptlen && prompt_status == 1) { + int e = error; + error = 0; + marked_prompt = ptraddmarks(marked_prompt, prompt->str); + if (MEM_ERROR) { promptzero(); errmsg("malloc(prompt)"); return; } + tty_puts(ptrdata(marked_prompt)); + col0 = printstrlen(promptstr); /* same as printstrlen(marked_prompt) */ + error = e; + } + prompt_status = 0; +} + +/* + * clear current input line (deleteprompt == 1 if to clear also prompt) + * cursor is left right after the prompt. + * + * since we do not expect data from the user at this point, + * do not print edattrbeg now. + */ +void clear_input_line __P1 (int,deleteprompt) +{ + /* + * be careful: if prompt and/or input line have been erased from screen, + * pos will be different from the actual cursor position + */ + if ((edlen && line_status == 0) || (promptlen && prompt_status == 0 && deleteprompt)) { + int newcol = deleteprompt ? 0 : col0; + int realpos = line_status == 0 ? pos : (prompt_status == 0 ? 0 : -col0); + + tty_gotoxy_opt(CURCOL(realpos), CURLINE(realpos), newcol, line0); + tty_puts(edattrend); + if (line0 < lines - 1) + tty_puts(tty_clreoscr); + else + tty_puts(tty_clreoln); + col0 = newcol; + } else { + tty_puts(edattrend); + } + if (deleteprompt) + status(1); + else + line_status = 1; +} + +/* + * clear input line, but do nothing else + */ +void clear_line __P1 (char *,dummy) +{ + if (!edlen) + return; + clear_input_line(0); + pickline = curline; + *edbuf = '\0'; + pos = edlen = 0; +} + +/* + * Redraw the input line and put the cursor at the current position. + * The cursor is assumed to be directly after the prompt. + */ +void draw_input_line __P0 (void) +{ + int i, oldline0; + + if (line_status == 0 || linemode & LM_NOECHO) + return; + + tty_puts(edattrbeg); + + if (edlen) { + oldline0 = line0; + if (edlen < cols_1 - col0) { + tty_puts(edbuf); + } else { + tty_printf("%.*s", cols_1 - col0, edbuf); + for (i = cols_1 - col0; i <= edlen; i += cols_1) { +#ifdef BUG_ANSI + if (edattrbg) + tty_printf("%s\n%s%.*s", edattrend, edattrbeg, cols_1, edbuf + i); + else +#endif + tty_printf("\n%.*s", cols_1, edbuf + i); + } + } + line0 = lines - (edlen + col0) / cols_1 - 1; + if (line0 > oldline0) + line0 = oldline0; + if ((i = CURLINE(pos)) < 0) + line0 -= i; + else if (i > lines - 1) + line0 -= i - lines + 1; + tty_gotoxy_opt(CURCOL(edlen), CURLINE(edlen), CURCOL(pos), CURLINE(pos)); + } + line_status = 0; +} + +/* + * redraw the input line + */ +void redraw_line __P1 (char *,dummy) +{ + clear_input_line(1); +} + +/* + * redraw the input line, clearing the prompt + */ +void redraw_line_noprompt __P1 (char *,dummy) +{ + clear_input_line(0); + tty_putc('\n'); + if (line0 < lines - 1) + line0++; + status(-1); +} + +/* + * GH: transpose two words to the left + */ +void transpose_words __P1 (char *,dummy) +{ + /* other refers to the word to the left, this is the one we are at */ + + int this_so, other_so, this_eo, other_eo; + char buf[BUFSIZE]; + int n; + + if (pos > 2) { + + this_eo = this_so = pos; + /* optionally traceback to find a word */ + while (this_so && strchr(DELIM, edbuf[this_so])) + this_so--; + + /* now find where the current word ends */ + while (this_eo < edlen && !strchr(DELIM, edbuf[this_eo])) + this_eo++; + + /* found a word; now find its start */ + while (this_so > 0 && !strchr(DELIM, edbuf[this_so - 1])) + this_so--; + + if (this_so < 2) + return; /* impossible that there's another word */ + + other_so = this_so - 1; + while (other_so >= 0 && strchr(DELIM, edbuf[other_so])) + other_so--; + if (other_so < 0) + return; + other_eo = other_so + 1; + while (other_so > 0 && !strchr(DELIM, edbuf[other_so - 1])) + other_so--; + + sprintf(buf, "%.*s%.*s%.*s", + this_eo - this_so, edbuf + this_so, + this_so - other_eo, edbuf + other_eo, + other_eo - other_so, edbuf + other_so); + + input_moveto(other_so); + for (n = 0; buf[n]; input_overtype_follow(buf[n++])) + ; + } +} + +/* + * transpose two characters to the left + */ +void transpose_chars __P1 (char *,dummy) +{ + int i, j; + char c; + if (pos > 1 || (pos > 0 && pos < edlen)) { + if (pos < edlen) { + j = pos; + i = pos - 1; + } else { + j = pos - 1; + i = pos - 2; + } + c = edbuf[j]; edbuf[j] = edbuf[i]; edbuf[i] = c; + + if (line_status == 0) { + tty_gotoxy_opt(CURCOL(pos), CURLINE(pos), CURCOL(i), CURLINE(i)); + tty_putc(edbuf[i]); + tty_gotoxy_opt(CURCOL(i+1), CURLINE(i+1), CURCOL(j), CURLINE(j)); + tty_putc(edbuf[j]); + if (pos < edlen) { + pos++; + tty_gotoxy_opt(CURCOL(j+1), CURLINE(j+1), CURCOL(pos), CURLINE(pos)); + } + } else + pos++; + } +} + +/* + * erase everything to the end of line + */ +void kill_to_eol __P1 (char *,dummy) +{ + if (line_status == 0) { + if (edattrbg) + tty_printf("%s%s", edattrend, tty_clreoln); + else + tty_puts(tty_clreoln); + if (CURLINE(edlen) > CURLINE(pos)) { + tty_printf("\n%s", tty_clreoscr); + tty_gotoxy_opt(0, CURLINE(pos) + 1, CURCOL(pos), CURLINE(pos)); + } + if (edattrbg) + tty_puts(edattrbeg); + } + edbuf[edlen = pos] = '\0'; +} + +/* + * move cursor to end of line + */ +void end_of_line __P1 (char *,dummy) +{ + input_moveto(edlen); +} + +/* + * move cursor to beginning of line + */ +void begin_of_line __P1 (char *,dummy) +{ + input_moveto(0); +} + +/* + * delete a character to the right + */ +void del_char_right __P1 (char *,dummy) +{ + input_delete_nofollow_chars(1); +} + +/* + * delete a character to the left + */ +void del_char_left __P1 (char *,dummy) +{ + if (pos) { + input_moveto(pos-1); + input_delete_nofollow_chars(1); + } +} + +/* + * move a line into history, but don't do anything else + */ +void to_history __P1 (char *,dummy) +{ + if (!edlen) + return; + clear_input_line(0); + put_history(edbuf); + pickline = curline; + *edbuf = '\0'; + pos = edlen = 0; +} + +/* + * put string in history at current position + * (string is assumed to be trashable) + */ +void put_history __P1 (char *,str) +{ + char *p; + if (hist[curline]) free(hist[curline]); + if (!(hist[curline] = my_strdup(str))) { + errmsg("malloc"); + return; + } + + if (++curline == MAX_HIST) + curline = 0; + + /* split into words and put into completion list */ + for (p = strtok(str, DELIM); p; + p = strtok(NULL, DELIM)) { + if (strlen(p) >= MIN_WORDLEN && + p[0] != '#') /* no commands/short words */ + put_word(p); + } +} + +/* + * move a node before wordindex, i.e. make it the last word + */ +static void demote_word __P1 (int,i) +{ + words[words[i].prev].next = words[i].next; + words[words[i].next].prev = words[i].prev; + words[i].prev = words[words[i].next = wordindex].prev; + words[wordindex].prev = words[words[wordindex].prev].next = i; +} + +/* + * match and complete a word referring to the word list + */ +void complete_word __P1 (char *,dummy) +{ + /* + * GH: rewritten to allow circulating through history with repetitive command + * code stolen from cancan 2.6.3a + * curr_word: index into words[] + * comp_len length of current completition + * root_len length of the root word (before the completition) + * root start of the root word + */ + + static int curr_word, comp_len = 0, root_len = 0; + char *root, *p; + int k, n; + + /* find word start */ + if (last_edit_cmd == (function_any)complete_word && comp_len) { + k = comp_len; + input_moveto(pos - k); + n = pos - root_len; + } else { + for (n = pos; n > 0 && !IS_DELIM(edbuf[n - 1]); n--) + ; + k = 0; + curr_word = wordindex; + root_len = pos - n; + } + root = edbuf + n; comp_len = 0; + + /* k = chars to delete, n = position of starting word */ + + /* scan word list for next match */ + while ((p = words[curr_word = words[curr_word].next].word)) { + if (!strncasecmp(p, root, root_len) && + *(p += root_len) && + (n = strlen(p)) + edlen < BUFSIZE) { + comp_len = n; + for (; k && n; k--, n--) + input_overtype_follow(*p++); + if (n > 0) + input_insert_follow_chars(p, n); + break; + } + } + if (k > 0) + input_delete_nofollow_chars(k); + + /* delete duplicate instances of the word */ + if (p && !(words[k = curr_word].flags & WORD_UNIQUE)) { + words[k].flags |= WORD_UNIQUE; + p = words[k].word; + n = words[k].next; + while (words[k = n].word) { + n = words[k].next; + if (!strcmp(p, words[k].word)) { + demote_word(k); + free(words[k].word); + words[k].word = 0; + words[curr_word].flags |= words[k].flags; /* move retain flag */ + if ((words[k].flags &= WORD_UNIQUE)) + break; + } + } + } +} + +/* + * match and complete entire lines backwards in history + * GH: made repeated complete_line cycle through history + */ +void complete_line __P1 (char *,dummy) +{ + static int curr_line = MAX_HIST-1, root_len = 0, first_line = 0; + int i; + + if (last_edit_cmd != (function_any)complete_line) { + root_len = edlen; + first_line = curr_line = curline; + } + + for (i = curr_line - 1; i != curr_line; i--) { + if (i < 0) i = MAX_HIST - 1; + if (i == first_line) + break; + if (hist[i] && !strncmp(edbuf, hist[i], root_len)) + break; + } + if (i != curr_line) { + clear_input_line(0); + if (i == first_line) { + edbuf[root_len] = 0; + edlen = root_len; + } else { + strcpy(edbuf, hist[i]); + edlen = strlen(edbuf); + } + pos = edlen; + curr_line = i; + } +} + +/* + * GH: word history handling stolen from cancan 2.6.3a + */ + +static void default_completions __P0 (void) +{ + char buf[BUFSIZE]; + cmdstruct *p; + int i; + for (i = 0, buf[0] = '#', p = commands; p->name; p++) + if (p->funct /*&& strlen(p->name) >= 3*/ ) { + if (++i >= MAX_WORDS) break; + strcpy(buf + 1, p->name); + if (!(words[i].word = my_strdup(buf))) + syserr("malloc"); + words[i].flags = WORD_UNIQUE | WORD_RETAIN; + } + for (i = MAX_WORDS; i--; words[i].prev = i - 1, words[i].next = i + 1) + ; + words[0].prev = MAX_WORDS - 1; + words[MAX_WORDS - 1].next = 0; +} + +/* + * put word in word completion ring + */ +void put_word __P1 (char *,s) +{ + int r = wordindex; + if (!(words[r].word = my_strdup(s))) { + errmsg("malloc"); + return; + } + words[r].flags = 0; + while (words[r = words[r].prev].flags & WORD_RETAIN) + ; + demote_word(r); + wordindex = r; + if (words[r].word) { + free(words[r].word); + words[r].word = 0; + } +} + +/* + * GH: set delimeters[DELIM_CUSTOM] + */ +void set_custom_delimeters __P1 (char *,s) +{ + char *old = delim_list[DELIM_CUSTOM]; + if (!(delim_list[DELIM_CUSTOM] = my_strdup(s))) + errmsg("malloc"); + else { + if (old) + free(old); + delim_len[DELIM_CUSTOM] = strlen(s); + delim_mode = DELIM_CUSTOM; + } +} + +/* + * enter a line + */ +void enter_line __P1 (char *,dummy) +{ + char *p; + + if (line_status == 0) + input_moveto(edlen); + else { + if (prompt_status != 0) + col0 = 0; + draw_input_line(); + } + PRINTF("%s\n", edattrend); + + line0 = CURLINE(edlen); + if (line0 < lines - 1) line0++; + + if (recordfile) + fprintf(recordfile, "%s\n", edbuf); + + col0 = error = pos = line_status = 0; + + if (!*edbuf || (verbatim && *edbuf != '#')) + tcp_write(tcp_fd, edbuf); + else + parse_user_input(edbuf, 1); + history_done = 0; + + /* don't put identical lines in history, nor empty ones */ + p = hist[curline ? curline - 1 : MAX_HIST - 1]; + if (!p || (edlen > 0 && strcmp(edbuf, p))) + put_history(edbuf); + pickline = curline; + if (*inserted_next) { + strcpy(edbuf, inserted_next); + inserted_next[0] = '\0'; + line_status = 1; + } else if (*prefixstr) { + strcpy(edbuf, prefixstr); + line_status = 1; + } else + edbuf[0] = '\0'; + pos = edlen = strlen(edbuf); +} + +/* + * move one word forward + */ +void next_word __P1 (char *,dummy) +{ + int i; + for (i = pos; edbuf[i] && !isalnum(edbuf[i]); i++) + ; + while (isalnum(edbuf[i])) + i++; + input_moveto(i); +} + +/* + * move one word backward + */ +void prev_word __P1 (char *,dummy) +{ + int i; + for (i = pos; i && !isalnum(edbuf[i - 1]); i--) + ; + while (i && isalnum(edbuf[i - 1])) + i--; + input_moveto(i); +} + +/* + * delete word to the right + */ +void del_word_right __P1 (char *,dummy) +{ + int i; + for (i = pos; edbuf[i] && !isalnum(edbuf[i]); i++) + ; + while (isalnum(edbuf[i])) + i++; + input_delete_nofollow_chars(i - pos); +} + +/* + * delete word to the left + */ +void del_word_left __P1 (char *,dummy) +{ + int i; + for (i = pos; i && !isalnum(edbuf[i - 1]); i--) + ; + while (i && isalnum(edbuf[i - 1])) + i--; + i = pos - i; + input_moveto(pos - i); + input_delete_nofollow_chars(i); +} + +/* + * GH: make word upcase + */ +void upcase_word __P1 (char *,dummy) +{ + int opos = pos; + + if (last_edit_cmd == (function_any)upcase_word) + pos = 0; + else { + while (pos > 0 && IS_DELIM(edbuf[pos])) pos--; + while (pos > 0 && !IS_DELIM(edbuf[pos - 1])) pos--; + } + input_moveto(pos); + while (!IS_DELIM(edbuf[pos]) || + (last_edit_cmd == (function_any)upcase_word && edbuf[pos])) + input_overtype_follow(toupper(edbuf[pos])); + input_moveto(opos); +} + +/* + * GH: make word downcase + */ +void downcase_word __P1 (char *,dummy) +{ + int opos = pos; + + if (last_edit_cmd == (function_any)downcase_word) + pos = 0; + else { + while (pos > 0 && IS_DELIM(edbuf[pos])) pos--; + while (pos > 0 && !IS_DELIM(edbuf[pos - 1])) pos--; + } + input_moveto(pos); + while (!IS_DELIM(edbuf[pos]) || + (last_edit_cmd == (function_any)downcase_word && edbuf[pos])) { + input_overtype_follow(tolower(edbuf[pos])); + } + input_moveto(opos); +} + +/* + * get previous line from history list + */ +void prev_line __P1 (char *,dummy) +{ + int i = pickline - 1; + if (i < 0) i = MAX_HIST - 1; + if (hist[i]) { + if (hist[pickline] && strcmp(hist[pickline], edbuf)) { + free(hist[pickline]); + hist[pickline] = NULL; + } + if (!hist[pickline]) { + if (!(hist[pickline] = my_strdup(edbuf))) { + errmsg("malloc"); + return; + } + } + pickline = i; + clear_input_line(0); + strcpy(edbuf, hist[pickline]); + pos = edlen = strlen(edbuf); + } +} + +/* + * get next line from history list + */ +void next_line __P1 (char *,dummy) +{ + int i = pickline + 1; + if (i == MAX_HIST) i = 0; + if (hist[i]) { + if (hist[pickline] && strcmp(hist[pickline], edbuf)) { + free(hist[pickline]); + hist[pickline] = NULL; + } + if (!hist[pickline]) { + if (!(hist[pickline] = my_strdup(edbuf))) { + errmsg("malloc"); + return; + } + } + pickline = i; + clear_input_line(0); + strcpy(edbuf, hist[pickline]); + edlen = pos = strlen(edbuf); + } +} + +/* + * move one char backward + */ +void prev_char __P1 (char *,dummy) +{ + input_moveto(pos-1); +} + +/* + * move one char forward + */ +void next_char __P1 (char *,dummy) +{ + input_moveto(pos+1); +} + +/* + * Flash cursor at parentheses that matches c inserted before current pos + */ +static void flashparen __P1 (char,c) +{ + int lev, i; + if (line_status != 0) + return; + for (i = pos - 1, lev = 0; i >= 0; i--) { + if (ISRPAREN(edbuf[i])) { + lev++; + } else if (ISLPAREN(edbuf[i])) { + lev--; + if (!lev) { + if (LPAREN(c) == edbuf[i]) + break; + else + i = -1; + } + } + } + if (i >= 0) { + tty_gotoxy_opt(CURCOL(pos), CURLINE(pos), CURCOL(i), CURLINE(i)); + flashback = 1; + excursion = i; + } +} + +/* + * put cursor back where it belongs + */ +void putbackcursor __P0 (void) +{ + if (line_status == 0) + tty_gotoxy_opt(CURCOL(excursion), CURLINE(excursion), CURCOL(pos), CURLINE(pos)); + flashback = 0; +} + +/* + * insert a typed character on screen (if it is printable) + */ +void insert_char __P1 (char,c) +{ + if (((c & 0x80) || (c >= ' ' && c <= '~')) && edlen < BUFSIZE - 2) { + if (flashback) putbackcursor(); + input_insert_follow_chars(&c, 1); + if (ISRPAREN(c)) + flashparen(c); + } +} + +static void insert_string __P1 (char *,arg) +{ + char buf[BUFSIZE]; + int len; + + if (!arg || !*arg) + return; + + my_strncpy(buf, arg, BUFSIZE-1); + unescape(buf); + len = strlen(buf); + + if (len > 1) { + if (flashback) putbackcursor(); + input_insert_follow_chars(buf, len); + } else if (len == 1) + insert_char(buf[0]); /* also flash matching parentheses */ +} + +/* + * execute string as if typed + */ +void key_run_command __P1 (char *,cmd) +{ + clear_input_line(opt_compact && !echo_key); + if (echo_key) { + tty_printf("%s%s%s\n", edattrbeg, cmd, edattrend); + } else if (!opt_compact) + tty_putc('\n'); + + status(1); + error = 0; + + if (recordfile) + fprintf(recordfile, "%s\n", edbuf); + + parse_instruction(cmd, 1, 0, 1); + history_done = 0; +} + +void edit_bootstrap __P0 (void) +{ + default_completions(); +} + @@ -0,0 +1,75 @@ +/* public things from edit.c */ + +#ifndef _EDIT_H_ +#define _EDIT_H_ + +typedef struct { + char *name; + function_str funct; +} edit_function; + +extern edit_function internal_functions[]; + +/* + * GH: completion list, stolen from cancan 2.6.3a + * + * words[wordindex] is where the next word will go (always empty) + * words[wordindex].prev is last (least interesting) + * words[wordindex].next is 2nd (first to search for completion) + */ +#define WORD_UNIQUE 1 /* word is unique in list */ +#define WORD_RETAIN 2 /* permanent (#command) */ +typedef struct { + char *word; + int next, prev; + char flags; +} wordnode; + +extern char *hist[MAX_HIST]; +extern int curline; +extern int pickline; + +extern wordnode words[MAX_WORDS]; +extern int wordindex; + +/* public function declarations */ +void edit_bootstrap __P ((void)); + +int lookup_edit_name __P ((char *name, char **arg)); +int lookup_edit_function __P ((function_str funct)); +void draw_prompt __P ((void)); +void clear_input_line __P ((int deleteprompt)); +void draw_input_line __P ((void)); +void redraw_line __P ((char *dummy)); +void redraw_line_noprompt __P ((char *dummy)); +void transpose_words __P ((char *dummy)); +void transpose_chars __P ((char *dummy)); +void kill_to_eol __P ((char *dummy)); +void end_of_line __P ((char *dummy)); +void begin_of_line __P ((char *dummy)); +void del_char_right __P ((char *dummy)); +void del_char_left __P ((char *dummy)); +void to_history __P ((char *dummy)); +void put_history __P ((char *str)); +void complete_word __P ((char *dummy)); +void complete_line __P ((char *dummy)); +void put_word __P ((char *s)); +void set_custom_delimeters __P ((char *s)); +void to_input_line __P ((char *str)); +void clear_line __P ((char *dummy)); +void enter_line __P ((char *dummy)); +void putbackcursor __P ((void)); +void insert_char __P ((char c)); +void next_word __P ((char *dummy)); +void prev_word __P ((char *dummy)); +void del_word_right __P ((char *dummy)); +void del_word_left __P ((char *dummy)); +void upcase_word __P ((char *dummy)); +void downcase_word __P ((char *dummy)); +void prev_line __P ((char *dummy)); +void next_line __P ((char *dummy)); +void prev_char __P ((char *dummy)); +void next_char __P ((char *dummy)); +void key_run_command __P ((char *cmd)); + +#endif /* _EDIT_H_ */ @@ -0,0 +1,1450 @@ +/* + * eval.c -- functions for builtin calculator + * + * (created: Massimiliano Ghilardi (Cosmos), Jan 15th, 1995) + * + * Copyright (C) 1998 by Massimiliano Ghilardi + * + * 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. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> +#include <unistd.h> +#include <time.h> +#include <sys/types.h> +#include <sys/time.h> +#include <limits.h> + +#include "defines.h" +#include "main.h" +#include "utils.h" +#include "cmd2.h" +#include "list.h" +#include "map.h" +#include "tty.h" +#include "edit.h" +#include "eval.h" + +#ifdef USE_RANDOM +# define get_random random +# define init_random srandom +#else +# define get_random lrand48 +# define init_random srand48 +#endif + +typedef struct { + int type; + long num; /* used for numeric types or as index for all variables */ + ptr txt; /* used for text types */ +} object; + +#define LEFT 1 +#define RIGHT 2 + +#define BINARY 0 +#define PRE_UNARY LEFT +#define POST_UNARY RIGHT + +#define LOWEST_UNARY_CODE 49 +/* + * it would be 47, but operators 47 '(' and 48 ')' + * are treated separately + */ + +enum op_codes { + null=0, comma, eq, or_or_eq, xor_xor_eq, and_and_eq, or_eq, xor_eq, and_eq, + lshift_eq, rshift_eq, plus_eq, minus_eq, times_eq, div_eq, ampersand_eq, + or_or, xor_xor, and_and, or, xor, and, + less, less_eq, greater, greater_eq, eq_eq, not_eq, + lshift, rshift, plus, minus, times, division, ampersand, + + colon_less, colon_greater, less_colon, greater_colon, + point_less, point_greater, less_point, greater_point, + colon, point, question, another_null, + + left_paren, right_paren, not, tilde, + pre_plus_plus, post_plus_plus, pre_minus_minus, post_minus_minus, + star, print, _random_, _attr_, colon_question, point_question, + pre_plus, pre_minus, a_circle, dollar, pre_null, post_null +}; + +typedef enum op_codes operator; + +typedef struct { + char priority, assoc, syntax, *name; + operator code; +} operator_list; + +typedef struct { + object obj[MAX_STACK]; + int curr_obj; + operator op[MAX_STACK]; + int curr_op; +} stack; + +char *error_msg[] = { + "unknown error", + "math stack overflow", + "math stack underflow", + "stack overflow", + "stack underflow", + "expression syntax", + "operator expected", + "value expected", + "division by zero", + "operand or index out of range", + "missing right parenthesis", + "missing left parenthesis", + "internal error!", + "operator not supported", + "operation not completed (internal error)", + "out of memory", + "text/string longer than limit, discarded", + "infinite loop", + "numeric value expected", + "string expected", + "missing label", + "missing separator `;'", + "#history recursion too deep", + "user break", + "too many defined variables", + "undefined variable", + "invalid digit in numeric value", + "bad attribute syntax", + "invalid variable name", +}; + +operator_list op_list[] = { + { 0, 0, 0, "", null }, + + { 1, LEFT, BINARY, ",", comma }, + + { 2, RIGHT, BINARY, "=", eq }, + { 2, RIGHT, BINARY, "||=", or_or_eq }, + { 2, RIGHT, BINARY, "^^=", xor_xor_eq }, + { 2, RIGHT, BINARY, "&&=", and_and_eq }, + { 2, RIGHT, BINARY, "|=", or_eq }, + { 2, RIGHT, BINARY, "^=", xor_eq }, + { 2, RIGHT, BINARY, "&=", and_eq }, + { 2, RIGHT, BINARY, "<<=", lshift_eq }, + { 2, RIGHT, BINARY, ">>=", rshift_eq }, + { 2, RIGHT, BINARY, "+=", plus_eq }, + { 2, RIGHT, BINARY, "-=", minus_eq }, + { 2, RIGHT, BINARY, "*=", times_eq }, + { 2, RIGHT, BINARY, "/=", div_eq }, + { 2, RIGHT, BINARY, "%=", ampersand_eq }, + + { 3, LEFT, BINARY, "||", or_or }, + + { 4, LEFT, BINARY, "^^", xor_xor }, + + { 5, LEFT, BINARY, "&&", and_and }, + + { 6, LEFT, BINARY, "|", or }, + + { 7, LEFT, BINARY, "^", xor }, + + { 8, LEFT, BINARY, "&", and }, + + { 9, LEFT, BINARY, "<", less }, + { 9, LEFT, BINARY, "<=", less_eq }, + { 9, LEFT, BINARY, ">", greater }, + { 9, LEFT, BINARY, ">=", greater_eq }, + { 9, LEFT, BINARY, "==", eq_eq }, + { 9, LEFT, BINARY, "!=", not_eq }, + + {10, LEFT, BINARY, "<<", lshift }, + {10, LEFT, BINARY, ">>", rshift }, + + {11, LEFT, BINARY, "+", plus }, + {11, LEFT, BINARY, "-", minus }, + + {12, LEFT, BINARY, "*", times }, + {12, LEFT, BINARY, "/", division }, + {12, LEFT, BINARY, "%", ampersand }, + + {14, LEFT, BINARY, ":<", colon_less }, + {14, LEFT, BINARY, ":>", colon_greater }, + {14, LEFT, BINARY, "<:", less_colon }, + {14, LEFT, BINARY, ">:", greater_colon }, + {14, LEFT, BINARY, ".<", point_less }, + {14, LEFT, BINARY, ".>", point_greater }, + {14, LEFT, BINARY, "<.", less_point }, + {14, LEFT, BINARY, ">.", greater_point }, + {14, LEFT, BINARY, ":", colon }, + {14, LEFT, BINARY, ".", point }, + {14, LEFT, BINARY, "?", question }, + + { 0, 0, 0, "", another_null }, + + { 0, RIGHT, PRE_UNARY, "(", left_paren }, + { 0, RIGHT, POST_UNARY, ")", right_paren }, + + {13, RIGHT, PRE_UNARY, "!", not }, + {13, RIGHT, PRE_UNARY, "~", tilde }, + {13, RIGHT, PRE_UNARY, "++", pre_plus_plus }, + {13, RIGHT, POST_UNARY, "++", post_plus_plus }, + {13, RIGHT, PRE_UNARY, "--", pre_minus_minus }, + {13, RIGHT, POST_UNARY, "--", post_minus_minus }, + {13, RIGHT, PRE_UNARY, "*", star }, + {13, RIGHT, PRE_UNARY, "%", print }, + {13, RIGHT, PRE_UNARY, "rand", _random_ }, + {13, RIGHT, PRE_UNARY, "attr", _attr_ }, + + {14, LEFT, PRE_UNARY, ":?", colon_question }, + {14, LEFT, PRE_UNARY, ".?", point_question }, + + {15, RIGHT, PRE_UNARY, "+", pre_plus }, + {15, RIGHT, PRE_UNARY, "-", pre_minus }, + {15, RIGHT, PRE_UNARY, "@", a_circle }, + {15, RIGHT, PRE_UNARY, "$", dollar }, + + { 0, 0, PRE_UNARY, "", pre_null }, + { 0, 0, POST_UNARY, "", post_null } +}; + +static stack stk; +static char *line; +static int depth; +int error; + +void print_error __P1 (int,err_num) +{ + clear_input_line(1); + if (error == NO_MEM_ERROR) { + tty_printf("#system call error: %s (%d", "malloc", ENOMEM); + tty_printf(": %s)\n", strerror(ENOMEM)); + } else + tty_printf("#error: %s.\n", error_msg[err_num]); +} + +static int push_op __P1 (operator *,op) +{ + if (stk.curr_op<MAX_STACK) { + stk.op[++stk.curr_op]=*op; + return 1; + } + else { + error=STACK_OV_ERROR; + return 0; + } +} + +static int pop_op __P1 (operator *,op) +{ + if (stk.curr_op>=0) { + *op=stk.op[stk.curr_op--]; + return 1; + } + else { + error=STACK_UND_ERROR; + return 0; + } +} + +static int push_obj __P1 (object *,obj) +{ + object *tmp; + + int curr=stk.curr_obj; + + if (curr<MAX_STACK) { + tmp = stk.obj + (stk.curr_obj = ++curr); + memmove(tmp, obj, sizeof(object)); + return 1; + } + else { + error=STACK_OV_ERROR; + return 0; + } +} + +static int pop_obj __P1 (object *,obj) +{ + object *tmp; + + int curr=stk.curr_obj; + + if (curr>=0) { + tmp = stk.obj + curr; + stk.curr_obj--; + memmove(obj, tmp, sizeof(object)); + return 1; + } + else { + error=STACK_UND_ERROR; + return 0; + } +} + +static int check_operator __P3 (char,side, operator *,op, int,mindepth) +{ + int i, max, len; + operator match; + char *name, c, d; + + if (!(c=*line) || c == CMDSEP) { + *op = side==BINARY ? null : side==LEFT ? pre_null : post_null; + return 1; + } + else if ((c=='$' || c=='@') && (d=line[1]) && (isalpha(d) || d=='_')) + return 0; /* Danger! found named variable */ + + else if (side==LEFT && c=='(') { + line++; + depth++; + *op=left_paren; + return 1; + } + else if (side==RIGHT && c==')') { + if (--depth >= mindepth) { + line++; + *op=right_paren; + } + else /* exit without touching the parenthesis */ + *op=post_null; + return 1; + } + else if (side==RIGHT && (c=='}' || c==']') && depth == mindepth) { + /* allow also exiting with a '}' or a ']' */ + --depth; + *op=post_null; + return 1; + } + + for (max=match=0, i=(side==BINARY ? 1 : LOWEST_UNARY_CODE); + *(name = op_list[i].name); i++) + if ((len=strlen(name)) > max && + (side==BINARY || side==op_list[i].syntax) && + !strncmp(line, name, (size_t)len)) { + match=op_list[i].code; + max=len; + } + + if (match) { + *op=match; + line+=max; + return 1; + } + else { + *op= side==BINARY ? null : side==PRE_UNARY ? pre_null : post_null; + if (side==BINARY) + error=NO_OPERATOR_ERROR; + } + return 0; +} + +static int check_object __P1 (object *,obj) +{ + long i=0, base = 10; + char c, *end, digit; + + if (c=*line, c == '#' || isdigit(c)) { + while (c == '#' || isalnum(c)) { + digit = !!isdigit(c); + if (c == '#') { + base = i; + i = 0; + if (!base) + base = 16; + } else { + i *= base; + if (digit) + i += (c - '0'); + else { + if (c >= 'a' && c <= 'z') + c = (c - 'a') + 'A'; + if (c - 'A' + 10 >= base) { + error=OUT_BASE_ERROR; + return 0; + } + i += (c - 'A' + 10); + } + } + c=*++line; + } + obj->type=TYPE_NUM; + obj->num=i; + i=1; + } + else if(c=='\"') { + end=first_valid(++line, '\"'); + if (*end) { + obj->type=TYPE_TXT; + obj->txt=ptrmcpy(obj->txt, line, end-line); + if (!REAL_ERROR) { + ptrunescape(obj->txt); + i=1; + line=end+1; + } + } + } + else if ((c=='$' || c=='@') && (c=line[1]) && (isalpha(c) || c=='_')) { + varnode *named_var; /* Found named variable */ + + if (*(line++) == '@') { + i = 0; + obj->type = TYPE_NUM_VAR; + } + else { + i = 1; + obj->type = TYPE_TXT_VAR; + } + end = line + 1; + while ((c=*end) && (isalpha(c) || c=='_' || isdigit(c))) + end++; + c = *end; *end = '\0'; + if (!(named_var = *lookup_varnode(line, i))) { + named_var = add_varnode(line, i); + if (REAL_ERROR) + return 0; + if (echo_int) { + PRINTF("#new variable: %s\n", line - 1); + } + } + *end = c; + line = end; + obj->num = named_var->index; + i = 1; + } + else if (!strncmp(line, "timer", 5)) { + obj->type = TYPE_NUM; + update_now(); + obj->num = diff_vtime(&now, &ref_time); + line += 5; + i = 1; + } + else if (!strncmp(line, "map", 3)) { + char buf[MAX_MAPLEN + 1]; + map_sprintf(buf); + obj->type = TYPE_TXT; + obj->txt = ptrmcpy(obj->txt, buf, strlen(buf)); + if (!REAL_ERROR) { + line += 3; + i = 1; + } + } + else if (!strncmp(line, "noattr", 6)) { + obj->type = TYPE_TXT; + obj->txt = ptrmcpy(obj->txt, tty_modestandoff, strlen(tty_modestandoff)); + obj->txt = ptrmcat(obj->txt, tty_modenorm, strlen(tty_modenorm)); + if (!REAL_ERROR) { + line += 6; + i = 1; + } + } + else + error=NO_VALUE_ERROR; + + return (int)i; +} + +static void check_delete __P1 (object *,obj) +{ + if (obj->type==TYPE_TXT && obj->txt) { + ptrdel(obj->txt); + obj->txt = NULL; + } +} + +static int exe_op __P1 (operator *,op) +{ + object o1, o2, *p=NULL; + long *l, rnd, delta; + ptr src = NULL, dst = NULL, start = NULL; + int srclen; + char *ssrc, *tmp; + int ret=0, i=0, j=0, danger=0; + + o1.txt = o2.txt = NULL; + + switch ((int)*op) { + case (int)comma: + if (pop_obj(&o2) && pop_obj(&o1)); + else if (REAL_ERROR) break; + check_delete(&o1); + p=&o2; + ret=1; + break; + case (int)eq: + if (pop_obj(&o2) && pop_obj(&o1)); + else if (REAL_ERROR) break; + + if (o2.type==TYPE_NUM_VAR) { + o2.num = *VAR[o2.num].num; + o2.type = TYPE_NUM; + } + + if (o1.type==TYPE_NUM_VAR && o2.type==TYPE_NUM) { + *VAR[o1.num].num = o2.num; + p=&o2; + ret=1; + } + else if (o1.type==TYPE_TXT_VAR && + (o2.type==TYPE_TXT || o2.type==TYPE_TXT_VAR)) { + + if (o2.type==TYPE_TXT_VAR) { + o2.txt = ptrdup(*VAR[o2.num].str); + if (REAL_ERROR) break; + o2.type=TYPE_TXT; + } + + *VAR[o1.num].str = ptrcpy(*VAR[o1.num].str, o2.txt); + if (REAL_ERROR) break; + p=&o2; + ret=1; + } + else + error=SYNTAX_ERROR; + break; + case (int)or_or_eq: + case (int)xor_xor_eq: + case (int)and_and_eq: + case (int)or_eq: + case (int)xor_eq: + case (int)and_eq: + case (int)lshift_eq: + case (int)rshift_eq: + case (int)plus_eq: + case (int)minus_eq: + case (int)times_eq: + case (int)div_eq: + case (int)ampersand_eq: + if (pop_obj(&o2) && pop_obj(&o1)); + else if (REAL_ERROR) break; + + if (o2.type==TYPE_NUM_VAR) { + o2.num = *VAR[o2.num].num; + o2.type = TYPE_NUM; + } + + if (o1.type==TYPE_NUM_VAR && o2.type==TYPE_NUM) { + l=VAR[o1.num].num; + + switch ((int)*op) { + case (int)or_or_eq: if ( o2.num) *l = 1; else *l = !!*l; break; + case (int)xor_xor_eq:if ( o2.num) *l = !*l; else *l = !!*l; break; + case (int)and_and_eq:if (!o2.num) *l = 0; else *l = !!*l; break; + case (int)or_eq: *l |= o2.num; break; + case (int)xor_eq: *l ^= o2.num; break; + case (int)and_eq: *l &= o2.num; break; + case (int)lshift_eq: *l <<= o2.num; break; + case (int)rshift_eq: *l >>= o2.num; break; + case (int)plus_eq: *l += o2.num; break; + case (int)minus_eq: *l -= o2.num; break; + case (int)times_eq: *l *= o2.num; break; + case (int)div_eq: *l /= o2.num; break; + case (int)ampersand_eq: + if ((*l %= o2.num) < 0) *l += o2.num; break; + } + o2.num=*l; + p=&o2; + ret=1; + } + else if (*op==plus_eq && o1.type==TYPE_TXT_VAR && + (o2.type==TYPE_TXT || o2.type==TYPE_TXT_VAR)) { + + if (o2.type==TYPE_TXT) + src=o2.txt; + else + src=*VAR[o2.num].str; + + *VAR[o1.num].str = ptrcat(*VAR[o1.num].str, src); + check_delete(&o2); + + dst = ptrdup(*VAR[o1.num].str); + if (REAL_ERROR) break; + + o1.type=TYPE_TXT; + o1.txt=dst; + p=&o1; + ret=1; + } + else if (*op==times_eq && o1.type==TYPE_TXT_VAR && + (o2.type==TYPE_NUM || o2.type==TYPE_NUM_VAR)) { + + if (o2.type==TYPE_NUM_VAR) { + o2.num = *VAR[o2.num].num; + o2.type = TYPE_NUM; + } + + if (o2.num < 0) + error = OUT_RANGE_ERROR; + else if (o2.num == 0) + ptrzero(*VAR[o1.num].str); + else if (o2.num == 1) + ; + else if (*VAR[o1.num].str && (delta = ptrlen(*VAR[o1.num].str))) { + long n; + *VAR[o1.num].str = ptrsetlen(*VAR[o1.num].str, delta*o2.num); + tmp = ptrdata(*VAR[o1.num].str); + for (n = 1; !error && n<o2.num; n++) + memcpy(tmp+n*delta, tmp, delta); + } + + check_delete(&o2); + dst = ptrdup(*VAR[o1.num].str); + if (REAL_ERROR) break; + + o1.type=TYPE_TXT; + o1.txt=dst; + p=&o1; + ret=1; + } + else + error=SYNTAX_ERROR; + break; + case (int)or_or: + case (int)xor_xor: + case (int)and_and: + case (int)or: + case (int)xor: + case (int)and: + case (int)less: + case (int)less_eq: + case (int)greater: + case (int)greater_eq: + case (int)eq_eq: + case (int)not_eq: + case (int)lshift: + case (int)rshift: + case (int)minus: + case (int)plus: + case (int)times: + case (int)division: + case (int)ampersand: + if (pop_obj(&o2) && pop_obj(&o1)); + else if (REAL_ERROR) break; + + if (o1.type==TYPE_NUM_VAR) { + o1.num = *VAR[o1.num].num; + o1.type = TYPE_NUM; + } + if (o2.type==TYPE_NUM_VAR) { + o2.num = *VAR[o2.num].num; + o2.type = TYPE_NUM; + } + + if (o1.type==TYPE_NUM && o2.type==TYPE_NUM) { + if (!o2.num && + (*op==division || *op==ampersand)) { + error=DIV_BY_ZERO_ERROR; + break; + } + + switch ((int)*op) { + case (int)less: o1.num = o1.num < o2.num ? 1 : 0; break; + case (int)less_eq: o1.num = o1.num <= o2.num ? 1 : 0; break; + case (int)greater: o1.num = o1.num > o2.num ? 1 : 0; break; + case (int)greater_eq:o1.num = o1.num >= o2.num ? 1 : 0; break; + case (int)eq_eq: o1.num = o1.num == o2.num ? 1 : 0; break; + case (int)not_eq: o1.num = o1.num != o2.num ? 1 : 0; break; + case (int)or_or: o1.num = o1.num || o2.num; break; + case (int)xor_xor:if (o2.num) o1.num = !o1.num; break; + case (int)and_and: o1.num = o1.num && o2.num; break; + case (int)or: o1.num |= o2.num; break; + case (int)xor: o1.num ^= o2.num; break; + case (int)and: o1.num &= o2.num; break; + case (int)lshift: o1.num <<= o2.num; break; + case (int)rshift: o1.num >>= o2.num; break; + case (int)minus: o1.num -= o2.num; break; + case (int)plus: o1.num += o2.num; break; + case (int)times: o1.num *= o2.num; break; + case (int)division:o1.num /= o2.num; break; + case (int)ampersand: + if ((o1.num %= o2.num) < 0) o1.num += o2.num; break; + } + + p=&o1; + ret=1; + } + else if ((o1.type==TYPE_TXT || o1.type==TYPE_TXT_VAR) && + (o2.type==TYPE_TXT || o2.type==TYPE_TXT_VAR)) { + + if (o1.type==TYPE_TXT_VAR) { + o1.txt = ptrdup(*VAR[o1.num].str); + if (REAL_ERROR) break; + } + dst = o1.txt; + if (o2.type==TYPE_TXT) + src=o2.txt; + else + src=*VAR[o2.num].str; + + if (*op == plus) { + dst = ptrcat(dst, src); + o1.type = TYPE_TXT; + } else { + o1.type = TYPE_NUM; + o1.num = ptrcmp(dst, src); + switch ((int)*op) { + case (int)minus: break; + case (int)less: o1.num = o1.num < 0; break; + case (int)less_eq: o1.num = o1.num <= 0; break; + case (int)greater: o1.num = o1.num > 0; break; + case (int)greater_eq: o1.num = o1.num >= 0; break; + case (int)eq_eq: o1.num = o1.num == 0; break; + case (int)not_eq: o1.num = o1.num != 0; break; + default: + error=SYNTAX_ERROR; + p=NULL; ret=0; break; + } + check_delete(&o1); + } + check_delete(&o2); + if (!REAL_ERROR) { + o1.txt = dst; + p=&o1; + ret=1; + } + } + else if (*op==times + && (o1.type==TYPE_TXT_VAR || o1.type==TYPE_TXT) + && o2.type==TYPE_NUM) { + + if (o2.num > 0 && o1.type==TYPE_TXT_VAR) { + o1.txt = ptrdup(*VAR[o1.num].str); + if (REAL_ERROR) break; + } + dst = o1.txt; + + if (o2.num < 0) + error = OUT_RANGE_ERROR; + else if (o2.num == 0) + ptrzero(dst); + else if (o2.num == 1) + ; + else if (dst && (delta = ptrlen(dst))) { + long n; + dst = ptrsetlen(dst, delta*o2.num); + tmp = ptrdata(dst); + for (n = 1; !error && n<o2.num; n++) + memcpy(tmp+n*delta, tmp, delta); + } + check_delete(&o2); + if (REAL_ERROR) break; + + o1.type=TYPE_TXT; + o1.txt=dst; + p=&o1; + ret=1; + } + else + error=SYNTAX_ERROR; + break; + case (int)colon_less: + case (int)colon_greater: + case (int)less_colon: + case (int)greater_colon: + case (int)colon: + case (int)point_less: + case (int)point_greater: + case (int)less_point: + case (int)greater_point: + case (int)point: + if (pop_obj(&o2) && pop_obj(&o1)); + else if (REAL_ERROR) break; + + if (o2.type==TYPE_NUM_VAR) { + o2.num = *VAR[o2.num].num; + o2.type = TYPE_NUM; + } + + if ((o1.type!=TYPE_TXT_VAR && o1.type!=TYPE_TXT) || o2.type!=TYPE_NUM) { + error=SYNTAX_ERROR; + break; + } + + if (o2.num<=0) { + error=OUT_RANGE_ERROR; + break; + } + + if (o1.type==TYPE_TXT_VAR) { + o1.type=TYPE_TXT; + o1.txt=dst=NULL; + src=start=*VAR[o1.num].str; + } + else { + /* Potentially dangerous: src and dst are overlapping */ + src=dst=start=o1.txt; + danger=1; + } + + if (!src) { + /* src == empty string. just return it */ + check_delete(&o2); + o1.txt = src; + if (!REAL_ERROR) + p=&o1; ret=1; + break; + } + + srclen = ptrlen(src); + ssrc = ptrdata(src); + + switch ((int)*op) { + case (int)colon_less: + while (o2.num && srclen) { + /* skip span of multiple word delimeters */ + while (srclen && memchr(DELIM, *ssrc, DELIM_LEN)) + srclen--, ssrc++, j++; + /* skip whole words */ + if (srclen && (tmp = memchrs(ssrc, srclen, DELIM, DELIM_LEN))) + i=tmp-ssrc, o2.num--, ssrc+=i, j+=i, srclen-=i; + else break; + } + + if (o2.num) { /* end of valid string before the n-th word */ + if (danger) + ; + else + dst = ptrcpy(dst, start); + } else { + if (danger) + ptrtrunc(dst, j); + else + dst = ptrmcpy(dst, ptrdata(start), j); + } + break; + case (int)colon: + case (int)colon_greater: + o2.num--; + /* skip span of multiple word delimeters */ + while (srclen && memchr(DELIM, *ssrc, DELIM_LEN)) + srclen--, ssrc++; + while (o2.num && srclen) { + /* skip whole words */ + if (srclen && (tmp = memchrs(ssrc, srclen, DELIM, DELIM_LEN))) { + i=tmp-ssrc, o2.num--, ssrc+=i, srclen-=i; + /* skip span of multiple word delimeters */ + while (srclen && memchr(DELIM, *ssrc, DELIM_LEN)) + srclen--, ssrc++; + } else break; + } + + if (o2.num) /* end of valid string before the n-th word */ + ptrzero(dst); + else { + if (*op==colon && + (tmp = memchrs(ssrc, srclen, DELIM, DELIM_LEN))) { + dst = ptrmcpy(dst, ssrc, tmp-ssrc); + } + else + dst = ptrmcpy(dst, ssrc, srclen); + } + break; + case (int)less_colon: + o2.num--; + while (o2.num && srclen) { + /* skip span of multiple word delimeters */ + while (srclen && memchr(DELIM, ssrc[srclen], DELIM_LEN)) + srclen--; + /* skip whole words */ + if (srclen && (tmp=memrchrs(ssrc, srclen, DELIM, DELIM_LEN))) + o2.num--, srclen=tmp-ssrc; + else break; + } + + if (o2.num) /* end of valid string before the n-th word */ + ptrzero(dst); + else + dst = ptrmcpy(dst, ssrc, srclen); + break; + case (int)greater_colon: + while (o2.num && srclen) { + /* skip span of multiple word delimeters */ + while (srclen && memchr(DELIM, ssrc[srclen], DELIM_LEN)) + srclen--; + /* skip whole words */ + if (srclen && (tmp=memrchrs(ssrc, srclen, DELIM, DELIM_LEN))) + o2.num--, srclen=tmp-ssrc; + else break; + } + + if (o2.num) /* end of valid string before the n-th word */ + dst = ptrcpy(dst, start); + else + dst = ptrmcpy(dst, ssrc+srclen+1, + ptrlen(start) - (ssrc+srclen+1 - ptrdata(start))); + break; + case (int)point: + dst = ptrmcpy(dst, ssrc+o2.num-1, 1); + break; + case (int)point_less: + j = o2.num < srclen ? o2.num : srclen; + if (danger) + ptrtrunc(dst, j); + else + dst = ptrmcpy(dst, ssrc, j); + break; + case (int)less_point: + j = srclen-o2.num+1; + if (j < 0) + j = 0; + if (danger) + ptrtrunc(dst, j); + else + dst = ptrmcpy(dst, ssrc, j); + break; + case (int)point_greater: + j = o2.num-1 < srclen ? o2.num-1 : srclen; + dst = ptrmcpy(dst, ssrc+j, srclen-j); + break; + case (int)greater_point: + j = srclen-o2.num; + if (j < 0) + j = 0; + dst = ptrmcpy(dst, ssrc+j, srclen-j); + break; + } + check_delete(&o2); + o1.txt = dst; + if (!REAL_ERROR) + p=&o1; ret=1; + break; + case (int)colon_question: + case (int)point_question: + if (pop_obj(&o1)); + else if (REAL_ERROR) break; + + if (o1.type==TYPE_TXT) + src=o1.txt; + else if (o1.type==TYPE_TXT_VAR) + src=*VAR[o1.num].str; + else { + error=SYNTAX_ERROR; + break; + } + if (!src) { + /* empty string. return 0 */ + check_delete(&o1); + o1.type=TYPE_NUM; + o1.num =0; + p=&o1; + ret=1; + break; + } + + ssrc = ptrdata(src); + srclen = ptrlen(src); + + if (*op==colon_question) { + o1.num = 0; + /* skip span of multiple word delimeters */ + while (srclen && memchr(DELIM, *ssrc, DELIM_LEN)) + ssrc++, srclen--; + while (srclen) { + /* skip whole words */ + if (srclen && (tmp=memchrs(ssrc, srclen, DELIM, DELIM_LEN))) { + i=tmp-ssrc, o1.num++, ssrc+=i, srclen-=i; + /* skip span of multiple word delimeters */ + while (srclen && memchr(DELIM, *ssrc, DELIM_LEN)) + srclen--, ssrc++; + } else { + srclen=0; + o1.num++; + } + } + } + else + o1.num=srclen; + + check_delete(&o1); + o1.type=TYPE_NUM; + p=&o1; + ret=1; + break; + case (int)question: + if (pop_obj(&o2) && pop_obj(&o1)); + else if (REAL_ERROR) break; + + if (o1.type==TYPE_TXT) + src = o1.txt; + else if (o1.type==TYPE_TXT_VAR) + src = *VAR[o1.num].str; + else + error = SYNTAX_ERROR; + + if (o2.type==TYPE_TXT) + dst = o2.txt; + else if (o2.type==TYPE_TXT_VAR) + dst = *VAR[o2.num].str; + else + error = SYNTAX_ERROR; + + if (!error) { + if ((ssrc = ptrfind(src, dst))) + i = (int)(ssrc - ptrdata(src)) + 1; + else + i = 0; + o1.type = TYPE_NUM; + o1.num = i; + p=&o1; ret=1; + } + check_delete(&o1); + check_delete(&o2); + break; + case (int)null: + case (int)another_null: + if (pop_obj(&o2) && pop_obj(&o1)); + else if (REAL_ERROR) break; + + check_delete(&o1); + check_delete(&o2); + + o1.type=0, o1.num=0, o1.txt=NULL; + + p=&o1; + ret=1; + break; + case (int)left_paren: + error=MISSING_PAREN_ERROR; + break; + case (int)right_paren: + if (pop_op(op)); + else if (REAL_ERROR) break; + + if (*op!=left_paren) + error=MISMATCH_PAREN_ERROR; + else + ret=1; + + break; + case (int)_random_: +#ifdef NO_RANDOM + error = NOT_SUPPORTED_ERROR; + break; +#endif + case (int)pre_plus: + case (int)pre_minus: + case (int)not: + case (int)tilde: + + if (pop_obj(&o1)); + else if (REAL_ERROR) break; + + if (o1.type==TYPE_NUM_VAR) { + o1.num = *VAR[o1.num].num; + o1.type = TYPE_NUM; + } + if (o1.type==TYPE_NUM) { + if (*op==pre_minus) + o1.num=-o1.num; + else if (*op==not) + o1.num=!o1.num; + else if (*op==tilde) + o1.num=~o1.num; +#ifndef NO_RANDOM + else if (*op==_random_) { + if (o1.num <= 0) { + error=OUT_RANGE_ERROR; + break; + } else { + delta = LONG_MAX - LONG_MAX % o1.num; + while (rnd = get_random(), rnd > delta); + /* skip numbers that would alterate distribution */ + o1.num = rnd / (delta / o1.num); + } + } +#endif + p=&o1; + ret=1; + } + else + error=SYNTAX_ERROR; + break; + case (int)_attr_: + if (pop_obj(&o1)); + else if (REAL_ERROR) break; + + if (o1.type==TYPE_TXT_VAR) { + o1.txt = ptrdup(*VAR[o1.num].str); + if (REAL_ERROR) break; + o1.type = TYPE_TXT; + } + + if (o1.type==TYPE_TXT) { + char dummy[CAPLEN]; /* just because attr_string must write somewhere */ + + if (o1.txt) + i = parse_attributes(ptrdata(o1.txt)); + else + i = NOATTRCODE; + if (i == -1) + error=BAD_ATTR_ERROR; + else { + o1.txt = ptrsetlen(o1.txt, CAPLEN); + if (REAL_ERROR) break; + attr_string(i, ptrdata(o1.txt), dummy); + ptrtrunc(o1.txt, strlen(ptrdata(o1.txt))); + p=&o1; + ret = 1; + } + } else + error=NO_STRING_ERROR; + break; + + case (int)star: + case (int)print: + if (pop_obj(&o1)); + else if (REAL_ERROR) break; + + if (o1.type==TYPE_NUM_VAR) + o1.num = *VAR[o1.num].num; + else if (o1.type==TYPE_TXT_VAR) + o1.txt = *VAR[o1.num].str; + + if (o1.type==TYPE_NUM || o1.type==TYPE_NUM_VAR) { + o1.txt = NULL; + if (*op==print) { + char buf[LONGLEN]; + sprintf(buf, "%ld", o1.num); + o1.txt = ptrmcpy(o1.txt, buf, strlen(buf)); + } else { + char buf = (char)o1.num; + o1.txt = ptrmcpy(o1.txt, &buf, 1); + } + if (REAL_ERROR) break; + o1.type = TYPE_TXT; + p=&o1; ret=1; + } + else if (o1.type==TYPE_TXT || o1.type==TYPE_TXT_VAR) { + if (*op==print) { + if (o1.txt && ptrlen(o1.txt)) + o1.num = atol(ptrdata(o1.txt)); + else + o1.num = 0; + } else { + if (o1.txt && ptrlen(o1.txt)) + o1.num = (long)(byte)*ptrdata(o1.txt); + else + o1.num = 0; + } + check_delete(&o1); + o1.type = TYPE_NUM; + p=&o1; ret=1; + } + else + error=SYNTAX_ERROR; + break; + case (int)pre_plus_plus: + case (int)post_plus_plus: + case (int)pre_minus_minus: + case (int)post_minus_minus: + if (pop_obj(&o1)); + else if (REAL_ERROR) break; + + if (o1.type==TYPE_NUM_VAR) { + l=VAR[o1.num].num; + o1.type=TYPE_NUM; + + if (*op==pre_plus_plus) + o1.num=++*l; + else if (*op==post_plus_plus) + o1.num=(*l)++; + else if (*op==pre_minus_minus) + o1.num=--*l; + else + o1.num=(*l)--; + + p=&o1; + ret=1; + } + else + error=SYNTAX_ERROR; + break; + case (int)a_circle: + case (int)dollar: + if (pop_obj(&o1)); + else if (REAL_ERROR) break; + + if (*op == dollar) + delta = 1; + else + delta = 0; + + if (o1.type==TYPE_NUM_VAR) { + o1.type=TYPE_NUM; + o1.num=*VAR[o1.num].num; + } + + if (o1.type==TYPE_NUM) { + if (o1.num<-NUMVAR || o1.num>=NUMPARAM) { + error=OUT_RANGE_ERROR; + break; + } + o1.type= delta ? TYPE_TXT_VAR : TYPE_NUM_VAR; + p=&o1; + ret=1; + } else { + varnode *named_var; + char c; + + if (o1.type==TYPE_TXT_VAR) + o1.txt = *VAR[o1.num].str; + else if (o1.type!=TYPE_TXT) { + error=SYNTAX_ERROR; + break; + } + + if (o1.txt && (tmp=ptrdata(o1.txt)) && + ((c=*tmp) == '_' || isalpha(c))) { + tmp++; + while ((c=*tmp) == '_' || isalnum(c)) + tmp++; + } + if (!o1.txt || *tmp) { + error=INVALID_NAME_ERROR; + break; + } + + if (!(named_var = *lookup_varnode(ptrdata(o1.txt), delta))) { + named_var = add_varnode(ptrdata(o1.txt), delta); + if (REAL_ERROR) + break; + if (echo_int) { + PRINTF("#new variable: %c%s\n", delta + ? '$' : '@', ptrdata(o1.txt)); + } + } + o1.type= delta ? TYPE_TXT_VAR : TYPE_NUM_VAR; + p=&o1; + ret=1; + } + break; + case (int)pre_null: + case (int)post_null: + ret=1; + break; + default: + break; + } + + if (REAL_ERROR) { + check_delete(&o2); + check_delete(&o1); + } + + if (!REAL_ERROR) { + if (!ret) + error=NOT_DONE_ERROR; + else if (p) { + if (push_obj(p)) + ; + else + check_delete(p); + } + } + + if (REAL_ERROR) + return 0; + + return ret; +} + +static int whichfirst __P2 (operator *,op1, operator *,op2) +{ + int p1, p2; + + p1=op_list[*op1].priority; + p2=op_list[*op2].priority; + if (p1!=p2) + return p1>p2 ? -1 : 1; + + p1 = op_list[*op1].assoc == LEFT; + return p1 ? -1 : 1; +} + +static int compare_and_unload __P1 (operator *,op) +{ + int first=0; + operator new; + + if (REAL_ERROR || stk.curr_op<0) + return 1; + + while (stk.curr_op>=0 && pop_op(&new) && !REAL_ERROR && + (first = whichfirst(&new, op)) == -1 && + (first = 0, exe_op(&new)) + ); + + if (!REAL_ERROR) { + if (!first) + return 1; + else + return push_op(&new); + } else + return 0; +} + +static int _eval __P1 (int,mindepth) +{ + operator op; + object obj; + char endreached = 0; + + for (;;) { + memzero(&obj, sizeof(obj)); + + while (*line==' ') line++; + if (!*line || *line == CMDSEP) + endreached = 1; + + while (check_operator(LEFT, &op, mindepth) && push_op(&op) && + !endreached) { + + if (error) return 0; + while (*line==' ') line++; + if (!*line || *line == CMDSEP) + endreached = 1; + } + + if (!endreached && check_object(&obj) && push_obj(&obj)); + else if (error) return 0; + + while (*line==' ') line++; + if (!*line || *line == CMDSEP) + endreached = 1; + + while (check_operator(RIGHT, &op, mindepth) && compare_and_unload(&op) && + exe_op(&op) && depth>=mindepth && !endreached) { + + if (error) return 0; + while (*line==' ') + line++; + if (!*line || *line == CMDSEP) + endreached = 1; + } + if (error) return 0; + + if (endreached || depth < mindepth) + break; + + if (check_operator(BINARY, &op, mindepth) && + compare_and_unload(&op) && push_op(&op)); + else if (error) return 0; + } + return 1; +} + +int eval_any __P3 (long *,lres, ptr *,pres, char **,what) +{ + int printmode; + long val; + ptr txt; + object res; + + if (pres) + printmode = PRINT_AS_PTR; + else if (lres) + printmode = PRINT_AS_LONG; + else + printmode = PRINT_NOTHING; + + error=0; + stk.curr_obj=stk.curr_op=-1; + line = *what; + + depth = 0; + (void)_eval(0); + + if (!error) + (void)pop_obj(&res); + if (error) { + if (opt_debug) { + PRINTF("#result not available\n"); + } + } else if (printmode!=PRINT_NOTHING || opt_debug) { + if (res.type==TYPE_NUM || res.type==TYPE_NUM_VAR) { + + val = res.type==TYPE_NUM ? res.num : *VAR[res.num].num; + + if (printmode==PRINT_AS_PTR) { + *pres = ptrsetlen(*pres, LONGLEN); + if (!MEM_ERROR) { + sprintf(ptrdata(*pres), "%ld", val); + (*pres)->len = strlen(ptrdata(*pres)); + } + } else if (printmode==PRINT_AS_LONG) + *lres=val; + + if (opt_debug) { + if (error) { + PRINTF("#result not available\n"); + } else { + PRINTF("#result: %ld\n", val); + } + } + } else { + txt = res.type==TYPE_TXT ? res.txt : *VAR[res.num].str; + if (printmode==PRINT_AS_PTR) { + if (txt && *ptrdata(txt)) { + if (res.type == TYPE_TXT) + /* shortcut! */ + *pres = txt; + else + *pres = ptrcpy(*pres, txt); + } else + ptrzero(*pres); + } + if (opt_debug) { + if (error) { + PRINTF("#result not available\n"); + } else if (txt && *ptrdata(txt)) { + PRINTF("#result: %s\n", ptrdata(txt)); + } else { + PRINTF("#result empty\n"); + } + } + } + } + *what=line; + + if (!error) { + if (printmode==PRINT_AS_PTR && res.type == TYPE_TXT + && res.txt && ptrdata(res.txt)) + /* shortcut! */ + ; + else + check_delete(&res); + } else { + while (stk.curr_obj>=0) { + pop_obj(&res); + check_delete(&res); + } + res.type = 0; + } + + if (res.type==TYPE_TXT_VAR) + res.type = TYPE_TXT; + else if (res.type==TYPE_NUM_VAR) + res.type = TYPE_NUM; + + return res.type; +} + +int evalp __P2 (ptr *,res, char **,what) +{ + return eval_any((long *)0, res, what); +} + +int evall __P2 (long *,res, char **,what) +{ + return eval_any(res, (ptr *)0, what); +} + +int evaln __P1 (char **,what) +{ + return eval_any((long *)0, (ptr *)0, what); +} + @@ -0,0 +1,58 @@ +/* public things from eval.c */ + +#ifndef _EVAL_H_ +#define _EVAL_H_ + +#define STACK_OV_ERROR 1 +#define STACK_UND_ERROR 2 +#define DYN_STACK_OV_ERROR 3 +#define DYN_STACK_UND_ERROR 4 +#define SYNTAX_ERROR 5 +#define NO_OPERATOR_ERROR 6 +#define NO_VALUE_ERROR 7 +#define DIV_BY_ZERO_ERROR 8 +#define OUT_RANGE_ERROR 9 +#define MISSING_PAREN_ERROR 10 +#define MISMATCH_PAREN_ERROR 11 +#define INTERNAL_ERROR 12 +#define NOT_SUPPORTED_ERROR 13 +#define NOT_DONE_ERROR 14 +#define NO_MEM_ERROR 15 +#define MEM_LIMIT_ERROR 16 +#define MAX_LOOP_ERROR 17 +#define NO_NUM_VALUE_ERROR 18 +#define NO_STRING_ERROR 19 +#define NO_LABEL_ERROR 20 +#define MISSING_SEPARATOR_ERROR 21 +#define HISTORY_RECURSION_ERROR 22 +#define USER_BREAK 23 +#define OUT_OF_VAR_SPACE_ERROR 24 +#define UNDEFINED_VARIABLE_ERROR 25 +#define OUT_BASE_ERROR 26 +#define BAD_ATTR_ERROR 27 +#define INVALID_NAME_ERROR 28 + +#define TYPE_NUM 1 +#define TYPE_TXT 2 +#define TYPE_NUM_VAR 3 +#define TYPE_TXT_VAR 4 + +#define PRINT_NOTHING 0 +#define PRINT_AS_PTR 1 +#define PRINT_AS_LONG 2 + +int eval_any __P ((long *lres, ptr *pres, char **what)); +int evalp __P (( ptr *pres, char **what)); +int evall __P ((long *lres, char **what)); +int evaln __P (( char **what)); + +void print_error __P ((int err_num)); + +extern char *error_msg[]; +extern int error; + +#define REAL_ERROR (error && error != USER_BREAK) +#define MEM_ERROR (error == NO_MEM_ERROR || error == MEM_LIMIT_ERROR) + +#endif /* _EVAL_H_ */ + diff --git a/follow.c b/follow.c new file mode 100644 index 0000000..fe75558 --- /dev/null +++ b/follow.c @@ -0,0 +1,166 @@ +/* + * follow.c -- interactively print an ASCII file. + * + * This file is placed in the public domain. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> +#include <time.h> +#include <unistd.h> +#include <sys/time.h> +#include <sys/types.h> + +#ifndef USE_SGTTY +# ifdef APOLLO +# include "/sys5.3/usr/include/sys/termio.h" +# else +/* + * including both termio.h and termios.h might be an overkill, and gives + * many warnings, but seems to be necessary at times. works anyway. + */ +# include <termios.h> +# include <termio.h> +# endif +/* #else USE_SGTTY */ +#endif + +/* + * SunOS 4 doesn't have function headers and has the defs needed from + * ioctl.h in termios.h. Does it compile with USE_SGTTY? + */ +#if (defined(sun) && defined(sparc) && ! defined(__SVR4)) +extern int printf(); +#else +# include <sys/ioctl.h> +#endif + +#ifdef BSD_LIKE +# include <sys/ioctl_compat.h> +# define O_RAW RAW +# define O_ECHO ECHO +# define O_CBREAK CBREAK +#endif + +#if defined(TCSETS) || defined(TCSETATTR) +# ifndef TCSETS /* cc for HP-UX SHOULD define this... */ +# define TCSETS TCSETATTR +# define TCGETS TCGETATTR +# endif +typedef struct termios termiostruct; +#else +# define TCSETS TCSETA +# define TCGETS TCGETA +typedef struct termio termiostruct; +#endif + +#ifdef VSUSP +# define O_SUSP VSUSP +#else +# ifdef SWTCH +# define O_SUSP SWTCH +# else +# define O_SUSP SUSP +# endif +#endif + +/*int ioctl();*/ + +#ifdef USE_SGTTY +static struct sgttyb ttybsave; +static struct tchars tcsave; +static struct ltchars ltcsave; +#else /* not USE_SGTTY */ +static termiostruct ttybsave; +#endif /* USE_SGTTY */ + +/* + * Terminal handling routines: + * These are one big mess of left-justified chicken scratches. + * It should be handled more cleanly...but unix portability is what it is. + */ + +/* + * Set the terminal to character-at-a-time-without-echo mode, and save the + * original state in ttybsave + */ +void set_terminal() +{ +#ifdef USE_SGTTY + struct sgttyb ttyb; + struct ltchars ltc; + ioctl(0, TIOCGETP, &ttybsave); + ioctl(0, TIOCGETC, &tcsave); + ioctl(0, TIOCGLTC, <csave); + ttyb = ttybsave; + ttyb.sg_flags = (ttyb.sg_flags|O_CBREAK) & ~O_ECHO; + ioctl(tty_read_fd, TIOCSETP, &ttyb); + ltc = ltcsave; + ltc.t_suspc = -1; + ioctl(0, TIOCSLTC, <c); +#else /* not USE_SGTTY */ + termiostruct ttyb; + ioctl(0, TCGETS, &ttyb); + ttybsave = ttyb; + ttyb.c_lflag &= ~(ECHO|ICANON); + ttyb.c_cc[VTIME] = 0; + ttyb.c_cc[VMIN] = 1; + /* disable the special handling of the suspend key (handle it ourselves) */ + ttyb.c_cc[O_SUSP] = 0; + ioctl(0, TCSETS, &ttyb); +#endif /* USE_SGTTY */ +} + +/* + * Reset the terminal to its original state + */ +void reset_terminal() +{ +#ifdef USE_SGTTY + ioctl(0, TIOCSETP, &ttybsave); + ioctl(0, TIOCSETC, &tcsave); + ioctl(0, TIOCSLTC, <csave); +#else /* not USE_SGTTY */ + ioctl(0, TCSETS, &ttybsave); +#endif /* USE_SGTTY */ +} + +int main(int argc, char *argv[]) { + FILE *f; + char c = 0, buf[512]; + int d; + + if (argc < 2) { + fprintf(stderr, "needed a file name\n"); + exit(0); + } + f = fopen(argv[1], "r"); + if (!f) { + fprintf(stderr, "unable to open %s\n", argv[1]); + exit(0); + } + + set_terminal(); + while(c!=0x1b) { + read(0, &c, 1); + if (c == 0x0a || c == 0x0d) { + if (fgets(buf, 512, f)) + fputs(buf, stdout); + else + break; + } + else { + if ((d = fgetc(f)) != EOF) + putchar(d); + else + break; + } + fflush(stdout); + } + reset_terminal(); + fputs("\033[0m\n", stdout); + return 0; +} + diff --git a/install-sh b/install-sh new file mode 100755 index 0000000..0ec27bc --- /dev/null +++ b/install-sh @@ -0,0 +1,294 @@ +#!/bin/sh +# +# install - install a program, script, or datafile +# +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +transformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd=$cpprog + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd=$stripprog + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "$0: no input file specified" >&2 + exit 1 +else + : +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d "$dst" ]; then + instcmd=: + chmodcmd="" + else + instcmd=$mkdirprog + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f "$src" ] || [ -d "$src" ] + then + : + else + echo "$0: $src does not exist" >&2 + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "$0: no destination specified" >&2 + exit 1 + else + : + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d "$dst" ] + then + dst=$dst/`basename "$src"` + else + : + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo "$dst" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' + ' +IFS="${IFS-$defaultIFS}" + +oIFS=$IFS +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS=$oIFS + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp=$pathcomp$1 + shift + + if [ ! -d "$pathcomp" ] ; + then + $mkdirprog "$pathcomp" + else + : + fi + + pathcomp=$pathcomp/ +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd "$dst" && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dst"; else : ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dst"; else : ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dst"; else : ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dst"; else : ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename "$dst"` + else + dstfile=`basename "$dst" $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename "$dst"` + else + : + fi + +# Make a couple of temp file names in the proper directory. + + dsttmp=$dstdir/#inst.$$# + rmtmp=$dstdir/#rm.$$# + +# Trap to clean up temp files at exit. + + trap 'status=$?; rm -f "$dsttmp" "$rmtmp" && exit $status' 0 + trap '(exit $?); exit' 1 2 13 15 + +# Move or copy the file name to the temp name + + $doit $instcmd "$src" "$dsttmp" && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dsttmp"; else :;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dsttmp"; else :;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dsttmp"; else :;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dsttmp"; else :;fi && + +# Now remove or move aside any old file at destination location. We try this +# two ways since rm can't unlink itself on some systems and the destination +# file might be busy for other reasons. In this case, the final cleanup +# might fail but the new file should still install successfully. + +{ + if [ -f "$dstdir/$dstfile" ] + then + $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null || + $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null || + { + echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2 + (exit 1); exit + } + else + : + fi +} && + +# Now rename the file to the real destination. + + $doit $mvcmd "$dsttmp" "$dstdir/$dstfile" + +fi && + +# The final little trick to "correctly" pass the exit status to the exit trap. + +{ + (exit 0); exit +} @@ -0,0 +1,679 @@ +/* + * list.c -- list utility functions. + * + * Copyright (C) 1998 by Massimiliano Ghilardi + * + * 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. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <time.h> +#include <sys/types.h> +#include <sys/time.h> + +#ifdef USE_REGEXP +# include "malloc.h" +# include <regex.h> +#endif + +#include "defines.h" +#include "main.h" +#include "utils.h" +#include "cmd2.h" +#include "tty.h" +#include "eval.h" + +/* + * compare two times, return -1 if t1 < t2, 1 if t1 > t2, 0 if t1 == t2 + */ +int cmp_vtime __P2 (vtime *,t1, vtime *,t2) +{ + int i; + i = t1->tv_sec < t2->tv_sec ? -1 : t1->tv_sec > t2->tv_sec ? 1 : 0; + if (!i) + i = t1->tv_usec < t2->tv_usec ? -1 : t1->tv_usec > t2->tv_usec ? 1 : 0; + return i; +} + +/* + * add t2 to t1 (i.e. t1 += t2) + */ +void add_vtime __P2 (vtime *,t1, vtime *,t2) +{ + t1->tv_sec += t2->tv_sec; + if ((t1->tv_usec += t2->tv_usec) >= uSEC_PER_SEC) { + t1->tv_sec += t1->tv_usec / uSEC_PER_SEC; + t1->tv_usec %= uSEC_PER_SEC; + } +} + +/* + * Return t1 - t2, in milliseconds + */ +long diff_vtime __P2 (vtime *,t1, vtime *,t2) +{ + return (t1->tv_sec - t2->tv_sec) * mSEC_PER_SEC + + (t1->tv_usec - t2->tv_usec) / uSEC_PER_mSEC; +} + +int rev_sort __P2 (defnode *,node1, defnode *,node2) +{ + return -1; +} + +/* + * standard ASCII comparison between nodes + */ +int ascii_sort __P2 (defnode *,node1, defnode *,node2) +{ + return strcmp(node1->sortfield, node2->sortfield); +} + +int rev_ascii_sort __P2 (defnode *,node1, defnode *,node2) +{ + return strcmp(node2->sortfield, node1->sortfield); +} + + +/* + * comparison between times of execution of nodes + * (return -1 if node1->when < node2->when) + */ +int time_sort __P2 (defnode *,node1, defnode *,node2) +{ + return cmp_vtime(&((delaynode *)node1)->when, &((delaynode *)node2)->when); +} + +/* + * reverse comparison between times of execution of nodes + * (return -1 if node1->when > node2->when) + */ +int rev_time_sort __P2 (defnode *,node1, defnode *,node2) +{ + return cmp_vtime(&((delaynode *)node2)->when, &((delaynode *)node1)->when); +} + +/* + * compute the hash value of a name + */ +int hash __P2 (char *,name, int,optlen) +{ + int h = 0, i = 0; + if (optlen < 0) + optlen = strlen(name); + while (optlen-- > 0) { + h += ((*name++) ^ i) << i; + if (++i == LOG_MAX_HASH) + i = 0; + } + return (h + (h >> LOG_MAX_HASH) + (h >> (2*LOG_MAX_HASH))) & (MAX_HASH-1); +} + +/* + * generic list node adding routine + */ +void add_node __P3 (defnode *,newnode, defnode **,base, function_sort,sort) +{ + while((*base) && (!sort || (*sort)(newnode, *base) > 0)) + base = &(*base)->next; + newnode->next = *base; + *base = newnode; +} + +static void add_sortednode __P3 (sortednode *,newnode, sortednode **,base, function_sort,sort) +{ + while((*base) && (!sort || (*sort)((defnode *)newnode, (defnode *)*base) > 0)) + base = &(*base)->snext; + newnode->snext = *base; + *base = newnode; +} + +void reverse_list __P1 (defnode **,base) +{ + defnode *node = *base, *list = NULL, *tmp; + while (node) { + tmp = node->next; + node->next = list; + list = node; + node = tmp; + } + *base = list; +} + +void reverse_sortedlist __P1 (sortednode **,base) +{ + sortednode *node = *base, *list = NULL, *tmp; + while (node) { + tmp = node->snext; + node->snext = list; + list = node; + node = tmp; + } + *base = list; +} + +static sortednode **selflookup_sortednode __P2 (sortednode *,self, sortednode **,base) +{ + sortednode **p = base; + while (*p && *p != self) + p = &(*p)->snext; + if (!*p) { + PRINTF("#internal error, selflookup_sortednode(`%s') failed!\n", self->sortfield); + error = INTERNAL_ERROR; + } + return p; +} + +/* + * add a node to the alias list + */ +void add_aliasnode __P2 (char *,name, char *,subst) +{ + aliasnode *new = (aliasnode*)malloc(sizeof(aliasnode)); + if (!new) { + errmsg("malloc"); + return; + } + + new->group = NULL; + new->active = 1; + new->name = my_strdup(name); + new->subst = my_strdup(subst); + if ((name && !new->name) || (subst && !new->subst)) { + errmsg("malloc"); + if (new->name) + free(new->name); + if (new->subst) + free(new->subst); + free(new); + return; + } + add_node((defnode*)new, (defnode**)&aliases[hash(name,-1)], rev_sort); + add_sortednode((sortednode*)new, (sortednode**)&sortedaliases, rev_ascii_sort); +} + +/* + * add a node to the marker list + */ +void add_marknode __P4 (char *,pattern, int,attrcode, char,mbeg, char,wild) +{ + marknode **p, *new = (marknode*)malloc(sizeof(marknode)); + int i; + if (!new) { + errmsg("malloc"); + return; + } + new->pattern = my_strdup(pattern); + new->attrcode = attrcode; + new->start = new->end = NULL; + new->mbeg = mbeg; + new->wild = wild; + if (!new->pattern) { + errmsg("malloc"); + free(new); + return; + } +#ifdef DO_SORT + add_node((defnode*)new, (defnode**)&markers, ascii_sort); +#else + for (p=&markers, i=1; *p && (a_nice==0 || i<a_nice); p = &(*p)->next, i++) + ; + new->next = *p; + *p = new; +#endif +} + +/* + * add a node to the action list + */ +void add_actionnode __P6 (char *,pattern, char *,command, char *,label, int,active, int,type, void *,vregexp) +{ + actionnode **p, *new = (actionnode*)malloc(sizeof(actionnode)); + int i; + if (!new) { + errmsg("malloc"); + return; + } + + new->group = NULL; + new->pattern = my_strdup(pattern); + new->command = my_strdup(command); + new->label = my_strdup(label); + new->active = active; + new->type = type; +#ifdef USE_REGEXP + new->regexp = vregexp; +#endif + if (!new->pattern || (command && !new->command) || (label && !new->label)) { + errmsg("malloc"); + if (new->pattern) + free(new->pattern); + if (new->command) + free(new->command); + if (new->label) + free(new->label); + free(new); + return; + } +#ifdef DO_SORT + add_node((defnode*)new, (defnode**)&actions, ascii_sort); +#else + for (p=&actions, i=1; *p && (a_nice==0 || i<a_nice); p = &(*p)->next, i++) + ; + new->next = *p; + *p = new; +#endif +} + +/* + * add a node to the prompt list + */ +void add_promptnode __P6 (char *,pattern, char *,command, char *,label, int,active, int,type, void *,vregexp) +{ + promptnode **p, *new = (promptnode*)malloc(sizeof(promptnode)); + int i; + if (!new) { + errmsg("malloc"); + return; + } + + new->pattern = my_strdup(pattern); + new->command = my_strdup(command); + new->label = my_strdup(label); + new->active = active; + new->type = type; +#ifdef USE_REGEXP + new->regexp = vregexp; +#endif + if (!new->pattern || (command && !new->command) || (label && !new->label)) { + errmsg("malloc"); + if (new->pattern) + free(new->pattern); + if (new->command) + free(new->command); + if (new->label) + free(new->label); + free(new); + return; + } +#ifdef DO_SORT + add_node((defnode*)new, (defnode**)&prompts, ascii_sort); +#else + for (p=&prompts, i=1; *p && (a_nice==0 || i<a_nice); p = &(*p)->next, i++) + ; + new->next = *p; + *p = new; +#endif +} + +/* + * add a node to the keydef list + */ +void add_keynode __P5 (char *,name, char *,sequence, int,seqlen, function_str,funct, char *,call_data) +{ + keynode *new = (keynode*)malloc(sizeof(keynode)); + if (!new) { + errmsg("malloc"); + return; + } + new->name = my_strdup(name); + if (!seqlen) seqlen = strlen(sequence); + new->sequence = (char *)malloc(seqlen + 1); + memmove(new->sequence, sequence, seqlen); + new->seqlen = seqlen; + new->funct = funct; + new->call_data = my_strdup(call_data); + if (!new->name || !new->sequence || (call_data && !new->call_data)) { + errmsg("malloc"); + if (new->name) + free(new->name); + if (new->sequence) + free(new->sequence); + if (new->call_data) + free(new->call_data); + free(new); + return; + } + add_node((defnode*)new, (defnode**)&keydefs, ascii_sort); +} + +/* + * add a node to the delayed command list + * is_dead == 1 means when < now (and so cannot be executed anymore) + */ +delaynode *add_delaynode __P4 (char *,name, char *,command, vtime *,when, int,is_dead) +{ + delaynode *new = (delaynode*)malloc(sizeof(delaynode)); + if (!new) { + errmsg("malloc"); + return NULL; + } + new->name = my_strdup(name); + new->command = my_strdup(command); + if (!new->name || (command && !new->command)) { + errmsg("malloc"); + if (new->name) + free(new->name); + if (new->command) + free(new->command); + free(new); + return NULL; + } + + new->when.tv_sec = when->tv_sec; + new->when.tv_usec = when->tv_usec; + if (is_dead) + add_node((defnode*)new, (defnode**)&dead_delays, rev_time_sort); + else + add_node((defnode*)new, (defnode**)&delays, time_sort); + + return new; +} + +/* + * add a node to named variables list + * + * do NOT allocate a ptr! + */ +varnode *add_varnode __P2 (char *,name, int,type) +{ + varnode *new; + int m, n; + + if (type) + type = 1; + + if (num_named_vars[type] >= max_named_vars) { + /* we are running low on var pointers. try to enlarge */ + m = NUMTOT + max_named_vars; + n = NUMTOT + max_named_vars * 2; + if (n < 0) { + /* overflow */ + print_error(error=OUT_OF_VAR_SPACE_ERROR); + return NULL; + } + else { + vars *newvar; + if ((newvar = (vars *)realloc(var, n*sizeof(vars) ))) + ; + else if ((newvar = (vars *)malloc( n*sizeof(vars) ))) { + memmove(newvar, var, m * sizeof(vars)); + free((void *)var); + } else { + errmsg("malloc"); + return NULL; + } + var = newvar; + max_named_vars += n-m; + memzero(var + m, (n-m)*sizeof(vars)); + } + } + + new = (varnode*)malloc(sizeof(varnode)); + if (!new) { + errmsg("malloc"); + return NULL; + } + new->name = my_strdup(name); + if (name && !new->name) { + errmsg("malloc"); + free(new); + return NULL; + } + new->num = 0; + new->str = (ptr)0; + new->index = m = NUMPARAM + num_named_vars[type]; + + if (type) + VAR[m].str = &new->str; + else + VAR[m].num = &new->num; + num_named_vars[type]++; + + add_node((defnode*)new, (defnode**)&named_vars[type][hash(name,-1)], rev_sort); + add_sortednode((sortednode*)new, (sortednode**)&sortednamed_vars[type], rev_ascii_sort); + return new; +} + +/* + * look up an alias node by name: + * return pointer to pointer to node or a pointer to NULL if nothing found + */ +aliasnode **lookup_alias __P1 (char *,name) +{ + aliasnode **p = &aliases[hash(name,-1)]; + while (*p && strcmp(name, (*p)->name)) + p = &(*p)->next; + return p; +} + +/* + * look up an action node by label: + * return pointer to pointer to node or a pointer to NULL if nothing found + */ +actionnode **lookup_action __P1 (char *,label) +{ + actionnode **p = &actions; + while (*p && strcmp(label, (*p)->label)) + p = &(*p)->next; + return p; +} + +/* + * look up an action node by pattern: + * return pointer to pointer to node or a pointer to NULL if nothing found + */ +actionnode **lookup_action_pattern __P1 (char *,pattern) +{ + actionnode **p = &actions; + while (*p && strcmp(pattern, (*p)->pattern)) + p = &(*p)->next; + return p; +} + +/* + * look up a prompt node by label: + * return pointer to pointer to node or a pointer to NULL if nothing found + */ +actionnode **lookup_prompt __P1 (char *,label) +{ + promptnode **p = &prompts; + while (*p && strcmp(label, (*p)->label)) + p = &(*p)->next; + return p; +} + +/* + * look up an marker node by pattern: + * return pointer to pointer to node or a pointer to NULL if nothing found + */ +marknode **lookup_marker __P2 (char *,pattern, char,mbeg) +{ + marknode **p = &markers; + while (*p && (mbeg != (*p)->mbeg || strcmp(pattern, (*p)->pattern))) + p = &(*p)->next; + return p; +} + +/* + * look up a key node by name: + * return pointer to pointer to node or a pointer to NULL if nothing found + */ +keynode **lookup_key __P1 (char *,name) +{ + keynode **p = &keydefs; + + while (*p && strcmp(name, (*p)->name)) + p = &(*p)->next; + return p; +} + +/* + * look up a delayed command node by label: + * return pointer to pointer to node or a pointer to NULL if nothing found + */ +delaynode **lookup_delay __P2 (char *,name, int,is_dead) +{ + delaynode **p = (is_dead ? &dead_delays : &delays); + while (*p && strcmp(name, (*p)->name)) + p = &(*p)->next; + return p; +} + +/* + * look up a named variable node by name: + * return pointer to pointer to node or a pointer to NULL if nothing found + */ +varnode **lookup_varnode __P2 (char *,name, int,type) +{ + varnode **p = &named_vars[type][hash(name,-1)]; + while (*p && strcmp(name, (*p)->name)) + p = &(*p)->next; + return p; +} + +/* + * delete an alias node, given a pointer to its precessor's pointer + */ +void delete_aliasnode __P1 (aliasnode **,base) +{ + aliasnode *p = *base; + *base = p->next; + if (*(base = (aliasnode**)selflookup_sortednode + ((sortednode*)p, (sortednode**)&sortedaliases))) + *base = p->snext; + else + return; + if (p->name) free(p->name); + if (p->subst) free(p->subst); + free((void*)p); +} + +/* + * delete an action node, given a pointer to its precessor's pointer + */ +void delete_actionnode __P1 (actionnode **,base) +{ + actionnode *p = *base; + if (p->pattern) free(p->pattern); + if (p->command) free(p->command); + if (p->label) free(p->label); +#ifdef USE_REGEXP + if (p->type == ACTION_REGEXP && p->regexp) { + regfree((regex_t *)p->regexp); + free(p->regexp); + } +#endif + *base = p->next; + free((void*)p); +} + +/* + * delete an prompt node, given a pointer to its precessor's pointer + */ +void delete_promptnode __P1 (promptnode **,base) +{ + promptnode *p = *base; + if (p->pattern) free(p->pattern); + if (p->command) free(p->command); + if (p->label) free(p->label); +#ifdef USE_REGEXP + if (p->type == ACTION_REGEXP && p->regexp) { + regfree((regex_t *)p->regexp); + free(p->regexp); + } +#endif + *base = p->next; + free((void*)p); +} + +/* + * delete an marker node, given a pointer to its precessor's pointer + */ +void delete_marknode __P1 (marknode **,base) +{ + marknode *p = *base; + if (p->pattern) free(p->pattern); + *base = p->next; + free((void*)p); +} + +/* + * delete a keydef node, given a pointer to its precessor's pointer + */ +void delete_keynode __P1 (keynode **,base) +{ + keynode *p = *base; + if (p->name) free(p->name); + if (p->sequence) free(p->sequence); + if (p->call_data) free(p->call_data); + *base = p->next; + free((void*)p); +} + +/* + * delete a delayed command node, given a pointer to its precessor's pointer + */ +void delete_delaynode __P1 (delaynode **,base) +{ + delaynode *p = *base; + if (p->name) free(p->name); + if (p->command) free(p->command); + *base = p->next; + free((void*)p); +} + +/* + * delete a named variable node, given a pointer to its precessor's pointer + */ +void delete_varnode __P2 (varnode **,base, int,type) +{ + varnode *p = *base; + int idx = p->index, i, n; + + *base = p->next; + if (*(base = (varnode**)selflookup_sortednode + ((sortednode*)p, (sortednode**)&sortednamed_vars[type]))) + *base = p->snext; + else + return; + if (p->name) free(p->name); + if (type && p->str) ptrdel(p->str); + free((void*)p); + + i = NUMPARAM + --num_named_vars[type]; + + if (idx == i) + return; + + /* now I must fill the hole in var[idx].*** */ + + for (n = 0; n < MAX_HASH; n++) + for (p = named_vars[type][n]; p; p = p->next) + if (p->index == i) { + n = MAX_HASH; + break; + } + + if (!p) { /* should NEVER happen */ + print_error(error=UNDEFINED_VARIABLE_ERROR); + return; + } + + p->index = idx; + + if (type) { + VAR[idx].str = &p->str; + VAR[ i ].str = NULL; + } else { + VAR[idx].num = &p->num; + VAR[ i ].num = NULL; + } +} @@ -0,0 +1,47 @@ +/* public definitions from list.c */ + +#ifndef _LIST_H_ +#define _LIST_H_ + +int cmp_vtime __P ((vtime *t1, vtime *t2)); +void add_vtime __P ((vtime *t1, vtime *t2)); +long diff_vtime __P ((vtime *t1, vtime *t2)); + +int rev_sort __P ((defnode *node1, defnode *node2)); +int ascii_sort __P ((defnode *node1, defnode *node2)); +int rev_ascii_sort __P ((defnode *node1, defnode *node2)); +int time_sort __P ((defnode *node1, defnode *node2)); +int rev_time_sort __P ((defnode *node1, defnode *node2)); + +int hash __P ((char *name)); + +void add_node __P ((defnode *newnode, defnode **base, function_sort sort)); +void reverse_sortedlist __P ((sortednode **base)); + +void add_aliasnode __P ((char *name, char *subst)); +void add_actionnode __P ((char *pattern, char *command, char *label, int active, int type, void *qregexp)); +void add_promptnode __P ((char *pattern, char *command, char *label, int active, int type, void *qregexp)); +void add_marknode __P ((char *pattern, int attrcode, char mbeg, char wild)); +void add_keynode __P ((char *name, char *sequence, int seqlen, function_str funct, char *call_data)); +delaynode *add_delaynode __P ((char *name, char *command, vtime *when, int is_dead)); +varnode *add_varnode __P ((char *name, int type)); + +aliasnode **lookup_alias __P ((char *name)); +actionnode **lookup_action __P ((char *label)); +actionnode **lookup_prompt __P ((char *label)); +actionnode **lookup_action_pattern __P ((char *pattern)); +marknode **lookup_marker __P ((char *pattern, char mbeg)); +keynode **lookup_key __P ((char *name)); +delaynode **lookup_delay __P ((char *name, int is_dead)); +varnode **lookup_varnode __P ((char *name, int type)); + +void delete_aliasnode __P ((aliasnode **base)); +void delete_actionnode __P ((actionnode **base)); +void delete_promptnode __P ((promptnode **base)); +void delete_marknode __P ((marknode **base)); +void delete_keynode __P ((keynode **base)); +void delete_delaynode __P ((delaynode **base)); +void delete_varnode __P ((varnode **base, int type)); + +#endif /* _LIST_H_ */ + @@ -0,0 +1,322 @@ +/* + * log.c -- code for #movie / #capture backbuffering + * and code for reprint-on-prompt + * + * Copyright (C) 1998 by Massimiliano Ghilardi + * + * 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. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <time.h> + +#include "defines.h" +#include "main.h" +#include "log.h" +#include "tty.h" +#include "list.h" +#include "utils.h" + +vtime movie_last; /* time movie_file was last written */ +FILE *capturefile = (FILE *)NULL; /* capture file or NULL */ +FILE *moviefile = (FILE *)NULL; /* movie file or NULL */ +FILE *recordfile = (FILE *)NULL; /* record file or NULL */ + + +static char *datalist; /* circular string list */ +static int datastart = 0; /* index to first string start */ +static int dataend = 0; /* index one past last string end */ +static int datasize = 0; /* size of circular string list */ + +#define DATALEFT (datastart > dataend ? datastart - dataend - 2 : datastart ? \ + MAX2(datastart - 1, datasize - dataend - 1) : datasize - dataend - 1) + +typedef struct logentry { + enum linetype kind; + long msecs; /* millisecs to sleep if kind == SLEEP */ + char *line; /* pointer to string in `datalist' circular buffer */ +} logentry; + +logentry *loglist; /* circular (pointer to string) list */ + +static int logstart = 0; /* index to first loglist used */ +static int logend = 0; /* index one past last loglist used */ +static int logsize = 0; /* size of circular (pointer to string) list */ + +#define LOGFULL (logend == (logstart ? logstart - 1 : logsize - 1)) + +static char *names[] = { NULL, "line", "prompt", "sleep" }; + +/* + * flush a single buffer line + */ +static void log_flushline __P1 (int,i) +{ + if (capturefile) + fprintf(capturefile, "%s%s", + loglist[i].line, loglist[i].kind == LINE ? "\n" : ""); + if (moviefile) { + if (loglist[i].msecs) + fprintf(moviefile, "%s %ld\n", + names[SLEEP], loglist[i].msecs); + fprintf(moviefile, "%s %s\n", + names[loglist[i].kind], loglist[i].line); + } +} + +/* + * remove the oldest (first) line from the buffer + */ +static void log_clearline __P0 (void) +{ + int next; + + if (logstart == logend) + return; + log_flushline(logstart); + + next = (logstart + 1) % logsize; + if (next == logend) + datastart = dataend = logstart = logend = 0; + else + datastart = loglist[next].line - datalist, logstart = next; +} + +/* + * remove an initial SLEEP from the buffer + */ +void log_clearsleep __P0 (void) +{ + if (logstart != logend) + loglist[logstart].msecs = 0; +} + +/* + * flush the buffer + */ +void log_flush __P0 (void) +{ + int i = logstart; + while (i != logend) { + log_flushline(i); + if (++i == logsize) + i = 0; + } + datastart = dataend = logstart = logend = 0; +} + +int log_getsize __P0 (void) +{ + return datasize; +} + +static void log_reset __P0 (void) +{ + if (datasize) { + if (datalist) free(datalist); + if (loglist) free(loglist); + loglist = NULL; + datalist = NULL; + logsize = datasize = 0; + } +} + + +void log_resize __P1 (int,newsize) +{ + if (newsize && newsize < 1000) { + PRINTF("#buffer size must be 0 (zero) or >= 1000\n"); + return; + } + + if (newsize == datasize) + return; + + log_flush(); + log_reset(); + if (newsize) { + datalist = (char *)malloc(newsize); + if (!datalist) { log_reset(); errmsg("malloc"); return; } + + loglist = (logentry *)malloc(newsize/16*sizeof(logentry)); + if (!loglist) { log_reset(); errmsg("malloc"); return; } + + datasize = newsize; + logsize = newsize / 16; + } + if (echo_int) { + PRINTF("#buffer resized to %d bytes%s\n", newsize, newsize ? "" : " (disabled)"); + } +} + +/* + * add a single line to the buffer + */ +static void log_writeline __P4 (char *,line, int,len, int,kind, long,msecs) +{ + int dst; + + if (++len >= datasize) { + PRINTF("#line too long, discarded from movie/capture buffer\n"); + return; + } + while (LOGFULL || DATALEFT < len) + log_clearline(); + /* ok, now we know there IS enough space */ + + if (datastart >= dataend /* is == iff loglist is empty */ + || datasize - dataend > len) + dst = dataend; + else + dst = 0; + + memcpy(loglist[logend].line = datalist + dst, line, len - 1); + datalist[dst + len - 1] = '\0'; + + loglist[logend].kind = kind; + loglist[logend].msecs = msecs; + + if ((dataend = dst + len) == datasize) + dataend = 0; + + if (++logend == logsize) + logend = 0; +} + +/* + * write to #capture / #movie buffer + */ +void log_write __P3 (char *,str, int,len, int,newline) +{ + char *next; + long diff; + int i, last = 0; + + if (!datasize && !moviefile && !capturefile) + return; + + update_now(); + diff = diff_vtime(&now, &movie_last); + movie_last = now; + + do { + if ((next = memchr(str, '\n', len))) + i = next - str; + else + i = len, last = 1; + + if (datasize) + log_writeline(str, i, last && !newline ? PROMPT : LINE, diff); + else { + if (moviefile) { + if (diff) + fprintf(moviefile, "%s %ld\n", + names[SLEEP], diff); + fprintf(moviefile, "%s %.*s\n", + names[last && !newline ? PROMPT : LINE], i, str); + } + if (capturefile) + fprintf(capturefile, "%.*s%s", + i, str, last && !newline ? "" : "\n"); + } + diff = 0; + if (next) { + len -= next + 1 - str; + str = next + 1; + } + } while (next && len > 0); +} + +static char reprintlist[BUFSIZE]; /* circular string list */ +static int reprintstart = 0; /* index to first string start */ +static int reprintend = 0; /* index one past last string end */ +static int reprintsize = BUFSIZE; /* size of circular string list */ + +#define REPRINTLEFT (reprintstart > reprintend ? reprintstart - reprintend - 1 : reprintstart ? \ + MAX2(reprintstart - 1, reprintsize - reprintend - 1) : reprintsize - reprintend - 1) + +static char *replist[BUFSIZE/8]; /* circular (pointer to string) list */ + +static int repstart = 0; /* index to first replist used */ +static int repend = 0; /* index one past last replist used */ +static int repsize = BUFSIZE/8; /* size of circular (pointer to string) list */ + +#define REPFULL (repend == (repstart ? repstart - 1 : repsize - 1)) + +/* + * remove the oldest (first) line from reprintlist + */ +static void reprint_clearline __P0 (void) +{ + int next; + + if (repstart == repend) + return; + + next = (repstart + 1) % repsize; + if (next == repend) + reprintstart = reprintend = repstart = repend = 0; + else + reprintstart = replist[next] - reprintlist, repstart = next; +} + +void reprint_clear __P0 (void) +{ + reprintstart = reprintend = repstart = repend = 0; +} + +/* + * add a single line to the buffer + */ +void reprint_writeline __P1 (char *,line) +{ + int len = strlen(line) + 1; + int dst; + + if (!opt_reprint || (promptlen && prompt_status != -1)) + /* + * if prompt is valid, we'll never have to reprint, as we + * _already_ printed the command at the right moment + */ + return; + + if (len >= reprintsize) { + PRINTF("#line too long, discarded from prompt reprint buffer\n"); + return; + } + while (REPFULL || REPRINTLEFT < len) + reprint_clearline(); + /* ok, now we know there IS enough space */ + + if (reprintstart >= reprintend /* is == iff replist is empty */ + || reprintsize - reprintend > len) + dst = reprintend; + else + dst = 0; + + memcpy(replist[repend] = reprintlist + dst, line, len - 1); + reprintlist[dst + len - 1] = '\0'; + + if ((reprintend = dst + len) == reprintsize) + reprintend = 0; + + if (++repend == repsize) + repend = 0; +} + +char *reprint_getline __P0 (void) +{ + char *line = NULL; + if (opt_reprint && repend != repstart) + line = replist[repstart]; + reprint_clearline(); + return line; +} + @@ -0,0 +1,22 @@ +/* public things from log.c */ + +#ifndef _LOG_H_ +#define _LOG_H_ + +enum linetype { EMPTY = 0, LINE = 1, PROMPT = 2, SLEEP = 3 }; + +extern FILE *capturefile, *recordfile, *moviefile; +extern vtime movie_last; + +void log_clearsleep __P ((void)); +void log_flush __P ((void)); +int log_getsize __P ((void)); +void log_resize __P ((int newsize)); +void log_write __P ((char *str, int len, int newline)); + +void reprint_writeline __P ((char *line)); +char *reprint_getline __P ((void)); +void reprint_clear __P ((void)); + +#endif /* _LOG_H_ */ + @@ -0,0 +1,1995 @@ +/* + * powwow -- mud client with telnet protocol + * + * Copyright (C) 1998,2000,2002 by Massimiliano Ghilardi + * + * 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. + * + * + * History: + * + * Initially inspired to the Tintin client by Peter Unold, + * Powwow contains no Tintin code. + * The original program Cancan, written by Mattias Engdegård (Yorick) + * (f91-men@nada.kth.se) 1992-94, + * was greatly improved upon by Vivriel, Thuzzle and Ilie and then + * transformed from Cancan into Powwow by Cosmos who worked + * to make it yet more powerful. + * AmigaDOS porting attempt by Fror. + * Many new features added by Dain. + * As usual, all the developers are in debt to countless users + * for suggestions and debugging. + */ + +/* + * Set this to whatever you like + * + * #define POWWOW_DIR "/home/gustav/powwow" + */ + +#define POWWOW_VERSION VERSION ", Copyright 2000-2005 by Cosmos\n" \ + "(contributions by Yorick, Vivriel, Thuzzle, Ilie, Fror, Dain)\n" +#define HELPNAME "powwow.help" +#define COPYNAME "COPYING" + +#ifndef POWWOW_DIR +# define POWWOW_DIR "./" +#endif + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <fcntl.h> +#include <ctype.h> +#include <errno.h> +#include <time.h> + +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/wait.h> +#include <memory.h> +#include <unistd.h> + +/* are these really needed? */ +extern int errno; +extern int select(); + +#ifdef USE_REGEXP +# include "malloc.h" +# include <regex.h> +#endif + +#include "defines.h" +#include "main.h" +#include "utils.h" +#include "beam.h" +#include "cmd.h" +#include "cmd2.h" +#include "edit.h" +#include "map.h" +#include "list.h" +#include "tcp.h" +#include "tty.h" +#include "eval.h" +#include "log.h" + +/* local function declarations */ +#ifdef MOTDFILE +static void printmotd __P ((void)); +#endif +static void mainloop __P ((void)); +static void exec_delays __P ((void)); +static void prompt_reset_iac __P ((void)); +static void get_remote_input __P ((void)); +static void get_user_input __P ((void)); + +static int search_action_or_prompt __P ((char *line, char clearline, char copyprompt)); +#define search_action(line, clearline) search_action_or_prompt((line), (clearline), 0) +#define search_prompt(line, copyprompt) search_action_or_prompt((line), 0, (copyprompt)+1) + +static void set_params __P ((char *line, int *match_s, int *match_e)); +static void parse_commands __P ((char *command, char *arg)); +static int subst_param __P ((ptr *buf, char *src)); +static int jit_subst_vars __P ((ptr *buf, char *src)); + + +/* GLOBALS */ +static char *helpname = HELPNAME; +static char *copyname = COPYNAME; + +long received = 0; /* amount of data received from remote host */ +long sent = 0; /* amount of data sent to remote host */ + +char identified = 0; /* 1 after #identify */ +VOLATILE char confirm = 0; /* 1 if just tried to quit */ +int history_done = 0; /* number of recursive #history commands */ +int prompt_status = 0; /* prompt status: 0 = ready -> nothing to do; + * 1 if internal echo -> must redraw; + * -1 if something sent to MUD -> waiting for it. + */ +int line_status = 0; /* input line status: 0 = ready -> nothing to do; + * 1 if printed something -> must redraw. + */ + +int limit_mem = 0; /* if !=0, max len of a string or text */ + +char echo_ext = 1; /* 1 if text sent to MUD must be echoed */ +char echo_key = 1; /* 1 if binds must be echoed */ +char echo_int = 1; /* 0 if internal messages are suppressed */ +char opt_exit = 0; /* 1 to autoquit when closing last conn. */ +char opt_history; /* 1 if to save also history */ +char opt_words = 0; /* 1 if to save also word completion list */ +char opt_compact = 0; /* 1 if to clear prompt between remote messages */ +char opt_debug = 0; /* 1 if to echo every line before executing it */ +char opt_speedwalk = 0; /* 1 = speedwalk on */ +char opt_wrap = 0; /* 1 = word wrap active */ +char opt_autoprint = 0; /* 1 = automatically #print lines matched by actions */ +char opt_reprint = 0; /* 1 = reprint sent commands when we get a prompt */ +char opt_sendsize = 0; /* 1 = send term size upon connect */ +char opt_autoclear = 1; /* 1 = clear input line before executing commands + * from spawned programs. + * if 0, spawned progs must #clear before printing + */ + +char hostname[BUFSIZE]; +int portnumber; +static char powwow_dir[BUFSIZE]; /* default path to definition files */ +char deffile[BUFSIZE]; /* name and path of definition file */ +char helpfile[BUFSIZE]; /* name and path of help file */ +char copyfile[BUFSIZE]; /* name and path of copyright file */ +aliasnode *aliases[MAX_HASH]; /* head of alias hash list */ +aliasnode *sortedaliases; /* head of (ASCII) sorted alias list */ +actionnode *actions; /* head of action list */ +promptnode *prompts; /* head of prompt list */ +marknode *markers; /* head of mark list */ +int a_nice = 0; /* default priority of new actions/marks */ +keynode *keydefs; /* head of key binding list */ +delaynode *delays; /* head of delayed commands list */ +delaynode *dead_delays; /* head of dead-delayed commands list */ + +varnode *named_vars[2][MAX_HASH]; /* head of named variables hash list */ +varnode *sortednamed_vars[2]; /* head of (ASCII) sorted named variables list */ +int max_named_vars = 100; /* max number of named vars (grows as needed) */ +int num_named_vars[2]; /* number of named variables actually used */ + +static param_stack paramstk; /* stack of local unnamed vars */ +static unnamedvar global_var[NUMTOT]; /* global unnamed vars */ + +vars *var; /* vector of all vars */ + +ptr globptr[2]; /* global ptr buffer */ +char globptrok = 1|2; /* x&i = 0 if globptr[i] is in use */ + +varnode *prompt; /* $prompt is always set */ +ptr marked_prompt; /* $prompt with marks added */ +static varnode *last_line; /* $line is always set to + * the last line processed */ + +vtime now; /* current time */ +int now_updated; /* current time is up to date */ +vtime start_time; /* time of powwow timer startup */ +vtime ref_time; /* time corresponding to timer == 0 */ + +function_any last_edit_cmd; /* GH: keep track of for repeated cmds */ + +clock_t start_clock, cpu_clock; + +char initstr[BUFSIZE]; /* initial string to send on connect */ + +int linemode = 0; /* line mode flags (LM_* in main.h) */ + +/* for line editing */ +int cols=80, lines=24; /* screen size */ +int cols_1=79; /* == cols if tty_wrapglitch, == cols-1 otherwise */ +int olines; /* previous screen size */ +int col0; /* input line offset (= printstrlen of prompt) */ +int line0; /* screen line where the input line starts */ +char edbuf[BUFSIZE]; /* line editing buffer */ +int edlen; /* length of current input line */ +int pos = 0; /* cursor position in line */ +char surely_isprompt = 0; /* !=0 if last #prompt set #isprompt */ +char verbatim = 0; /* 1 = don't expand aliases or process semicolons */ +char prefixstr[BUFSIZE]; /* inserted in the editing buffer each time */ +char inserted_next[BUFSIZE];/* inserted in buffer just once */ +char flashback = 0; /* cursor is on excursion and should be put back */ +int excursion; /* where the excursion is */ +char edattrbeg[CAPLEN]; /* starting input line attributes */ +char edattrend[CAPLEN]; /* ending input line attributes */ +int edattrbg; /* input line attributes do change bg color */ + +/* signals handling */ +VOLATILE int sig_pending, sig_winch_got, sig_chld_got; + + +/* GH: different ID characters for different action types */ +/* + * Cosmos: they are hardcoded in cmd2.c, function parse_action() + * so don't change them. + */ +char action_chars[ACTION_TYPES] = { '>', '%' }; + +/* GH: different delimeter modes */ +char *delim_list[] = { " ;", " <>!=(),;\"'{}[]+-/*%", 0 }; +int delim_len [] = { 2 , 21 , 0 }; +char *delim_name[] = { "normal", "program", "custom" }; +int delim_mode = DELIM_NORMAL; + + +int main __P2 (int,argc, char **,argv) +{ + char *p; + int i; + int read_file = 0; /* GH: if true, powwow was started with + * a file argument, and initstr shall be ran */ + + /* initializations */ + initstr[0] = 0; + memzero(conn_list, sizeof(conn_list)); + + update_now(); + ref_time = start_time = movie_last = now; + + start_clock = cpu_clock = clock(); +#ifndef NO_RANDOM + init_random((int)now.tv_sec); +#endif + + _cmd_init(); + + if ((p = getenv("POWWOWDIR"))) { + strcpy(powwow_dir, p); + if (powwow_dir[strlen(powwow_dir) - 1] != '/') + strcat(powwow_dir, "/"); + } else + powwow_dir[0] = '\0'; + + if ((p = getenv("POWWOWHELP"))) + strcpy(helpfile, p); + else if (powwow_dir[0]) + strcpy(helpfile, powwow_dir); + else + strcpy(helpfile, POWWOW_DIR); + + if (helpfile[strlen(helpfile) - 1] != '/') + strcat(helpfile, "/"); + strcat(helpfile, helpname); + if (access(helpfile, R_OK) == -1 && !access(helpname, R_OK)) + strcpy(helpfile, helpname); + + if (powwow_dir[0]) + strcpy(copyfile, powwow_dir); + else + strcpy(copyfile, POWWOW_DIR); + if (helpfile[strlen(helpfile) - 1] != '/') + strcat(copyfile, "/"); + strcat(copyfile, copyname); + if (access(copyfile, R_OK) == -1 && !access(copyname, R_OK)) + strcpy(copyfile, copyname); + + /* initialize variables */ + if ((var = (vars *)malloc(sizeof(vars)*(NUMTOT+max_named_vars)))) { + for (i=0; i<NUMTOT; i++) { + var[i].num = &global_var[i].num; + var[i].str = &global_var[i].str; + } + } else + syserr("malloc"); + + /* stack is empty */ + paramstk.curr = 0; + + /* allocate permanent variables */ + if ((prompt = add_varnode("prompt", 1)) + && (prompt->str = ptrnew(PARAMLEN)) + && (marked_prompt = ptrnew(PARAMLEN)) + && (last_line = add_varnode("last_line", 1)) + && (last_line->str = ptrnew(PARAMLEN)) + && (globptr[0] = ptrnew(PARAMLEN)) + && (globptr[1] = ptrnew(PARAMLEN)) + && !MEM_ERROR) + ; + else + syserr("malloc"); + + + /* + ptr_bootstrap(); + utils_bootstrap(); + beam_bootstrap(); + cmd_bootstrap(); + map_bootstrap(); + eval_bootstrap(); + list_bootstrap(); + tcp_bootstrap(); + */ + edit_bootstrap(); + tty_bootstrap(); + +#ifdef MOTDFILE + printmotd(); +#endif + + printver(); + + if (argc == 1) { + tty_printf( +"\nPowwow comes with ABSOLUTELY NO WARRANTY; for details type `#help warranty'.\n\ +This is free software, and you are welcome to redistribute it\n\ +under certain conditions; type `#help copyright' for details.\n" + ); + } + + if (argc == 1 || argc == 3) { + tty_add_initial_binds(); + tty_add_walk_binds(); + } else if (argc == 2 || argc == 4) { + /* + * assuming first arg is definition file name + * If three args, first is definition file name, + * second and third are hostname and port number + * (they overwrite the ones in definition file) + */ + set_deffile(argv[1]); + + if (access(deffile,R_OK) == -1 || access(deffile,W_OK) == -1) { + char portnum[INTLEN]; + tty_printf("Creating %s\nHost name :", deffile); + tty_flush(); + tty_gets(hostname, BUFSIZE); + if (hostname[0] == '\n') + hostname[0] = '\0'; + else + strtok(hostname, "\n"); + tty_puts("Port number:"); + tty_flush(); + tty_gets(portnum, INTLEN); + portnumber = atoi(portnum); + tty_add_initial_binds(); + tty_add_walk_binds(); + limit_mem = 1048576; + if (save_settings() < 0) + exit(0); + } else if (read_settings() < 0) + exit(0); + else + read_file = 1; + } + if (argc == 3 || argc == 4) { + /* assume last two args are hostname and port number */ + my_strncpy(hostname, argv[argc - 2], BUFSIZE-1); + portnumber = atoi(argv[argc - 1]); + } + + signal_start(); + tty_start(); + + tty_puts(tty_clreoscr); + tty_putc('\n'); + tty_gotoxy(col0 = 0, lines - 2); + tty_puts("Type #help for help.\n"); + line0 = lines - 1; + + FD_ZERO(&fdset); + FD_SET(tty_read_fd, &fdset); + + if (*hostname) + tcp_open("main", (*initstr ? initstr : NULL), hostname, portnumber); + + if (read_file && !*hostname && *initstr) { + parse_instruction(initstr, 0, 0, 1); + history_done = 0; + } + + confirm = 0; + + mainloop(); + + /* NOTREACHED */ + return 0; +} + +/* + * show current version + */ +void printver __P0 (void) +{ + tty_printf("Powwow version %s\n%s (%s, %s)%s\n", POWWOW_VERSION, +#if __STDC__ + "compiled " __TIME__ " " __DATE__, +#else + "", +#endif +#ifdef USE_VT100 + "vt100-only", +#else + "termcaps", +#endif +#ifdef USE_SGTTY + "BSD sgtty", +#else + "termios", +#endif +#ifdef USE_REGEXP + "" +#else + " no regexp" +#endif + ); +} + +#ifdef MOTDFILE +/* + * print the message of the day if present + */ +static void printmotd __P0 (void) +{ + char line[BUFSIZE]; + FILE *f = fopen(MOTDFILE, "r"); + if (f) { + while (fgets(line, BUFSIZE, f)) + tty_puts(line); + fclose(f); + } +} +#endif + +static void redraw_everything __P0 (void) +{ + if (prompt_status == 1 && line_status == 0) + line_status = 1; + if (prompt_status == 1) + draw_prompt(); + else if (prompt_status == -1) { + promptzero(); + col0 = surely_isprompt = '\0'; + } + if (line_status == 1) + draw_input_line(); +} + +/* how much can we sleep in select() ? */ +static void compute_sleeptime __P1 (vtime **,timeout) +{ + static vtime tbuf; + int sleeptime = 0; + + if (delays) { + update_now(); + sleeptime = diff_vtime(&delays->when, &now); + if (!sleeptime) + sleeptime = 1; /* if sleeptime is less than 1 millisec, + * set to 1 millisec */ + } + if (flashback && (!sleeptime || sleeptime > FLASHDELAY)) + sleeptime = FLASHDELAY; + + if (sleeptime) { + tbuf.tv_sec = sleeptime / mSEC_PER_SEC; + tbuf.tv_usec = (sleeptime % mSEC_PER_SEC) * uSEC_PER_mSEC; + *timeout = &tbuf; + } else + *timeout = (vtime *)NULL; +} + +/* + * main loop. + */ +static void mainloop __P0 (void) +{ + fd_set readfds; + int i, err; + vtime *timeout; + + for (;;) { + readfds = fdset; + + tcp_fd = tcp_main_fd; + exec_delays(); + + do { + if (sig_pending) + sig_bottomhalf(); /* this might set errno... */ + + tcp_flush(); + + if (!(pos <= edlen)) { + PRINTF("\n#*ARGH* assertion failed (pos <= edlen): mail max@linuz.sns.it\n"); + pos = edlen; + } + + redraw_everything(); + tty_flush(); + + compute_sleeptime(&timeout); + + error = now_updated = 0; + + err = select(tcp_max_fd+1, &readfds, NULL, NULL, timeout); + + prompt_reset_iac(); + + } while (err < 0 && errno == EINTR); + + if (err < 0 && errno != EINTR) + syserr("select"); + + if (flashback) putbackcursor(); + + /* process subsidiary and spawned connections first */ + if (tcp_count > 1 || tcp_attachcount) { + for (i=0; err && i<conn_max_index; i++) { + if (CONN_INDEX(i).id && CONN_INDEX(i).fd != tcp_main_fd) { + tcp_fd = CONN_INDEX(i).fd; + if (FD_ISSET(tcp_fd, &readfds)) { + err--; + get_remote_input(); + } + } + } + } + /* and main connection last */ + if (tcp_main_fd != -1 && FD_ISSET(tcp_main_fd, &readfds)) { + tcp_fd = tcp_main_fd; + get_remote_input(); + } + if (FD_ISSET(tty_read_fd, &readfds)) { + tcp_fd = tcp_main_fd; + confirm = 0; + get_user_input(); + } + + } +} + +/* + * set the new prompt / input line status + */ +void status __P1 (int,s) +{ + if (s < 0) { + /* waiting prompt from the MUD */ + prompt_status = s; + line_status = 1; + } else { + if (prompt_status >= 0) + prompt_status = s; + if (line_status >= 0) + line_status = s; + } +} + +/* + * execute the delayed labels that have expired + * and place them in the disabled delays list + */ +static void exec_delays __P0 (void) +{ + delaynode *dying; + ptr *pbuf, buf = (ptr)0; + + if (!delays) + return; + + update_now(); + + if (cmp_vtime(&delays->when, &now) > 0) + return; + + /* remember delayed command may modify the prompt and/or input line! */ + if (prompt_status == 0) { + clear_input_line(opt_compact || !echo_int); + if (!opt_compact && echo_int && prompt_status == 0 && promptlen) { + tty_putc('\n'); + col0 = 0; + status(1); + } + } + + TAKE_PTR(pbuf, buf); + + while (delays && cmp_vtime(&delays->when, &now) <= 0) { + dying = delays; /* remove delayed command from active list */ + delays = dying->next; /* and put it in the dead one */ + + add_node((defnode *)dying, (defnode **)&dead_delays, rev_time_sort); + + /* must be moved before executing delay->command + * and command must be copied in a buffer + * (can't you imagine why? The command may edit itself...) + */ + + if (echo_int) + tty_printf("#now [%s]\n", dying->command); + + if (*dying->command) { + + error = 0; + + *pbuf = ptrmcpy(*pbuf, dying->command, strlen(dying->command)); + if (MEM_ERROR) + errmsg("malloc (#in/#at)"); + else { + parse_instruction(ptrdata(*pbuf), 0, 0, 1); + history_done = 0; + } + } + } + DROP_PTR(pbuf); +} + + +#define IAC_N 1024 +static char *iac_v[IAC_N]; +static int iac_f, iac_l; + +static void prompt_reset_iac __P0 (void) +{ + iac_f = iac_l = 0; +} + +void prompt_set_iac __P1 (char *,p) +{ + if (iac_f == iac_l) + iac_f = iac_l = 0; + + if (iac_l < IAC_N) + iac_v[iac_l++] = p; +} + +static char *prompt_get_iac __P0 (void) +{ + return iac_l > iac_f ? iac_v[iac_f] : NULL; +} + +static int grab_prompt __P3 (char *,linestart, int,len, int,islast) +{ + char *p; + int is_iac_prompt = surely_isprompt = 0; + + /* recognize IAC GA as end-of-prompt marker */ + if ((CONN_LIST(tcp_fd).flags & IDPROMPT)) { + if ((p = prompt_get_iac()) && p > linestart && p <= linestart+len) + iac_f++, is_iac_prompt = len = p - linestart; + else if (!islast) + return 0; + } + + /* + * We may get a prompt in the middle of a bunch of lines, so + * match #prompts. They usually have no #print, so we print manually + * if islast is not set and a #prompt matches. + */ + if ((is_iac_prompt || islast || printstrlen(linestart) < cols) && + ((search_prompt(linestart, 1) && surely_isprompt) || is_iac_prompt)) { + + char *reprint; + /* + * the line starts with a prompt. + * #isprompt placed the actual prompt in $prompt, + * we must still process the rest of the line. + */ + if (surely_isprompt > 0 && surely_isprompt <= len) { + len = surely_isprompt; + prompt_status = 1; + } else if (!surely_isprompt && is_iac_prompt) { + prompt->str = ptrmcpy(prompt->str, linestart, len = surely_isprompt = is_iac_prompt); + if (MEM_ERROR) { promptzero(); errmsg("malloc(prompt)"); return 0; } + prompt_status = 1; + } + + /* + * following data may be the reply to a previously sent command, + * so we may have to reprint that command. + */ + if ((reprint = reprint_getline()) && *reprint) { + smart_print(promptstr, 0); + status(-1); + tty_printf("(%s)\n", reprint); + } else if (!islast) + smart_print(promptstr, 1); + } else if (islast) { + prompt->str = ptrmcpy(prompt->str, linestart, len); + if (MEM_ERROR) { promptzero(); errmsg("malloc(prompt)"); return 0; } + prompt_status = 1; /* good, we got what to redraw */ + } else + len = 0; + + return len; +} + + +/* + * process remote input one line at time. stop at "\n". + */ +static void process_singleline __P2 (char **,pbuf, int *,psize) +{ + int size, len = 0; + char *wasn = 0, *buf, *linestart = *pbuf, *lineend, *end = *pbuf + *psize; + + if ((lineend = memchr(linestart, '\n', *psize))) { + /* ok, there is a newline */ + + *(wasn = lineend) = '\0'; + buf = lineend + 1; /* start of next line */ + } + + if (!lineend) + /* line continues till end of buffer, no trailing \n */ + buf = lineend = end; + + size = buf - linestart; + +#ifdef DEBUGCODE_2 + /* debug code to see in detail what codes come from the server */ + { + char c; + char *t; + tty_putc('{'); + for (t = linestart; t < lineend && (c = *t); t++) { + if (c < ' ' || c > '~') + tty_printf("[%d]", (int)c); + else + tty_putc(c); + } + tty_puts("}\n"); + } +#endif + + /* + * Try to guess where is the prompt... really not much more than + * a guess. Again, do it only on main connection: we do not want + * output from other connections to mess with the prompt + * of main connection :) + * + * Since we now have #prompt, behave more restrictively: + * if no #prompts match or a #prompt matches but does not set #isprompt + * (i.e. recognize it for not being a prompt), + * we check for #actions on it when the \n arrives. + * if a #prompt matches and sets #isprompt, then it is REALLY a prompt + * so never match #actions on it. + */ + if (lineend == end && tcp_fd == tcp_main_fd && printstrlen(linestart) < cols) { + /* + * The last line in the chunk we received has no trailing \n + * Assume it is a prompt. + */ + if (surely_isprompt && promptlen && prompt_status == 1) { + draw_prompt(); tty_putc('\n'); col0 = 0; + } + surely_isprompt = 0; + promptzero(); + if (lineend > linestart && (len = grab_prompt(linestart, lineend-linestart, 1))) + size = len; + } else { + if (tcp_fd == tcp_main_fd) { + surely_isprompt = 0; + promptzero(); + + if (linestart[0]) { + /* set $last_line */ + last_line->str = ptrmcpy(last_line->str, linestart, strlen(linestart)); + if (MEM_ERROR) { print_error(error); return; } + + if (lineend > linestart && (len = grab_prompt(linestart, lineend-linestart, 0))) + size = len; + } + } + if (!len && (!*linestart || (!search_action(linestart, 0) || opt_autoprint))) { + if (line0 < lines - 1) + line0++; + if (tcp_fd != tcp_main_fd) /* sub connection */ + tty_printf("##%s> ", CONN_LIST(tcp_fd).id); + + smart_print(linestart, 1); + } + } + + /* + * search_prompt and search_action above + * might set error: clear it to avoid troubles. + */ + error = 0; + if (wasn) *wasn = '\n'; + *pbuf += size; + *psize -= size; +} + +/* + * Code to merge lines from host that were splitted + * into different packets: it is a horrible kludge (sigh) + * and can be used only on one connection at time. + * We currently do it on main connection. + * + * Note that this code also works for _prompts_ splitted into + * different packets, as long as no #prompts execute #isprompt + * on an incomplete prompt (as stated in the docs). + */ +static int process_first_fragment __P2 (char *,buf, int,got) +{ + int processed = 0; + + /* + * Don't merge if the first part of the line was intercepted + * by a #prompt action which executed #isprompt + * (to avoid intercepting it twice) + */ + if (*buf == '\n') { + char deleteprompt = 0, matched = 0; + + if (opt_compact) { + /* in compact mode, skip the first \n */ + deleteprompt = 1; + processed++; + } + + /* + * the prompt was actually a complete line. + * no need to put it on the top of received data. + * unless #isprompt was executed, demote it to a regular line, + * match #actions on it, copy it in last_line. + */ + if (!surely_isprompt) { + last_line->str = ptrcpy(last_line->str, prompt->str); + if (MEM_ERROR) { print_error(error); return 0; } + + /* + * Kludge for kludge: don't delete the old prompt immediately. + * Instead, match actions on it first. + * If it matches, clear the line before running the action + * (done by the `1' in search_action() ) + * If it doesn't match, delete it only if opt_compact != 0 + */ + + matched = search_action(promptstr, 1); + } + if (!matched) + clear_input_line(deleteprompt); + status(-1); + } else { + /* + * try to merge the prompt with the first line in buf + * (assuming we have a line splitted into those parts) + * then clear the prompt. + */ + char *lineend, *spinning = NULL; + + /* find the end of the first line. include the final newline. */ + if ((lineend = strchr(buf, '\n'))) + lineend++; + else + lineend = buf + got; + + if (surely_isprompt || (spinning = memchr(buf, '\b', lineend - buf))) { + /* + * either #isprompt _was_ executed, + * or we got a MUME spinning bar. + * in both cases, don't try to merge. + * + * print a newline (to keep the old prompt on screen) + * only if !opt_compact and we didn't get a MUME spinning bar. + */ + clear_input_line(opt_compact); + if (!spinning && !opt_compact) + tty_putc('\n'), col0 = 0; + promptzero(); + } else { + ptr *pp, p = (ptr)0; + char *dummy; + int dummyint; + + /* ok, merge this junk with the prompt */ + TAKE_PTR(pp, p); + *pp = ptrcpy(*pp, prompt->str); + *pp = ptrmcat(*pp, buf, lineend - buf); + + if (MEM_ERROR) { print_error(error); return 0; } + if (!*pp) + return 0; + dummy = ptrdata(*pp); + dummyint = ptrlen(*pp); + /* this also sets last_line or prompt->str : */ + clear_input_line(1); + process_singleline(&dummy, &dummyint); + + processed = lineend - buf; + } + } + return processed; +} + +/* + * process input from remote host: + * detect special sequences, trigger actions, locate prompt, + * word-wrap, print to tty + */ +void process_remote_input __P2 (char *,buf, int,size) +{ + + if (promptlen && tcp_fd == tcp_main_fd) + promptzero(); /* discard the prompt, we look for another one */ + + status(1); + + do { + process_singleline(&buf, &size); + } while (size > 0); +} + +static void common_clear __P1 (int,newline) +{ + clear_input_line(opt_compact); + if (newline) { + tty_putc('\n'); col0 = 0; status(1); + } +} + +/* + * get data from the socket and process/display it. + */ +static void get_remote_input __P0 (void) +{ + char buffer[BUFSIZE + 2]; /* allow for a terminating \0 later */ + char *buf = buffer, *newline; + int got, otcp_fd, i; + + if (CONN_LIST(tcp_fd).fragment) { + if ((i = strlen(CONN_LIST(tcp_fd).fragment)) >= BUFSIZE-1) { + i = 0; + common_clear(promptlen && !opt_compact); + tty_printf("#error: ##%s : line too long, discarded\n", CONN_LIST(tcp_fd).id); + } else { + buf += i; + memcpy(buffer, CONN_LIST(tcp_fd).fragment, i); + } + free(CONN_LIST(tcp_fd).fragment); + CONN_LIST(tcp_fd).fragment = 0; + } else + i = 0; + + got = tcp_read(tcp_fd, buf, BUFSIZE - i); + if (!got) + return; + + buf[got]='\0'; /* Safe, there is space. Do it now not to forget it later */ + received += got; + +#ifdef DEBUGCODE + /* debug code to see in detail what strange codes come from the server */ + { + char c, *t; + newline = buf + got; + tty_printf("%s{", edattrend); + for (t = buf; t < newline; t++) { + if ((c = *t) < ' ' || c > '~') + tty_printf("[%d]", c); + else tty_putc(c); + } + tty_puts("}\n"); + } +#endif + + if (!(CONN_LIST(tcp_fd).flags & ACTIVE)) + return; /* process only active connections */ + + got += (buf - buffer); + buf = buffer; + + if (CONN_LIST(tcp_fd).flags & SPAWN) { + /* this is data from a spawned child or an attached program. + * execute as if typed */ + otcp_fd = tcp_fd; + tcp_fd = tcp_main_fd; + + if ((newline = strchr(buf, '\n'))) { + /* instead of newline = strtok(buf, "\n") */ + *newline = '\0'; + + if (opt_autoclear && line_status == 0) { + common_clear(!opt_compact); + } + do { + if (echo_int) { + if (line_status == 0) { + common_clear(!opt_compact); + } + tty_printf("##%s [%s]\n", CONN_LIST(otcp_fd).id, buf); + } + parse_user_input(buf, 0); + /* + * strtok() may have been used in parse_user_input()... + * cannot rely it refers on what we may have set above. + * (it causes a bug in #spawned commands if they + * evaluate (attr(), noattr) or they #connect ... ) + * so do it manually. + */ + /* + * buf = strtok(NULL, "\n"); + */ + if ((buf = newline) && + (newline = strchr(++buf, '\n'))) + *newline = '\0'; + } while (buf && newline); + } + + if (buf && *buf && !newline) { + /* + * save last fragment for later, when spawned command will + * (hopefully) send the rest of the text + */ + CONN_LIST(otcp_fd).fragment = my_strdup(buf); + + if (echo_int) { + if (line_status == 0) { + common_clear(!opt_compact); + } + tty_printf("#warning: ##%s : unterminated [%s]\n", CONN_LIST(otcp_fd).id, buf); + } + } + tcp_fd = otcp_fd; + return; + } + + if (linemode & LM_CHAR) { + /* char-by-char mode: just display output, no fuss */ + clear_input_line(0); + tty_puts(buf); + return; + } + + /* line-at-a-time mode: process input in a number of ways */ + + if (tcp_fd == tcp_main_fd && promptlen) { + i = process_first_fragment(buf, got); + buf += i, got -= i; + } else { + common_clear(promptlen && !opt_compact); + } + + if (got > 0) + process_remote_input(buf, got); +} + + +#ifdef USE_REGEXP +/* + * GH: matches precompiled regexp, return actual params in param array + * return 1 if matched, 0 if not + */ +static int match_regexp_action __P4 (void *,regexp, char *,line, int *,match_s, int *,match_e) +{ + regmatch_t reg_match[NUMPARAM - 1]; + + if (!regexec((regex_t *)regexp, line, NUMPARAM - 1, reg_match, 0)) { + int n; + + match_s[0] = 0; + match_e[0] = strlen(line); + for (n = 1; n < NUMPARAM; n++) + match_s[n] = match_e[n] = 0; + for (n = 0; n <= (int)((regex_t *)regexp)->re_nsub && + reg_match[n].rm_so != -1 && n < NUMPARAM - 1; n++) { + match_s[n+1] = reg_match[n].rm_so; + match_e[n+1] = reg_match[n].rm_eo; + } + return 1; + } + return 0; +} +#endif + +/* + * match action containing &1..&9 and $1..$9 and return actual params start/end + * in match_s/match_e - return 1 if matched, 0 if not + */ +static int match_weak_action __P4 (char *,pat, char *,line, int *,match_s, int *,match_e) +{ + char mpat[BUFSIZE], *npat=0, *npat2=0, *src=line, *nsrc=0, c; + ptr *pbuf, buf = (ptr)0; + char *tmp, *realpat = pat; + int mbeg = 0, mword = 0, prm = -1, p; + + TAKE_PTR(pbuf, buf); + + if (jit_subst_vars(pbuf, pat)) + pat = ptrdata(*pbuf); + if (REAL_ERROR) { + print_error(error); + DROP_PTR(pbuf); + return 0; + } + unescape(pat); + + for (p = 0; p < NUMPARAM; p++) + match_s[p] = match_e[p] = 0; + p = 0; + + if (*pat == '^') { + pat++; + mbeg = 1; /* anchor match at line start */ + } + if (*pat == '&' || *pat == '$') + mbeg = - mbeg - 1; /* pattern starts with '&' or '$' */ + + while (pat && *pat) { + if (((c=*pat) == '&' || c == '$')) { + /* &x matches a string */ + /* $x matches a single word */ + tmp = pat + 1; + if (isdigit(*tmp)) { + p = 0; + while (isdigit(*tmp) && p < NUMPARAM) { + p *= 10; + p += *tmp++ - '0'; + } + if (p <= 0 || p >= NUMPARAM) { + DROP_PTR(pbuf); + return 0; + } + prm = p; + pat = tmp; + if (c == '$') + mword = 1; + } else { + PRINTF("#error: bad action pattern `%s\'\n#missing digit after `%s\'\n", + realpat, pat); + DROP_PTR(pbuf); + return 0; + } + } + + npat = first_valid(pat, '&'); + npat2 = first_valid(pat, '$'); + if (npat2 < npat) npat = npat2; + if (!*npat) npat = 0; + + if (npat) { + my_strncpy(mpat, pat, npat-pat); + /* mpat[npat - pat] = 0; */ + } else + strcpy(mpat, pat); + + if (*mpat) { + nsrc = strstr(src, mpat); + if (!nsrc) { + DROP_PTR(pbuf); + return 0; + } + if (mbeg > 0) { + if (nsrc != src) { + DROP_PTR(pbuf); + return 0; + } + mbeg = 0; /* reset mbeg to stop further start match */ + } + if (prm != -1) { + match_s[prm] = src - line; + match_e[prm] = nsrc - line; + } + } else if (prm != -1) { + /* end of pattern space */ + match_s[prm] = src - line; + match_e[prm] = strlen(line); + } + + /* post-processing of param */ + if (prm != -1 && match_e[prm] && mword) { + if (mbeg == -1) { + /* unanchored '$' start, take last word */ + if ((tmp = memrchrs(line + match_s[prm], + match_e[prm] - match_s[prm], + DELIM, DELIM_LEN))) { + match_s[prm] = tmp - line + 1; + } + } else if (!*pat) { + /* '$' at end of pattern, take first word */ + if ((tmp = memchrs(line + match_s[prm], + match_e[prm] - match_s[prm], + DELIM, DELIM_LEN))) + match_e[prm] = tmp - line; + } else { + /* match only if param is single-worded */ + if (memchrs(line + match_s[prm], + match_e[prm] - match_s[prm], + DELIM, DELIM_LEN)) { + DROP_PTR(pbuf); + return 0; + } + } + } + if (prm != -1 && match_e[prm]) + mbeg = mword = 0; /* reset match flags */ + src = nsrc + strlen(mpat); + pat = npat; + } + DROP_PTR(pbuf); + + match_s[0] = 0; match_e[0] = strlen(line); + return 1; +} + +/* + * Search for #actions or #prompts to trigger on an input line. + * The line can't be trashed since we want to print it on the screen later. + * Return 1 if line matched to some #action, 0 otherwise + * + * Optionally clear the input line before running the trigger command. + */ +static int search_action_or_prompt __P3 (char *,line, char,clearline, char,onprompt) +{ + /* + * we need actionnode and promptnode to be the same `triggernode' type + */ + triggernode *p; + int ret = 0; + int match_s[NUMPARAM], match_e[NUMPARAM]; + + for (p = onprompt ? prompts : actions; p; p = p->next) { +#ifdef USE_REGEXP + if (p->active && + ((p->type == ACTION_WEAK && match_weak_action(p->pattern, line, match_s, match_e)) + || (p->type == ACTION_REGEXP && match_regexp_action(p->regexp, line, match_s, match_e)) + )) +#else + if (p->active && + ((p->type == ACTION_WEAK && match_weak_action(p->pattern, line, match_s, match_e)) + )) +#endif + { + push_params(); if (error) return 0; + ret = 1; error = 0; + set_params(line, match_s, match_e); if (error) return 0; + if (onprompt == 2) { + prompt->str = ptrmcpy(prompt->str, line, strlen(line)); + if (MEM_ERROR) { promptzero(); errmsg("malloc(prompt)"); return 0; } + } + if (clearline) + clear_input_line(1); + parse_instruction(p->command, 0, 1, 1); + history_done = 0; + if (error!=DYN_STACK_UND_ERROR && error!=DYN_STACK_OV_ERROR) + pop_params(); + break; + } + } + if (error) return 0; + return ret; +} + +/* + * read terminal input and send to parser. + * decode keys that send escape sequences + */ +static void get_user_input __P0 (void) +{ + int i, j, chunk = 1; + static char buf[BUFSIZE+1]; /* allow for terminating \0 */ + char *c = buf; + static char typed[CAPLEN]; /* chars typed so far (with partial match) */ + static int nchars = 0; /* number of them */ + + /* We have 4 possible line modes: + * line mode, local echo: line editing functions in effect + * line mode, no echo: sometimes used for passwords, no line editing + * char mode, no echo: send a character directly, no local processing + * char mode, local echo: extremely rare, do as above. + */ + if (!(linemode & (LM_NOECHO | LM_CHAR))) /* line mode, local echo */ + chunk = BUFSIZE; + + while ((j = tty_read(tty_read_fd, c, chunk)) < 0 && errno == EINTR) + ; + if (j <= 0 || (chunk == 1 && j != chunk)) + syserr("read from tty"); + + c[chunk] = '\0'; + + if (linemode & LM_CHAR) { + /* char mode. chunk == 1 */ + while ((i = write(tcp_fd, c, 1)) < 0 && errno == EINTR) + ; + if (i != 1) + syserr("write to socket"); + if (!(linemode & LM_NOECHO)) + tty_putc(*c); + last_edit_cmd = (function_any)0; + } else if (linemode & LM_NOECHO) { + /* sending password (line mode, no echo). chunk == 1 */ + if ((*c != '\n' && *c != '\r') && edlen < BUFSIZE - 2) + edbuf[edlen++] = *c; + else { + edbuf[edlen] = '\0'; +#ifdef BUG_ANSI + if (edattrbg) + tty_printf("%s\n", edattrend); + else +#endif + tty_putc('\n'); + + tcp_write(tcp_fd, edbuf); + edlen = 0; + typed[nchars = 0] = 0; + } + edbuf[pos = edlen] = '\0'; + last_edit_cmd = (function_any)0; + } else { + /* normal mode (line mode, echo). chunk == BUFSIZE */ + int done = 0; + keynode *p; + + for (; j > 0; c++, j--) { + + /* search function key strings for match */ + /* GH: support for \0 in sequence */ + done = 0; + typed[nchars++] = *c; + + while (!done) { + done = 1; + /* + * shortcut: + * an initial single ASCII char cannot match any #bind + */ + if (nchars == 1 && *c >= ' ' && *c <= '~') + p = NULL; + else { + for (p = keydefs; (p && (p->seqlen < nchars || + memcmp(typed, p->sequence, nchars))); + p = p->next) + ; + } + + if (!p) { + /* + * GH: type the first character and keep processing + * the rest in the input buffer + */ + i = 1; + last_edit_cmd = (function_any)0; + insert_char(typed[0]); + while (i < nchars) { + typed[i - 1] = typed[i]; + i++; + } + if (--nchars) + done = 0; + } else if (p->seqlen == nchars) { + if (flashback) + putbackcursor(); + p->funct(p->call_data); + last_edit_cmd = (function_any)p->funct; /* GH: keep track of last command */ + nchars = 0; + } + } + } + } +} + +/* + * split str into words separated by DELIM, and place in + * VAR[1].str ... VAR[9].str - + * the whole str is put in VAR[0].str + */ +static char *split_words __P1 (char *,str) +{ + int i; + char *end; + ptr *prm; + + *VAR[0].str = ptrmcpy(*VAR[0].str, str, strlen(str)); + for (i = 1; i < NUMPARAM; i++) { + *VAR[i].num = 0; + prm = VAR[i].str; + /* skip multiple span of DELIM */ + while (*str && strchr(DELIM, *str)) + str++; + end = str; + while (*end && !strchr(DELIM, *end)) + end++; + *prm = ptrmcpy(*prm, str, end-str); + str = end; + if (MEM_ERROR) { print_error(error); return NULL; } + } + return str; +} + +/* + * free the whole stack and reset it to empty + */ +static void free_allparams __P0 (void) +{ + int i,j; + + paramstk.curr = 0; /* reset stack to empty */ + + for (i=1; i<MAX_STACK; i++) { + for (j=0; j<NUMPARAM; j++) { + ptrdel(paramstk.p[i][j].str); + paramstk.p[i][j].str = (ptr)0; + } + } + for (j=0; j<NUMPARAM; j++) { + VAR[j].num = ¶mstk.p[0][j].num; + VAR[j].str = ¶mstk.p[0][j].str; + } +} + +void push_params __P0 (void) +{ + int i; + + if (paramstk.curr < MAX_STACK - 1) + paramstk.curr++; + else { + print_error(error=DYN_STACK_OV_ERROR); + free_allparams(); + return; + } + for (i=0; i<NUMPARAM; i++) { + *(VAR[i].num = ¶mstk.p[paramstk.curr][i].num) = 0; + ptrzero(*(VAR[i].str = ¶mstk.p[paramstk.curr][i].str)); + } +} + +void pop_params __P0 (void) +{ + int i; + + if (paramstk.curr > 0) + paramstk.curr--; + else { + print_error(error=DYN_STACK_UND_ERROR); + free_allparams(); + return; + } + for (i=0; i<NUMPARAM; i++) { + ptrdel(*VAR[i].str); *VAR[i].str = (ptr)0; + VAR[i].num = ¶mstk.p[paramstk.curr][i].num; + VAR[i].str = ¶mstk.p[paramstk.curr][i].str; + } +} + +static void set_params __P3 (char *,line, int *,match_s, int *,match_e) +{ + int i; + + for (i=0; i<NUMPARAM; i++) { + *VAR[i].num = 0; + if (match_e[i] > match_s[i]) { + *VAR[i].str = ptrmcpy(*VAR[i].str, line + match_s[i], + match_e[i] - match_s[i]); + if (MEM_ERROR) { + print_error(error); + return; + } + } else + ptrzero(*VAR[i].str); + } +} + +char *get_next_instr __P1 (char *,p) +{ + int count, is_if; + char *sep, *q; + + p = skipspace(p); + + if (!*p) + return p; + + count = is_if = !strncmp(p, "#if", 3); + + do { + sep = first_regular(p, CMDSEP); + + q = p; + if (*q) do { + if (*q == '#') q++; + + q = first_regular(q, '#'); + } while (*q && strncmp(q, "#if", 3)); + + if (sep<=q) { + if (*(p = sep)) + p++; + } + else + if (*q) + p = get_next_instr(q); + else { + print_error(error=SYNTAX_ERROR); + return NULL; + } + sep = skipspace(p); + } while (*p && count-- && + (!is_if || (!strncmp(sep, "#else", 5) && + (*(p = sep + 5))))); + + return p; +} + +static void send_line __P2 (char *,line, char,silent) +{ + if (!silent && echo_ext) { PRINTF("[%s]\n", line); } + tcp_write(tcp_fd, line); +} + + +/* + * Parse and exec the first instruction in 'line', and return pointer to the + * second instruction in 'line' (if any). + */ +char *parse_instruction __P4 (char *,line, char,silent, char,subs, char,jit_subs) +{ + aliasnode *np; + char *buf, *arg, *end, *ret; + char last_is_sep = 0; + int len, copied = 0, otcp_fd = -1; + ptr p1 = (ptr)0, p2 = (ptr)0; + ptr *pbuf, *pbusy, *tmp; + + if (error) return NULL; + + ret = get_next_instr(line); + + if (!ret || ret==line) /* error or empty instruction, bail out */ + return ret; + + /* + * remove the optional ';' after an instruction, + * to have an usable string, ending with \0. + * If it is escaped, DON'T remove it: it is not a separator, + * and the instruction must already end with \0, or we would not be here. + */ + if (ret[-1] == CMDSEP) { + /* instruction is not empty, ret[-1] is allowed */ + if (ret > line + 1 && ret[-2] == ESC) { + /* ';' is escaped */ + } else { + *--ret = '\0'; + last_is_sep = 1; + } + } + + /* + * using two buffers, p1 and p2, for four strings: + * result of subs_param, result of jit_subst_vars, result of + * unescape and first word of line. + * + * So care is required to avoid clashes. + */ + TAKE_PTR(pbuf, p1); + TAKE_PTR(pbusy, p2); + + if (subs && subst_param(pbuf, line)) { + line = *pbuf ? ptrdata(*pbuf) : ""; + SWAP2(pbusy, pbuf, tmp); + copied = 1; + } + if (jit_subs && jit_subst_vars(pbuf, line)) { + line = *pbuf ? ptrdata(*pbuf) : ""; + SWAP2(pbusy, pbuf, tmp); + copied = 1; + } + if (!copied) { + *pbuf = ptrmcpy(*pbuf, line, strlen(line)); + line = *pbuf ? ptrdata(*pbuf) : ""; + SWAP2(pbusy, pbuf, tmp); + } + if (subs || jit_subs) + unescape(line); + + /* now line is in (pbusy) and (pbuf) is available */ + + /* restore integrity of original line: must still put it in history */ + if (last_is_sep) + *ret++ = CMDSEP; + + if (REAL_ERROR) { + print_error(error); + DROP_PTR(pbuf); DROP_PTR(pbusy); + return NULL; + } + /* run-time debugging */ + if (opt_debug) { + PRINTF("#parsing: %s\n", line); + } + + if (!*line) + send_line(line, silent); + else do { + arg = skipspace(line); + + if (arg[0] == '#' && arg[1] == '#') { /* send to other connection */ + *pbuf = ptrsetlen(*pbuf, len = strlen(arg)); + if (REAL_ERROR) { print_error(error); break; } + buf = ptrdata(*pbuf); + line = split_first_word(buf, len+1, arg + 2); + /* now (pbuf) is used too: first word of line */ + /* line contains the rest */ + otcp_fd = tcp_fd; + if ((tcp_fd = tcp_find(buf))<0) { + error = OUT_RANGE_ERROR; + PRINTF("#no connection named `%s'\n", buf); + break; + } + arg = skipspace(line); + if (!*arg) { + if (CONN_LIST(tcp_fd).flags & SPAWN) { + error = OUT_RANGE_ERROR; + PRINTF("#only MUD connections can be default ones!\n"); + } else { + /* set it as main connection */ + tcp_set_main(tcp_fd); + otcp_fd = -1; + } + /* stop parsing, otherwise a newline would be sent to tcp_fd */ + break; + } + /* now we can trash (pbuf) */ + } + + if (*arg == '{') { /* instruction contains a block */ + end = first_regular(line = arg + 1, '}'); + + if (*end) { + *end = '\0'; + parse_user_input(line, silent); + *end = '}'; + } else + print_error(error=MISSING_PAREN_ERROR); + } else { + int oneword; + /* initial spaces are NOT skipped this time */ + + *pbuf = ptrsetlen(*pbuf, len = strlen(line)); + if (REAL_ERROR) { print_error(error); break; } + + buf = ptrdata(*pbuf); + arg = split_first_word(buf, len+1, line); + /* buf contains the first word, arg points to arguments */ + + /* now pbuf is used too */ + if (!*arg) oneword = 1; + else oneword = 0; + + if ((np = *lookup_alias(buf))&&np->active) { + push_params(); + if (REAL_ERROR) break; + + split_words(arg); /* split argument into words + and place them in $0 ... $9 */ + parse_instruction(np->subst, 0, 1, 1); + + if (error!=DYN_STACK_UND_ERROR && error!=DYN_STACK_OV_ERROR) + pop_params(); + + /* now check for internal commands */ + /* placed here to allow also aliases starting with `#' */ + } else if (*(end = skipspace(line)) == '#') { + + if (*(end = skipspace(end + 1)) == '(') { /* execute #() */ + end++; + (void)evaln(&end); + if (REAL_ERROR) print_error(error); + } else + parse_commands(buf + 1, arg); + /* ok, buf contains skipspace(first word) */ + } else if (!oneword || !map_walk(buf, silent, 0)) { + /* it is ok, map_walk accepts only one word */ + + if (!subs && !jit_subs) + unescape(line); + send_line(line, silent); + } + } + } while (0); + + if (otcp_fd != -1) + tcp_fd = otcp_fd; + DROP_PTR(pbuf); DROP_PTR(pbusy); + return !REAL_ERROR ? ret : NULL; +} + +/* + * parse input from user: calls parse_instruction for each instruction + * in cmd_line. + * silent = 1 if the line should not be echoed, 0 otherwise. + */ +void parse_user_input __P2 (char *,line, char,silent) +{ + do { + line = parse_instruction(line, silent, 0, 0); + } while (!error && line && *line); +} + +/* + * parse powwow's own commands + */ +static void parse_commands __P2 (char *,command, char *,arg) +{ + int i, j; + cmdstruct *c; + + /* We ALLOW special commands also on subsidiary connections ! */ + + /* assume output will be enough to make input line = last screen line */ + /* line0 = lines - 1; */ + if (isdigit(*command) && (i = atoi(command))) { + if (i >= 0) { + while (i--) + (void)parse_instruction(arg, 1, 0, 1); + } else { + PRINTF("#bogus repeat count\n"); + } + } else { + j = strlen(command); + + if( j == 0 ) { + /* comment */ + return; + } + + for( c = commands; c != NULL; c = c -> next ) + if (!strncmp(command, c -> name, j)) { + if (c -> funct) { + (*(c -> funct))(arg); + return; + } + } + + PRINTF("#unknown powwow command `%s'\n", command); + } +} + +/* + * substitute $0..$9 and @0..@9 in a string + * (unless $ or @ is escaped with backslash) + * + * return 0 if dst not filled. if returned 0 and not error, + * there was nothing to substitute. + */ +static int subst_param __P2 (ptr *,buf, char *,src) +{ + int done, i; + char *dst, *tmp, kind; + + if (!strchr(src, '$') && !strchr(src, '@')) + return 0; + + i = strlen(src); + if (!*buf || ptrlen(*buf) < i) { + *buf = ptrsetlen(*buf, i); + if (REAL_ERROR) + return 0; + } + dst = ptrdata(*buf); + + while (*src) { + while (*src && *src != '$' && *src != '@' && *src != ESC) + *dst++ = *src++; + + if (*src == ESC) { + while (*src == ESC) + *dst++ = *src++; + + if (*src) + *dst++ = *src++; + } + + done = 0; + if (*src == '$' || *src == '@') { + kind = *src == '$' ? 1 : 0; + tmp = src + 1; + if (isdigit(*tmp)) { + i = atoi(tmp); + while (isdigit(*tmp)) + tmp++; + + if (i < NUMPARAM) { + int max = 0, n; + char *data = NULL, buf2[LONGLEN]; + + done = 1; + src = tmp; + + /* now the actual substitution */ + if (kind) { + if (*VAR[i].str && (data = ptrdata(*VAR[i].str))) + max = ptrlen(*VAR[i].str); + } else { + sprintf(data = buf2, "%ld", *VAR[i].num); + max = strlen(buf2); + } + if (data && max) { + n = dst - ptrdata(*buf); + *buf = ptrpad(*buf, max); + if (REAL_ERROR) + return 0; + dst = ptrdata(*buf) + n; + memcpy(dst, data, max); + dst += max; + } + } + } + } + if (!done && (*src == '$' || *src == '@')) + *dst++ = *src++; + } + *dst = '\0'; + return 1; +} + +/* + * just-in-time substitution: + * substitute ${name}, @{name} and #{expression} in a string + * (unless `${', `@{' or `#{' are escaped with backslash) + * + * return 0 if dst not filled. if returned 0 and not error, + * there was nothing to substitute. + */ + +static int jit_subst_vars __P2 (ptr *,buf, char *,src) +{ + int i, done, kind; + char *tmp, *name, *dst, c; + varnode *named_var; + + if (!strstr(src, "${") && !strstr(src, "@{") && !strstr(src, "#{")) + return 0; + + i = strlen(src); + if (!*buf || ptrlen(*buf) < i) { + *buf = ptrsetlen(*buf, i); + if (REAL_ERROR) + return 0; + } + dst = ptrdata(*buf); + + while (*src) { + while (*src && *src != '$' && *src != '@' && *src != '#' && *src != ESC) + *dst++ = *src++; + + if (*src == ESC) { + while (*src == ESC) + *dst++ = *src++; + + if (*src) + *dst++ = *src++; + } + + done = 0; + if (*src == '$' || *src == '@') { + i = 0; + kind = *src == '$' ? 1 : 0; + tmp = src + 1; + if (*tmp == '{') { + tmp = skipspace(tmp+1); + if (isdigit(*tmp) || *tmp == '-') { + /* numbered variable */ + i = atoi(tmp); + if (i >= -NUMVAR && i < NUMPARAM) { + if (*tmp == '-') + tmp++; + while (isdigit(*tmp)) + tmp++; + done = 1; + } + } else if (isalpha(*tmp) || *tmp == '_') { + /* named variable */ + name = tmp++; + while (isalnum(*tmp) || *tmp == '_') + tmp++; + c = *tmp; + *tmp = '\0'; + named_var = *lookup_varnode(name, kind); + *tmp = c; + if (named_var) { + i = named_var->index; + done = 1; + } + } + tmp = skipspace(tmp); + if (done) { + int max = 0, n; + char *data = NULL, buf2[LONGLEN]; + + src = tmp + 1; /* skip the '}' */ + + /* now the actual substitution */ + if (kind == 1) { + if (*VAR[i].str && (data = ptrdata(*VAR[i].str))) + max = ptrlen(*VAR[i].str); + } else { + sprintf(data = buf2, "%ld", *VAR[i].num); + max = strlen(buf2); + } + if (data && max) { + n = dst - ptrdata(*buf); + *buf = ptrpad(*buf, max); + if (REAL_ERROR) + return 0; + dst = ptrdata(*buf) + n; + memcpy(dst, data, max); + dst += max; + } + } else if (*tmp == '}') + /* met an undefined variable, consider empty */ + src = tmp + 1; + + /* else syntax error, do nothing */ + } + } else if (src[0] == '#' && src[1] == '{') { + int max, n; + ptr pbuf = (ptr)0; + + src += 2; + (void)evalp(&pbuf, &src); + if (REAL_ERROR) { + ptrdel(pbuf); + return 0; + } + if (pbuf) { + max = ptrlen(pbuf); + n = dst - ptrdata(*buf); + *buf = ptrpad(*buf, max); + if (REAL_ERROR) { + ptrdel(pbuf); + return 0; + } + dst = ptrdata(*buf) + n; + memcpy(dst, ptrdata(pbuf), max); + dst += max; + } + ptrdel(pbuf); + + if (*src) + src = skipspace(src); + if (*src != '}') { + PRINTF("#{}: "); + print_error(error=MISSING_PAREN_ERROR); + return 0; + } + done = 1; + if (*src) + src++; + } + + if (!done && (*src == '$' || *src == '@' || *src == '#')) + /* not matched, just copy */ + *dst++ = *src++; + } + *dst = '\0'; + ptrtrunc(*buf, dst - ptrdata(*buf)); + return 1; +} + +/* + * set definition file: + * rules: if powwow_dir is set it is searched first. + * if file doesn't exist, it is created there. + * If a slash appears in the name, the powwow_dir isn't used. + */ +void set_deffile __P1 (char *,arg) +{ + if (!strchr(arg, '/') && *powwow_dir) { + strcpy(deffile, powwow_dir); + strcat(deffile, arg); + if ((access(deffile, R_OK) == -1 || access(deffile, W_OK) == -1) + && !access(arg,R_OK) && !access(arg, W_OK)) + strcpy(deffile, arg); + } else + strcpy(deffile, arg); +} + +/* + * GH: return true if var is one of the permanent variables + */ +int is_permanent_variable __P1 (varnode *,v) +{ + return (v == prompt || v == last_line); +} @@ -0,0 +1,117 @@ +/* + * main.h + * various constants etc + */ + +#ifndef _MAIN_H_ +#define _MAIN_H_ + +/* shared functions from main.c */ +void printver __P ((void)); +void status __P ((int s)); +void process_remote_input __P ((char *buf, int size)); +void push_params __P ((void)); +void pop_params __P ((void)); +void prompt_set_iac __P ((char *p)); +char *parse_instruction __P ((char *line, char silent, char subs, char jit_subs)); +char *get_next_instr __P ((char *p)); +void parse_user_input __P ((char *line, char silent)); +void set_deffile __P ((char *arg)); +int is_permanent_variable __P ((varnode *v)); + + +/* shared vars from main.c */ +extern char identified; +extern int prompt_status, line_status; +extern int limit_mem; +extern char ready; +extern VOLATILE char confirm; +extern int history_done; +extern int linemode; +extern char hostname[]; +extern int portnumber; +extern char deffile[], helpfile[], copyfile[]; + +extern int cols, lines, cols_1; /* terminal window size */ +extern int olines; /* previous terminal window size */ +extern int line0, col0; /* origin of input line */ + +extern varnode *prompt; /* $prompt is always set */ +extern ptr marked_prompt; /* $prompt with marks added */ + +#define promptstr (ptrdata(prompt->str)) +#define promptlen (ptrlen(prompt->str)) +#define promptzero() (prompt_status = 0, ptrzero(prompt->str)) + +extern char surely_isprompt; /* 1 if #prompt set #isprompt */ +extern char edbuf[]; /* input line buffer */ +extern int edlen; /* characters in edbuf */ +extern int pos; /* cursor position in edbuf */ +extern char edattrbeg[], edattrend[]; +extern int edattrbg; + +extern VOLATILE int sig_pending, sig_winch_got, sig_chld_got; + +extern long received, sent; + +#ifndef NO_CLOCK +#include <time.h> +extern clock_t start_clock, cpu_clock; +#endif + +extern aliasnode *aliases[MAX_HASH]; +extern aliasnode *sortedaliases; +extern actionnode *actions; +extern promptnode *prompts; +extern marknode *markers; +extern int a_nice; +extern keynode *keydefs; +extern delaynode *delays; +extern delaynode *dead_delays; +extern varnode *named_vars[2][MAX_HASH]; +extern varnode *sortednamed_vars[2]; +extern int num_named_vars[2]; +extern int max_named_vars; +extern vars *var; +#define VAR (var+NUMVAR) + +extern ptr globptr[]; +extern char globptrok; +#define TAKE_PTR(pbuf, buf) do { if (globptrok & 1) globptrok &= ~1, pbuf = globptr; else if (globptrok & 2) globptrok &= ~2, pbuf = globptr + 1; else pbuf = &buf; } while(0) +#define DROP_PTR(pbuf) do { if (*pbuf == *globptr) globptrok |= 1; else if (*pbuf == *(globptr+1)) globptrok |= 2; else ptrdel(*pbuf); } while(0) + +extern vtime now, start_time, ref_time; +extern int now_updated; + +extern char initstr[]; +extern char prefixstr[]; +extern char inserted_next[]; +extern char flashback; +extern int excursion; +extern char verbatim; + +extern char opt_exit; +extern char opt_history; +extern char opt_words; +extern char opt_compact; +extern char opt_debug; +extern char opt_wrap; +extern char echo_ext; +extern char echo_int; +extern char echo_key; +extern char opt_speedwalk; +extern char opt_autoprint; +extern char opt_reprint; +extern char opt_sendsize; +extern char opt_autoclear; + +extern function_str last_edit_cmd; + +extern char *delim_list[]; +extern int delim_len[]; +extern char *delim_name[]; +extern int delim_mode; + +extern char action_chars[]; + +#endif /* _MAIN_H_ */ @@ -0,0 +1,193 @@ +/* + * map.c -- mapping routines. + * + * Copyright (C) 1998 by Massimiliano Ghilardi + * + * 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. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <ctype.h> +#include <time.h> +#include <sys/types.h> +#include <sys/time.h> + +#include "defines.h" +#include "main.h" +#include "tty.h" +#include "edit.h" +#include "tcp.h" + +/* + * mapping variables + */ +static char mappath[MAX_MAPLEN]; /* circular path list */ +static int mapstart = 0; /* index to first map entry */ +static int mapend = 0; /* index one past last map entry */ + +#define MAPINDEX(i) (((i) + MAX_MAPLEN) % MAX_MAPLEN) +#define MAPENTRY(i) mappath[MAPINDEX(i)] + +/* + * return reverse direction + */ +static char reverse_dir __P1 (char,dir) +{ + static char dirs[] = "nsewud"; + char *p = strchr(dirs, dir); + return p ? dirs[(p - dirs) ^ 1] : 0; +} + +/* + * retrace steps on map, optionally walk them back + */ +void map_retrace __P2 (int,steps, int,walk_back) +{ + char cmd[2]; + + cmd[1] = '\0'; + + if (!steps && !walk_back) + mapend = mapstart; + else { + if (!steps) + steps = -1; + if (walk_back && echo_ext) { + status(1); + tty_putc('['); + } + + while (mapstart != mapend && steps--) { + mapend = MAPINDEX(mapend - 1); + if (walk_back) { + cmd[0] = reverse_dir(mappath[mapend]); + if (echo_ext) + tty_putc(cmd[0]); + tcp_write(tcp_fd, cmd); + } + } + if (walk_back && echo_ext) + tty_puts("]\n"); + } +} + +/* + * show automatic map (latest steps) in the form s2ews14n + */ +void map_show __P0 (void) +{ + char lastdir; + int count = 0; + int i; + + if (mapstart == mapend) { + PRINTF("#map empty\n"); + } else { + PRINTF("#map: "); + + lastdir = mappath[mapstart]; + for (i = mapstart; i != mapend; i = MAPINDEX(i + 1)) { + if (mappath[i] != lastdir) { + if (count > 1) + tty_printf("%d", count); + tty_putc(lastdir); + + count = 1; + lastdir = mappath[i]; + } else + count++; + } + + if (count > 1) + tty_printf("%d", count); + + tty_printf("%c\n", lastdir); + } +} + +/* + * print map to string in the form seewsnnnnn + */ +void map_sprintf __P1 (char *,buf) +{ + int i; + + if (mapstart != mapend) + for (i = mapstart; i != mapend; i = MAPINDEX(i + 1)) + *buf++ = mappath[i]; + *buf = '\0'; +} + +/* + * add direction to automap + */ +void map_add_dir __P1 (char,dir) +{ +#ifdef NOMAZEMAPPING + if (mapend != mapstart && dir == reverse_dir(MAPENTRY(mapend - 1))) { + mapend = MAPINDEX(mapend - 1); /* retrace one step */ + } else +#endif + { + MAPENTRY(mapend) = dir; + mapend = MAPINDEX(mapend + 1); + if(mapend == mapstart) + mapstart = MAPINDEX(mapstart + 1); + } +} + +/* + * execute walk if word is valid [speed]walk sequence - + * return 1 if walked, 0 if not + */ +int map_walk __P3 (char *,word, int,silent, int,maponly) +{ + char buf[16]; + int n = strlen(word); + int is_main = (tcp_fd == tcp_main_fd); + + if (!is_main && !maponly && !opt_speedwalk) + return 0; + if (!n || (n > 1 && !opt_speedwalk && !maponly) || + !strchr("neswud", word[n - 1]) || + (int)strspn(word, "neswud0123456789") != n) + return 0; + + if (maponly) + silent = 1; + buf[1] = '\0'; + while (*word) { + if (!silent) { status(1); tty_putc('['); } + + if (isdigit(*word)) { + n = strtol(word, &word, 10); + if (!silent) + tty_printf("%d", n); + } else + n = 1; + if (!silent) + tty_putc(*word); + while (n--) { + *buf = *word; + if (!maponly) { + tcp_write(tcp_fd, buf); + } + if (is_main || maponly) + map_add_dir(*word); + } + if (!silent) + tty_puts("] "); + word++; + } + if (!silent) + tty_putc('\n'); + return !maponly; +} + @@ -0,0 +1,15 @@ +/* public things from map.c */ + +#ifndef _MAP_H_ +#define _MAP_H_ + +void map_bootstrap __P ((void)); + +void map_retrace __P ((int steps, int walk_back)); +void map_show __P ((void)); +void map_sprintf __P ((char *buf)); +void map_add_dir __P ((char dir)); +int map_walk __P ((char *word, int silent, int maponly)); + +#endif /* _MAP_H_ */ + @@ -0,0 +1,336 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. +# Copyright (C) 1996, 1997, 1999, 2000, 2002 Free Software Foundation, Inc. +# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +run=: + +# In the cases where this matters, `missing' is being run in the +# srcdir already. +if test -f configure.ac; then + configure_ac=configure.ac +else + configure_ac=configure.in +fi + +case "$1" in +--run) + # Try to run requested program, and just exit if it succeeds. + run= + shift + "$@" && exit 0 + ;; +esac + +# If it does not exist, or fails to run (possibly an outdated version), +# try to emulate it. +case "$1" in + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + --run try to run the given command, and emulate it if it fails + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + automake touch all \`Makefile.in' files + bison create \`y.tab.[ch]', if possible, from existing .[ch] + flex create \`lex.yy.c', if possible, from existing .c + help2man touch the output file + lex create \`lex.yy.c', if possible, from existing .c + makeinfo touch the output file + tar try tar, gnutar, gtar, then tar without non-portable flags + yacc create \`y.tab.[ch]', if possible, from existing .[ch]" + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing 0.4 - GNU automake" + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + + aclocal*) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`acinclude.m4' or \`${configure_ac}'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`${configure_ac}'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`acconfig.h' or \`${configure_ac}'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` + test -z "$files" && files="config.h" + touch_files= + for f in $files; do + case "$f" in + *:*) touch_files="$touch_files "`echo "$f" | + sed -e 's/^[^:]*://' -e 's/:.*//'`;; + *) touch_files="$touch_files $f.in";; + esac + done + touch $touch_files + ;; + + automake*) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print | + sed 's/\.am$/.in/' | + while read f; do touch "$f"; done + ;; + + autom4te) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is needed, and you do not seem to have it handy on your + system. You might have modified some files without having the + proper tools for further handling them. + You can get \`$1Help2man' as part of \`Autoconf' from any GNU + archive site." + + file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'` + test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo "#! /bin/sh" + echo "# Created by GNU Automake missing as a replacement of" + echo "# $ $@" + echo "exit 0" + chmod +x $file + exit 1 + fi + ;; + + bison|yacc) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + rm -f y.tab.c y.tab.h + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if [ ! -f y.tab.h ]; then + echo >y.tab.h + fi + if [ ! -f y.tab.c ]; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex|flex) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.l' file. You may need the \`Flex' package + in order for those modifications to take effect. You can get + \`Flex' from any GNU archive site." + rm -f lex.yy.c + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if [ ! -f lex.yy.c ]; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + help2man) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a dependency of a manual page. You may need the + \`Help2man' package in order for those modifications to take + effect. You can get \`Help2man' from any GNU archive site." + + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'` + fi + if [ -f "$file" ]; then + touch $file + else + test -z "$file" || exec >$file + echo ".ab help2man is required to generate this page" + exit 1 + fi + ;; + + makeinfo) + if test -z "$run" && (makeinfo --version) > /dev/null 2>&1; then + # We have makeinfo, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file` + fi + touch $file + ;; + + tar) + shift + if test -n "$run"; then + echo 1>&2 "ERROR: \`tar' requires --run" + exit 1 + fi + + # We have already tried tar in the generic part. + # Look for gnutar/gtar before invocation to avoid ugly error + # messages. + if (gnutar --version > /dev/null 2>&1); then + gnutar "$@" && exit 0 + fi + if (gtar --version > /dev/null 2>&1); then + gtar "$@" && exit 0 + fi + firstarg="$1" + if shift; then + case "$firstarg" in + *o*) + firstarg=`echo "$firstarg" | sed s/o//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + case "$firstarg" in + *h*) + firstarg=`echo "$firstarg" | sed s/h//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + fi + + echo 1>&2 "\ +WARNING: I can't seem to be able to run \`tar' with the given arguments. + You may want to install GNU tar or Free paxutils, or check the + command line arguments." + exit 1 + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and you do not seem to have it handy on your + system. You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequirements for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 diff --git a/mkinstalldirs b/mkinstalldirs new file mode 100755 index 0000000..d2d5f21 --- /dev/null +++ b/mkinstalldirs @@ -0,0 +1,111 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy +# Author: Noah Friedman <friedman@prep.ai.mit.edu> +# Created: 1993-05-16 +# Public domain + +errstatus=0 +dirmode="" + +usage="\ +Usage: mkinstalldirs [-h] [--help] [-m mode] dir ..." + +# process command line arguments +while test $# -gt 0 ; do + case $1 in + -h | --help | --h*) # -h for help + echo "$usage" 1>&2 + exit 0 + ;; + -m) # -m PERM arg + shift + test $# -eq 0 && { echo "$usage" 1>&2; exit 1; } + dirmode=$1 + shift + ;; + --) # stop option processing + shift + break + ;; + -*) # unknown option + echo "$usage" 1>&2 + exit 1 + ;; + *) # first non-opt arg + break + ;; + esac +done + +for file +do + if test -d "$file"; then + shift + else + break + fi +done + +case $# in + 0) exit 0 ;; +esac + +case $dirmode in + '') + if mkdir -p -- . 2>/dev/null; then + echo "mkdir -p -- $*" + exec mkdir -p -- "$@" + fi + ;; + *) + if mkdir -m "$dirmode" -p -- . 2>/dev/null; then + echo "mkdir -m $dirmode -p -- $*" + exec mkdir -m "$dirmode" -p -- "$@" + fi + ;; +esac + +for file +do + set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` + shift + + pathcomp= + for d + do + pathcomp="$pathcomp$d" + case $pathcomp in + -*) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" + + mkdir "$pathcomp" || lasterr=$? + + if test ! -d "$pathcomp"; then + errstatus=$lasterr + else + if test ! -z "$dirmode"; then + echo "chmod $dirmode $pathcomp" + lasterr="" + chmod "$dirmode" "$pathcomp" || lasterr=$? + + if test ! -z "$lasterr"; then + errstatus=$lasterr + fi + fi + fi + fi + + pathcomp="$pathcomp/" + done +done + +exit $errstatus + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# End: +# mkinstalldirs ends here @@ -0,0 +1,93 @@ +/* + * movie.c -- replay powwow movies or convert them into ASCII + * + * This file is placed in the public domain. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/time.h> +#include <sys/types.h> +#include <unistd.h> + +void millisec_sleep(msec) +long msec; +{ + struct timeval t; + t.tv_sec = msec / 1000; + t.tv_usec = (msec % 1000) * 1000; + select(0, NULL, NULL, NULL, &t); +} + +int main(argc, argv) +int argc; char *argv[]; +{ + FILE *infile, *outfile; + char buf[4096]; + int i, play = 0; + + if (strstr(argv[0], "movie_play")) + play = 1; + else if (!strstr(argv[0], "movie2ascii")) { + fprintf(stderr, "Please run this program as `movie_play' or `movie2ascii'\n"); + return 1; + } + + if (play) { + if (argc == 2) { + infile = fopen(argv[1], "rb"); + outfile = stdout; + if (infile == NULL) { + fprintf(stderr, "Error opening input file `%s'\n", argv[1]); + return 1; + } + } else { + infile = stdin; + outfile = stdout; + } + } else { + if (argc == 3) { + infile = fopen(argv[1], "rb"); + outfile = fopen(argv[2], "wb"); + if (infile == NULL) { + fprintf(stderr, "Error opening input file `%s'\n", argv[1]); + return 1; + } + if (outfile == NULL) { + fprintf(stderr, "Error opening output file `%s'\n", argv[2]); + return 1; + } + } else { + fprintf(stderr, "Usage: %s [infile [outfile]]\n", argv[0]); + return 1; + } + } + + while (fgets(buf, 4096, infile) != NULL) { + i = strlen(buf); + if (i > 0 && buf[i-1] == '\n') + buf[i-1] = '\0'; + if (!strncmp(buf, "sleep ", 6)) { + if (play) + millisec_sleep(atoi(buf + 6)); + } + else if (!strncmp(buf, "line ", 5)) + fprintf(outfile, "%s\n", buf + 5); + else if (!strncmp(buf, "prompt ", 7)) + fprintf(outfile, "%s", buf + 7); + else { + fprintf(stderr, "Syntax error in line:\n%s\n", buf); + return 1; + } + fflush(outfile); + } + if (feof(infile)) { + fprintf(outfile, "\n"); + return 0; + } else { + fprintf(stderr, "Error reading file\n"); + return 1; + } +} + @@ -0,0 +1,298 @@ +#include <curses.h> +#include <stdio.h> + +/* Curses based powwow movie player. + * Author: Steve Slaven - http://hoopajoo.net + */ + +#define JUMP_SMALL 1000 +#define JUMP_BIG 5000 +#define MAX_SPEED 20 + +/* Speed is a variable from 0 - 9, where 5 = normal and > 5 is faster */ +int main( int argc, char *argv[] ) { + WINDOW *text, *status; + int speed = 5; + int key, sleep, orig, i, color, looping, cursx, cursy; + FILE *in; + char line[ 1000 ], *displine, action[ 100 ]; + long curr_pos, file_size, new_pos; + + if( argc < 2 ) { + fprintf( stderr, + "mud cinema v%s\n" + "Author: Steve Slaven - http://hoopajoo.net\n" + "\n" + "Usage: muc file\n" + "\n" + "file should be a #movie file generated in powwow\n", + VERSION ); + exit( 1 ); + } + + /* Validate our file passed */ + if( ! ( in = fopen( argv[ 1 ], "ro" ) ) ) { + perror( "Unable to open file" ); + exit( 1 ); + } + + /* Get file size */ + fseek( in, 0, SEEK_END ); + file_size = ftell( in ); + rewind( in ); + + /* Setup some basic stuff */ + initscr(); + cbreak(); + noecho(); + + /* Initialize color */ + start_color(); + + /* this *should* init the default ansi colors... :/ */ + for( i = 0; i < 16; i++ ) + init_pair( i, i, COLOR_BLACK ); + + /* Create our windows, a status bar on the bottom and a + scrollable window on top */ + text = newwin( LINES - 2, COLS, 0, 0 ); + status = newwin( 2, COLS, LINES - 2, 0 ); + + keypad( stdscr, TRUE ); + scrollok( text, TRUE ); + leaveok( text, TRUE ); + leaveok( status, TRUE ); + /* wattron( status, A_BOLD ); */ + wbkgd( status, A_REVERSE ); + + /* instructions */ + mvwprintw( status, 0, 0, + "(q)uit (r)ew small (R)ew large (f)orw small (F)orw large (0-9)(+)(-) speed" ); + + /* Main loop */ + refresh(); + timeout( 0 ); + looping = 1; + while( looping ) { + bzero( line, 1000 ); + fgets( line, 1000, in ); + + /* get file pos */ + new_pos = curr_pos = ftell( in ); + + /* handle disp or other */ + displine = NULL; + if( strncmp( line, "line", 4 ) == 0 ) { + displine = &line[ 5 ]; + sleep = 0; + }else if( strncmp( line, "prompt", 5 ) == 0 ) { + displine = &line[ 7 ]; + /* Munch newline */ + line[ strlen( line ) - 1 ] = 0; + sleep = 0; + }else if( strncmp( line, "sleep", 5 ) == 0 ) { + sscanf( line, "sleep %d", &sleep ); + }else if( line[ 0 ] == '#' ) { /* custom extension for commenting logs */ + sscanf( line, "#%d", &sleep ); + if( sleep > 0 ) + sleep *= 100; /* comment sleep is in seconds */ + + /* Skip to space */ + displine = line; + while( displine[ 0 ] != ' ' && displine[ 0 ] != 0 ) { + displine++; + } + displine++; + + /* We will go ahead and display it here, in bold, then + null out displine so it will not display later */ + wattron( text, A_REVERSE ); + wprintw( text, "##==> %s", displine ); + wattroff( text, A_REVERSE ); + displine = NULL; + } + + /* suck out action for display */ + sscanf( line, "%100s", action ); + + /* Modify sleep time according to speed, zero is fast as you can go, 1 == pause */ + orig = sleep; + if( speed > 5 ) { + sleep /= ( ( speed - 5 ) * 2 ); + }else{ + sleep *= ( 6 - speed ); + } + + /* Handle pause */ + if( speed == 0 ) + sleep = -1; + + /* handle insane speed */ + /* if( speed == 9 ) + sleep = 0; */ + + /* Setup sleeptime for getch() */ + timeout( sleep ); + + /* Update status line */ + mvwprintw( status, 1, 0, + "%7d/%7d/%2d%% Speed: %d (5=normal,0=pause) Cmd: %-6s (%d/%d)\n", + curr_pos, file_size, curr_pos * 100 / file_size, + speed, action, sleep, orig ); + wrefresh( status ); + + /* Disp if we found an offset to do */ + if( displine != NULL ) { + /* handle converting ansi colors to curses attrs */ + for( i = 0; i < strlen( displine ); i++ ) { + if( displine[ i ] == 0x1b ) { + /* this is super crappy ansi color decoding */ + i++; + if( strncmp( &displine[ i ], "[3", 2 ) == 0 ) { + /* start a color */ + sscanf( &displine[ i ], "[3%dm", &color ); + wattron( text, COLOR_PAIR( color ) ); + }else if( strncmp( &displine[ i ], "[9", 2 ) == 0 ) { + /* start a high color */ + sscanf( &displine[ i ], "[9%dm", &color ); + wattron( text, COLOR_PAIR( color ) ); + wattron( text, A_BOLD ); + }else if( strncmp( &displine[ i ], "[1", 2 ) == 0 ) { + wattron( text, A_BOLD ); + }else if( strncmp( &displine[ i ], "[0", 2 ) == 0 ) { + /* end color, color will (should?) still be set from last color */ + /* wattr_off( text, COLOR_PAIR( color ), NULL ); */ + wattrset( text, A_NORMAL ); + } + /* eat chars to the next m */ + while( displine[ i ] != 'm' && displine != 0 ) + i++; + }else{ + waddch( text, (unsigned char)displine[ i ] ); + } + } + } + + /* check if we are at EOF and override timeout */ + if( curr_pos == file_size ) { + wprintw( text, "\n**** END ***\n" ); + timeout( -1 ); + } + + wrefresh( text ); + + /* Move the cursor to the end of the text window, so it looks + like a real session */ + getyx( text, cursy, cursx ); + move( cursy, cursx ); + + key = getch(); + + switch( key ) { + case 'Q': + case 'q': + looping = 0; + break; + case '+': + case '=': + speed++; + break; + case '-': + speed--; + break; + + case '1': + speed = 1; + break; + case '2': + speed = 2; + break; + case '3': + speed = 3; + break; + case '4': + speed = 4; + break; + case '5': + speed = 5; + break; + case '6': + speed = 6; + break; + case '7': + speed = 7; + break; + case '8': + speed = 8; + break; + case '9': + speed = 9; + break; + case '0': + speed = 0; + break; + + case 'r': + new_pos -= JUMP_SMALL; + break; + case 'R': + new_pos -= JUMP_BIG; + break; + case 'f': + new_pos += JUMP_SMALL; + break; + case 'F': + new_pos += JUMP_BIG; + break; + + default: + break; + } + + /* Validate speed is ok */ + if( speed > MAX_SPEED ) + speed = MAX_SPEED; + + if( speed < 0 ) + speed = 0; + + /* Check if we are moving the seek */ + if( new_pos != curr_pos ) { + wattron( text, A_BOLD ); + if( new_pos > file_size ) + new_pos = file_size; + + if( new_pos < 0 ) + new_pos = 0; + + wprintw( text, + "\n=============\nMoving from %d to file offset %d\n", + curr_pos, new_pos ); + + /* calcs offsets because we may want to seek to + 0, which using SEEK_CUR won't let us do without + some other error checking that I don't want to do */ + fseek( in, new_pos, SEEK_SET ); + + /* read to next newline so we don't break up + lines seeking around */ + fgets( line, 1000, in ); + new_pos = ftell( in ); + + /* Make a note of moving */ + wprintw( text, + "Final offset after adjusting for newline: %d (%d)\n=============\n", + new_pos, new_pos - curr_pos ); + wattroff( text, A_BOLD ); + } + } + + /* Cleanup */ + delwin( text ); + delwin( status ); + endwin(); + + fclose( in ); + + return( 0 ); +} diff --git a/plugtest.c b/plugtest.c new file mode 100644 index 0000000..596eab1 --- /dev/null +++ b/plugtest.c @@ -0,0 +1,18 @@ +#include <stdio.h> + +#include "defines.h" +#include "cmd.h" + +void plugtest( char *arg ); + +cmdstruct mycommand = { NULL, "plugtest", "test command", plugtest, NULL }; + +void powwow_init() { + printf( "Init plugtest.so!\n" ); + + cmd_add_command( &mycommand ); +} + +void plugtest( char *arg ) { + printf( "Arg was '%s'\n", arg ); +} diff --git a/powwow.6 b/powwow.6 new file mode 100644 index 0000000..197134f --- /dev/null +++ b/powwow.6 @@ -0,0 +1,115 @@ +.\" -*-nroff-*- +.TH POWWOW 6 "09 Mar 1994" +.UC 4 +.SH NAME +powwow \- telnet protocol client for MUD playing +.SH SYNOPSIS +.B powwow +[ +.I host port +] +| +[ +.I definition-file +] +.SH DESCRIPTION +.PP +.B powwow +is a client program that implements the telnet protocol, adding some bells +and whistles to the standard +.B telnet(1) +communication utility, mainly intended for playing multi-user games +such as +.I MUDs (Multi User Dungeons). +.PP +.B powwow +is either invoked with +.I host +and +.I port, +and then does not save any definitions, or with a +.I definition-file, +which is supposed to contain various definitions as well as the name +of the host and the port number. If the definition-file does not +exist, the user is prompted for the host name and port number which +are saved in the new file. The definition file can be edited with any +text editor, and is updated whenever a definition (action, alias etc) +is changed. If the environment variable POWWOWDIR is defined, +.B powwow +will look there first for definition files (and create new ones +there). + +Lines that begin with `#' are assumed to be special commands to be +processed locally. Help is available with the #help command. There is +also a more detailed manual somewhere. Notably, semicolons separate +commands on a single line. To send a literal semicolon, prefix it with +a backslash. + +.B powwow +also supports the MUME editing protocol for editing texts locally. The +name of the editor is taken from the environment variable POWWOWEDITOR +or EDITOR. "emacs" is used by default. For text viewing, POWWOWPAGER +is searched, then PAGER and "more" is used by default. + +If the first character of the editor is `&' (which is then skipped), +the editor is assumed to run in another window and powwow will run +concurrently with the editor without waiting for it to finish. + +.SH AUTHOR +.PP +Massimiliano Ghilardi <max@Linuz.sns.it> and +Gustav Hållberg <f92-gha@nada.kth.se> +are the people that added many new features to an existing client, +.I Cancan +and transformed it into powwow. +Mattias Engdegard (f91-men@nada.kth.se) was the original author of Cancan +but many other people have contributed at least as much, including +Finn Arne Gangstad (finnag@pvv.unit.no), David Gay (dgay@di.epfl.ch), +Gary Dezern (gdezern@satelnet.org) and Lai-Chang Woo (vivriel@scs.com.sg). + +.I powwow +was originally inspired by Peter Unold's +.I Tintin +client, but now only bears a very remote resemblance +to the original. It aims to be a simple but very interactive client, +and contains features that are interesting for "immortal players", in +particular on MUME, though any mud player should benefit from +.I powwow +as well. +.SH FILES +.br +.DT +.ta \w'$(POWWOWDIR)/*\ \ \ 'u +powwow The binary. +.br +$(POWWOWDIR)/* Definition files (aliases, etc) +.SH ENVIRONMENT +.DT +.ta \w'POWWOWEDITOR\ \ \ 'u +TERM Your terminal type. +.br +POWWOWDIR Where powwow will store and search for its +.br + files by default. +.br +POWWOWEDITOR Name of editor to use +.br +EDITOR Alternative editor +.br +POWWOWPAGER Name of pager to use +.br +PAGER Alternative pager +.SH SEE ALSO +telnet(1), more(1), emacs(1) +.SH DIAGNOSTICS +Most diagnostics are self-explanatory. Some are even more +self-explanatory than others, namely those who crash the program. +There is a diagnostic report called `core' which is not currently in +human-readable form. The messages from +.I powwow +are generally prefixed with a `#' to separate them from output from +the remote host. +.SH BUGS +.PP +Are you kidding? + diff --git a/powwow.doc b/powwow.doc new file mode 100644 index 0000000..5dd5420 --- /dev/null +++ b/powwow.doc @@ -0,0 +1,2152 @@ + P O W W O W + + doc for version 1.2.4 + last modified Sep 23, 1998 + +INTRODUCTION + + powwow is a client program, which replaces telnet for the lazy + mudder who wants some (only some?) extra features. + It is primarily designed for DikuMUDs, but nothing prevents its use + for other types of muds. powwow is based on another client, cancan, + and cancan was originally inspired by tintin (yet another client) + by Peter Unold (pjunold@daimi.aau.dk), but is entirely re-written. + powwow also implements the MUME remote editing protocol, which + enables you to edit texts on the mud using your own favourite + editor, several texts at once if you have a windowing terminal. + +STARTING POWWOW + + Powwow maintains definition files where aliases, actions and + mud addresses are saved. Powwow is then called by: + + $ powwow definition-file + + (the $ above stands for your prompt, do NOT type it) + + If the definition file doesn't exist (as the first time you + use powwow) you are asked for a host name and port number. + This will then be stored in the file. The file will be updated + every time you type '#save' or when powwow terminates. + The file is in plain text, so you can edit it if you want. + It makes sense to have one file for each mud you play, or for + each set of definitions you use in the same mud. + + If the environment variable POWWOWDIR exists, that directory + is first searched for definition files and new files are + created there rather than in the current directory, unless + definition-file contains a slash ("/"). + + The file 'Config.demo' is a demonstrative definition file provided + together with powwow to help you building your own configuration. + Look at it: there are many useful examples and non-trivial code + to fully use powwow. + + You may also start powwow with: + + $ powwow netaddress portnumber + + but nothing will then be saved. + + In alternative you can simply type: + + $ powwow + + and you will enter test-mode: you will be able to use internal commands + but you will need to start a session manually + (#connect main <address> <port>) if you want to connect to a MUD. + + To solve the problem met in MUME, where you may have to try many + different servers to connect to the game, a fourth syntax has been + added: + + $ powwow definition-file netaddress portnumber + + With this syntax powwow reads settings from definition file, + but overwrites the old address with the newly specified one. + + Note: If you have several sessions (different invokations) + with the same definition file active simultaneously, the + settings changed in one session can be overwritten by a change + in another session. + +QUITTING POWWOW + + At any time, you can type #quit to exit from powwow. Be + careful, as #quit brutally closes the connection to the mud, + without renting your character. Normally, you want to log out + gracefully from the mud before doing that. If you wish to cut + your link manually, you can also press the break key on your + system twice (usually Control-C or DEL) (You must hit it twice + because hitting only once is used to stop command parsing - + see the bottom of this file). + +POWWOW TEST MODE + + There are various ways to enter powwow test mode: + + 1) typing `powwow' from you command shell + (You will have to load your definition file manually if you need it, + using the following command: #load <save-file> ) + + 2) starting powwow with a definition file that does not contain + a '#host' line or contains a '#host' alone, without any address + + 3) starting powwow opening one or more MUD connections, + then closing them all. (You'll need to have #option quit + disabled or powwow will exit when closing the last connection) + + Remember that to connect to a MUD from test mode you must use: + #connect main <address> <port> + +COMMAND CHAINING + + Powwow allows you to type several commands on one line + separated by the ; character. If you want to use a semicolon + literally, prefix it by a backslash (\). (Backslashes must of + course be escaped too if used literally.) + + Examples: + > n;get coins;s rapidly rescue some money + > say No beer? \;) semicolon must be escaped + + In addition, you must also surround every list of commands by braces: + '{' and '}'. The only exception (as you can see from the example above) + is when you type multiple commands from keyboard: in that case, + and only in that, braces are not needed. + Also, if you want to use a { or } literally, prefix it with a backslash + as you do with semicolons. + + Another use of semicolons is to send a <new-line> character to the MUD + you are connected to. Infact powwow sends a <new-line> every time it + meets a null command (0 chars) followed by a semicolon. + + Examples: + > press <return> only: send a <new-line> + > ; press ; and then <return>: same effect + > ;; send two <new-line> + > ;;; three <new-line> ... + + Of course multiple <new-line> are considered as multiple commands, + so you usually have to surrond them with braces. If directly typed + from keyboard, the braces are optional. + + > {} do nothing + > {;} send a <new-line> + > {;;} send two <new-line> + > {;;;} and so on... + + The verbatim mode disables this special meaning of semicolons and + braces, and the #quote command lets you switch between verbatim and + normal mode. + +SPECIAL COMMANDS: ALIASES AND ACTIONS + + Powwow parses all lines beginning with the character '#' as + special commands. To send a line that begins with '#' itself, precede + it with a backslash. The commands are case-sensitive. + Commands can be abbreviated as much as you want. + ----------------------------------------------------------- + Alias definition + #alias [name[=[command]]] + + Aliases are abbreviations for longer, frequently used commands. + As all powwow commands, they are only recognized at the beginning + of a line or directly after a semicolon, an open or closed brace. + When an alias is used, the first word following the alias name + is placed in the variable $1, the second in $2, etc... up to $9. + also, the whole string following alias name is placed in $0. + + Then, before executing <command>, every $n in <command> is replaced + by its contents. + + Example: + #alias summ=cast 'summon' $0 (then "summ thor" is replaced by + "cast 'summon' thor") + #alias cs=cast '$1' $2 ("cs summon thor" is expanded to + "cast 'summon' thor") + #alias summ (lets you edit the definition of summ) + #alias summ= (removes the alias summ) + #alias (display all defined aliases) + #alias ws={wake;stand} (note that you must use braces) + + As noted above, aliases are saved automatically if you started powwow + with a file name as argument. + Aliases can contain other aliases, and an alias can also contain itself + (be careful, or powwow will enter a long - but not infinite - loop) + Aliases are not expanded in verbatim mode. + + Where aliases contain other aliases, one or more '\' can be prepended + to $n to delay text substition or to use the symbol $n literally. + + Example: + #alias ac=#alias $1=cast '$2' \$0 + (then "ac sm summon" will give you a new alias + "#alias sm=cast 'summon' $0") + + #alias \==score + (this defines = as an alias for 'score', Note that you must + escape the first = to force powwow to consider it literally) + + #alias \`=#history $0 + (this defines \ as an alias for '#history'. Note that you must + use ` to escape the \ . Just doing \= would escape the = ) + + Aliases starting with `#' are allowed and do work, + but cannot override any special command. + ----------------------------------------------------------- + Automatic command execution triggered on output + #action [[<|=|>|%][+|-]label] [{pattern | (expression)}=[command]] + + When 'pattern' is found in a line from the remote host, the + 'command' is automatically executed. If the pattern contains $n, + powwow matches one word of the remote line and puts it in the + variable $n. If the pattern contains &n, powwow matches a string + (possibly more than one word) of the shortest possible length + from the remote line and puts it in the variable $n. + + As in aliases, $n can be from $1 to $9. NOTE: $0 is a variable as well, + but #action automatically places in it the whole line from remote host. + As well, &n can be from &1 to &9. + + Warning: powwow does NOT print on screen lines from MUD that are + intercepted with an #action. So if you want to print them, you + must explicitly use a #print or set the #option +autoprint + (the help on #print and #option is below in this text) + If you want to intercept a prompt, use #prompt instead of #action. + (the help on #prompt is near the end of this file) + + If the first character of the pattern is ^ (caret), the match + will only be possible at the beginning of a line. + The match is case-sensitive. + If 'label' is specified, the action is labeled; otherwise it is + numbered. + + If an <expression surrounded by parentheses> is used insted of pattern, + powwow evaluates the expression with the inline calculator (see below) + and then uses the result as pattern. + + Examples: + #action ^You are hungry=eat bread + #action ^You are hungry= (removes the action) + #action ^$1 hugs you={#print;kiss $1} + #action ^$1 says &2=say $1 said $2 (note you must use $, not & + after the =) + #action Jehova={#print;say Who said that? Stone him!} + + Labeled actions: + > means define, < means delete, = is edit, + is turn on, - is turn off. + Also, >- means define and turn off, while >+ means define and turn on + ( > alone is the same as >+ ) + + #action >fount ^There is a fountain here={#print;drink water} + (named action) + #action -fount (turns off action) + #action +fount (turns it back on) + #action =fount (lets you edit it) + #action <fount (removes action) + + #action >-loot is dead! R.I.P.={#print;get all from corpse} + (define and turn off the action) + + #action >joke ("^$1 says '&2;)'")= wink $1 + (you must either use this syntax or escape the + ; to force it to be considered literally) + + #action >argh ^$1 tells you 'hello \`=tell $1 I heard you + (as in #alias, \ must be followed by ` when you + need the \ to be followed by a special char + and you do not want this char to be escaped) + + If you have compiled powwow with -DUSE_REGEXP and use % instead of > + you define an action that uses an Extended POSIX regexp to match + instead of the standard matcher. + + #action %first ^([[:alpha:]]+) ([[:digit:]]+)=#print $2 counted $3. + (matches abc 123) + + Note that if the pattern starts with '(', it is evaluated, which means + that a regexp that starts with '(' has either to be surrounded by + ("...") or to be prepended by a backslash. + Also note that powwow requires parentheses to be balanced: + for example, \(.+|) would be a valid regexp pattern as the backslash + gets removed by the unescaping, but powwow will choke on it + as the first parenthesis is escaped while the second is not. + + #action %second ("(..+)-\\1")=#print Double $1 + (matches xyz-xyz) + #action %third \(..+\)-\\1=#print Double $1 + (same as above) + For regexp actions, $0 = the line, $1 = the whole match and $2... + contain the submatches. + + Actions and aliases can run other powwow commands, including + #action and #alias. + Example: + #alias calc=#! echo '$0' | bc -l + #alias hungryon=#action ^You are hungry=eat bread + + As with aliases, additional \'s can be prepended to $n to + delay text substitution in actions. + Example: + #action >reply ^$1 tells you={#print; #alias reply=tell $1 \$0} + ----------------------------------------------------------- + +MISSING: #PROMPT + + There is another special command quite similar to #action: + #prompt [[<|=|>|%][+|-]label] [{pattern | (expression)}=[command]] + + You will need to use it only if you want to mess with the prompt + that your MUD sends, which is often not needed. Also, to use it + you need to understand exactly how powwow recognizes prompts, + so the description is considered an advanced topic and is placed + near the end of this file, in the "ADVANCED TOPIC: #PROMPT" section. + +MISSING: SUBSTITUTION AND UNESCAPING + + Also, only intuitive definitions of substitution, delayed substition + and escaping/unescaping have been given so far. If you want the real, + rigorous thing, read the "ADVANCED TOPIC: SUBSTITUTIONS AND UNESCAPING" + section near the end of this file. That section also explains + `just in time' substitution, not yet introduced. + ----------------------------------------------------------- + +SPECIAL COMMANDS: ALL OTHERS + + This is the rest of #commands recognized by powwow. + ----------------------------------------------------------- + Toggle verbatim mode + #quote [on | off] + + In verbatim mode, no alias expansion takes place and + semicolons, escapes, braces and ` are sent as typed, + unless the command line begins with a #, so you can still issue + powwow - specific commands. + This is useful if you want to paste a text from an editor into + a powwow session. + Type #quote to turn on the verbatim mode, and type #quote again + to turn it off. + ----------------------------------------------------------- + Show/execute commands in history + #history [number] + + #history alone shows you the last commands in history, up to the number + of lines in your screen. + #history -n shows the last n commands in history, and + #history n executes the n-th command of the history. + + Recursive #history commands (i.e. an #history <n> calling itself or + another #history <n>) are allowed only up to levels of 128 recursions. + + Example: + + #history 1 (repeat last command) + ----------------------------------------------------------- + Add a text or expression to word completion list (not to history) + #add {text | (expression)} + + #add puts the text or result of expression (calculator is used to + evaluate the expression) in the word completion list. + Useful if used together with #action. + Example: + + #action >reply ^$1 tells you={#print;#add $1} + (from now on, you can use TAB to complete that name) + ----------------------------------------------------------- + Put a text or expression into history (and to word completion list) + #put {text | (expression)} + + #put puts the text or result of expression (uses calculator) in the + history, so that you can use cursor-up key to recall the text as if + typed from keyboard. + Also, you can execute the text using the #history command. + Example: + + #action >safeflee ^You flee head over heels.= + {#print;#put #print You have already fled away!} + + (If you type 'flee' from keyboard, you can keep trying to flee using + cursor-up (which gets the last command in history) and <RETURN> key. + When you finally manage to flee, the message above is put in history, + so that further attempts to flee do not lead you again in danger) + ----------------------------------------------------------- + Bind keys to enter commands + #bind [edit | name [sequence][=[command]]] + + You can bind most function keys and control keys to enter a command + for you when the key is pressed. Also, you can redefine a key already + used for an editing function (such as the arrow keys). + 'name' is the label of the key you want to define; you can just use + what is written upon it. When defining a new key binding, you will + be asked to press it so powwow can record the control sequence + your terminal sends. + If you want, you can specify the control sequence directly in the #bind + command instead of having to press the key on your keyboard. + + Examples: + + #bind (lists all user key bindings) + #bind edit (lists all line editing keys) + #bind f1=recite scroll (you'll have to press f1 then) + #bind f1=cast 'sanctuary' (change existing definition) + #bind f1 (lets you edit the definition) + #bind f1= (removes the key) + #bind f1 [[A=cast 'heal' (also tell powwow that f1 on your + keyboard sends ESC [ [ A, so you + do not have to press it) + + NOTE: if there is already something on your input line, powwow + does not ruin it when you press f1 (or any other #bind), but executes + the command you want and then shows you again the input line. + + #bind f5=&prev-line (&prev-line is one of the reserved commands for + line-editing functions, see bottom + of this file) + #bind Up=u (Up is an editing key, but can be redefined) + + By default, the vt100 numeric keypad is partially used to walk around + with: + Key string sent + 2 s + 3 d + 4 w + 5 exits + 6 e + 7 look + 8 n + 9 u + + The reserved names that powwow identifies as line-editing functions + are at the end of this file, together with the default keys used for + them. + + Remember that ALL keys can be redefined... + ----------------------------------------------------------- + Change the keyboard sequence associated to an existing key binding + #rebind name [sequence] + + If you just want to change the control sequence of a binding, but not + its name or its effect, you can just tell powwow to 'rebind' it. + If #rebind is invoked with only the name of a binding, you are asked + to press the key you want to rebind. + Of course, you will not be asked to press the key if you specify + its control codes in the #rebind command. + Examples: + + #rebind f1 ^[OP (tell powwow that your f1 key sends ESC O P + and not ESC [ [ A) + #rebind f1 (you are asked to press again f1, useful if you + changed terminal in the meanwhile) + ----------------------------------------------------------- + Change the keyboard sequence of all existing key bindings + #rebindall + #rebindALL + + #rebindall runs #rebind on most key bindings (skips trivial ones like + ^A, ^B, etc.), asking you to press each corresponding key. + + #rebindALL does the same, but for really every key binding. + ----------------------------------------------------------- + Execute a key as if pressed on keyboard + #key name + + If 'name' is the label of one of the key defined with #bind, + (see above) #key executes the corresponding command. + + Example: + If you have already typed + #bind f1=cast 'heal' + + At any time, then, you can either: + - Press your f1 key on you keyboard + - Execute the command "#key f1" + and powwow will execute the command "cast 'heal'" for you. + + Using #key, for example, can be useful from inside an + #alias or #action, since powwow cannot press f1 for you. + + Since 1.1.5, powwow allows #key also for editing functions. + If you have already + #bind Up=&prev-line + and you execute + #key Up + powwow will do what you expect: step to the previous line in history. + + Warning: powwow does not distinguish at all between a real key pressed + on the keyboard and one faked with #key, so commands executed with #key + will also be written in the #record file. + + ----------------------------------------------------------- + Execute an editing function as if pressed on keyboard + #keyedit function + + If 'function' is the name of one of the reserved commands + for line-editing functions, #keyedit function will run it. + + For example, if you already have + #bind Up=&prev-line + the following are all equivalent: + * pressing the key Up on your keyboard + * executing #key Up + * executing #keyedit &prev-line + + Anyway, if you type #key or #keyedit directly from the keyboard + the effect is slightly different, as you have to press ENTER + to run them and the function &enter-line (which is executed by ENTER) + has a few side effects. + ----------------------------------------------------------- + Clear aliases, actions or what you specify + #reset {all | name of a list} + + Argument: Effect: + all clear everything (apply all lines below) + alias clear all aliases + action clear all actions + bind clear all key bindings and restart with default + settings. Note that also editing keys are resetted + to default function. + at clear all delayed commands + in (same thing) + mark clear all markers + prompt clear all prompts + var clear all variables + ----------------------------------------------------------- + Mark certain output + #mark [pattern[=[attribute]]] + + This command highlights a part of a line in your output in the way you + choose (if your terminal supports it). + See the section "ATTRIBUTES: COLORS AND OTHER HILIGHTINGS" + about the syntax of attributes. + + Wildcards are allowed in the pattern, and syntax is very similar to + #action: $ matches a single word, & matches any string. + + Examples: + #mark Sizzler=bold (mark `Sizzler' in bold) + #mark Sizzler (lets you edit the above definition) + #mark Sizzler= (Sizzler is no longer put in bold) + #mark (lists all markers) + #mark {&}=inverse (mark in reverse any string in { } + note that also the { } are highlited) + #mark ^You=yellow (mark `You' in yellow only if it appears + at the beginning of a line) + #mark \^=on blue (mark a literal ^ ) + ----------------------------------------------------------- + Set/show priority for new actions/marks + #nice [{number | (expression)} [command]] + + When #nice is 0 (default) powwow puts new actions at the bottom of the + action list (and same thing for marks). If you want to put new + actions/marks in another point of the list, just set #nice to the + corresponding value: + + If you specify a command after 'number', the new #nice value is used + only for that command, then the old value is restored. + + Examples: + + #nice 12 (tells powwow to put new actions/marks in the 12th + (place of the list) + + #nice 4 #mark Grizzly=red on blue (put the mark in the 4th place of + the list) + + Note that #nice works only for new actions/marks: if an action/mark + is already defined, you cannot change its place in the list. + ----------------------------------------------------------- + Input highlighting + #hilite [attribute] + + This sets the attribute of your entered text to the given attribute. + Just #hilite turns it off. + See "ATTRIBUTES: COLORS AND OTHER HILIGHTINGS" below for more syntax. + ----------------------------------------------------------- + Set standard colours + #color [attrib] + + (This command exists only if BUG_TELNET is defined, to cope with + deficiencies of NCSA telnet 2.2) + Set your standard foreground and background to the colours you specify. + #color returns to the default colors for your screen + ----------------------------------------------------------- + Capture output to file + #capture [[>]filename] + + This captures all output from the main MUD connection and your typed + commands to a local disk file. To close the file and end the + capturing, type #capture without argument. + If the filename starts with a '>', new text will be appended to the + end of the file instead of overwriting it. + You can only capture output to one file at a time. + Example: + > #capture message + > look at board + > #capture + + It is possible to capture in the #capture file even text that you have + _already_ received: see #setvar buffer. + ----------------------------------------------------------- + Record typed commands to file + #record [filename] + + This records all text typed from keyboard to a local disk file. + (output from remote host is not recorded) + To close the file and end the recording, type #record without argument. + You can only record typed text to one file at a time, but #capture and + #record can be active at the same time on different files. + Example: + > #record walk-home + > n;e;e;u;n;w;s + > open door + > s + > close door + > sleep + > #record + ----------------------------------------------------------- + Capture output to file, with timestamps + #movie [filename] + + This is similar to #capture, but adds timestamps to each line + received from the main MUD connection or typed from the keyboard, + to allow replay at correct speed. + The program `movie_play' for replay is included with powwow sources. + Usage: `movie_play <filename>' + To convert a movie to plain ASCII, the program `movie2ascii' + is included too. + Usage: `movie2ascii <infile> <outfile>'. + + It is possible to capture in the #movie file even text that you have + _already_ received: see #setvar buffer. + ----------------------------------------------------------- + Execute a shell command + #! command + + Executes a command using /bin/sh. Powwow waits until your shell + finishes, but you can put jobs in the background with & as usual. + Example: + > #! who | sort | less + > #! nethack + > #! xbiff & + + Note that semicolons, escapes and braces need to be escaped if they + are to be sent to the shell. + If your shell has job control, you can also suspend powwow + with ^Z as usual. + ----------------------------------------------------------- + Put a string in the edit buffer automatically + #prefix [string] + + Each new line you type will automatically begin with the prefix string. + You can of course edit or delete the inserted string as usual. To + remove the prefix, just issue a #prefix command without arguments. + This is handy when you are talking to someone, for example. + > #prefix tell arthur + ----------------------------------------------------------- + Help + #help [keys | math | command] + + Shows a list of powwow's commands. + '#help keys' shows the editing keys. + '#help math' show help on inline calculator. + You can also have help on specific commands, using for example + '#help alias' or in general '#help <command-name>'. + A help file is needed and provided for this last feature of #help, + and powwow will look for the file "powwow_help" in the directory + specified by the environment variable POWWOWHELP. If this variable + does not exist, powwow looks in current directory. + ----------------------------------------------------------- + Command repetition + #n command + + This repeats the command n times. Example: + > #5 buy bread (buy five breads) + + + Alternatively, you can use this syntax to repeat a command n times: + #do (expr) command + + In this case, powwow evaluates the expression, and uses the result + as counter. + Example: + > #do (3*8) north (go north 24 times) + ----------------------------------------------------------- + Iterate a command + #while (expression) command + + This syntax repeats a command while expression (evaluated with + calculator) keeps true. (see below for help about calculator) + As with #alias and #action, the $n and @n in command are + replaced by their values. (Even if you can, using @n after the = + in #action and #alias is useless, because you have no way to + assign them a non-zero value. This is the reason why we did not talk + about them in the #alias and #action section) + + Example: + + #while (@0<13) {read @0;#(\@0++)} read messages 0-12 + As you can see, the last @0 is escaped to avoid it to be + substituted with its value. (We want to increase the variable!) + ----------------------------------------------------------- + Iterate a command + #for ([init];check;[loop]) command + + Directly copied from C language, this command evaluates 'init' + with calculator (if specified), then repeats the following cycle: + 1) evaluate 'check', if result is 0 (false) stop repetition + 2) execute 'command' + 3) evaluate 'loop' (if specified) + 4) restart from 1) + + As with #while, #for performs the parameter substitution in 'command', + so the only significative difference between #while and #for is that + #for allows you to execute an initialization before the repeat cycle. + + Example: + + #for (@1=32; @1<=47; @1++) read @0 (read messages 32-47) + ----------------------------------------------------------- + Branch execution command + #if (expression) command1 [; #else command2] + + Evaluate the expression: if result is 'true' execute command1, + otherwise (if there is an #else) execute command2. + If expression is false and there is no #else, execute nothing. + remember that you must use braces {} if command1 or command2 + contain more than one instruction. + + Note that nested #if-#else are allowed, and that #if-#else itself + is not a multiple command. + + WARNING: using an alias for #if is very dangerous and will cause + powwow to make confusion when the full #if-#else syntax is used. + ----------------------------------------------------------- + Automapping control + #map [-[number] | walksequence] + + With no argument, "#map" shows the map of the directions you + travelled up to now. "#map -" clears the last number of steps + from the map. + + Example: + #map (displays "#current map: e3su" after above walk) + #map -1 (leaves the map as "esss") + #map - (clears the whole map and starts fresh) + #map nsssue (add the list of directions to map) + ----------------------------------------------------------- + Retrace steps + #retrace [number] + + This command walks you in the reverse direction of the last + number of steps. If number is 0 or left blank, you walk all + the way back to where automapping started. + ----------------------------------------------------------- + Connect initialization string + #init [=[command]] + + This command sets up the initialization string to send to + the host on establishing a connection. + + Example: + #init (shows the string) + #init ={#identify;#speedwalk} (sets the string) + #init = (clears the whole string) + ----------------------------------------------------------- + Identify as an editing client + #identify [startedit [endedit]] + + This command sends an identification string to the server, to + indicate that the client supports editing functions. It is + best attached to an action trigged by a string in the login + screen, but can also be entered by hand. + This command must be issued for the cooperative editing to work + on servers that support it (currently only MUME). + The startedit/endedit parameters are commands issued when an editing + session starts/ends (for changing your title, emoting etc). + + Example: + + #action >mume *** MUME=#identify + #identify foo bar + (where foo and bar are aliases that do something useful) + ----------------------------------------------------------- + Identify as a IAC GA compliant client + #idprompt + + This command sends an identification string to the server, to + indicate that the client supports (and wants) the special sequence + IAC GA at the end of each prompt. This helps the client + to automatically detect the prompt, and can be used as alternative + to #prompt / #isprompt if all you want with the prompt is detecting + it (and not altering it) + + BIG WARNING: + this is experimental and not tested! + last time I checked, MUME used to kill the link on #idprompt + + Example: + + #action >mume *** MUME={#print;#identify;#idprompt} + #idprompt + ----------------------------------------------------------- + List all editing sessions + #edit + + This command shows your active editing sessions, with a brief + description and their number. + ----------------------------------------------------------- + Cancel an editing session + #cancel [number] + + Without an argument, all editing sessions are cancelled; + otherwise, only the given session is cancelled. The corresponding + editor processes are brutally killed. + ----------------------------------------------------------- + List/turn various options on/off + #option [[+|-|=]option-name] + + Currently available option names are: + exit, history, wrap, compact, debug, echo, info, keyecho, + speedwalk, wrap, autoprint, buffer, reprint, sendsize, + autoclear + + #option +name turns an option on + #option -name turns it off + #option name toggles it + #option =name reports its status + + ------------- + #option exit + + If the `exit' option is on, powwow automatically quits when the last + connection is closed. Otherwise, to quit powwow you need to manually + type `#quit' + ------------- + #option history + + With `history' option on, powwow writes into your savefile also + all your commands in history + ------------- + #option words + + With `words' option on, powwow writes into your savefile also + your word completion list + ------------- + #option compact + + Normally, powwow does not touch the prompts on screen while you play. + In `compact' mode, instead, lines containing only a prompt are deleted + when further messages arrive from the remote host. + + WARNING: this command works correctly only if you have #prompts which + correctly run #isprompt. Otherwise it may occasionally erase + some lines from the screen. + ------------- + #option debug + + Normally, powwow does not print on screen the command lines it + executes. When `debug' is on, every line executed by powwow is also + echoed on screen, so that you can check if your code works correctly + (warning: this prints LOTS of lines on your screen) + ------------- + #option echo + + Normally, powwow echoes on your screen each command sent to remote + host but not directly typed (example: aliases and actions sending text + to the MUD). When `echo' is off, such commands are still sent to host, + but not echoed on screen. + ------------- + #option info + + Normally, powwow prints on screen some messages each time you + define/edit/delete an #alias, #action, #bind and similar. + When `info' is off, those messages are not typed at all. + (But errors are still printed on screen) + ------------- + #option keyecho + + Normally, powwow echoes on your screen the commands sent to remote host + when you hit a key associated to a #bind. When `keyecho' is off, such + commands are still sent to host, but not echoed on screen. + ------------- + #option speedwalk + + With `speedwalk' on, a command consisting of only lowercase + n, e, s, w, u, d and numeric digits is considered to be a + walk sequence. The numeric digits specify the number of + times to repeat the direction immediately following. + + Example: + esssu (walk east, 3 south, up) + e3su (same as above) + ------------- + #option wrap + + Normally, powwow wraps words that would have been cut by the right + margin to the next line. This command lets you turn it off and on. + ------------- + #option autoprint + + If `autoprint' is on, powwow prints lines matched by an #action + even without an explicit #print. + ------------- + #option sendsize + + Usually powwow does not send the window size to the MUD unless asked. + If you want to send the window size automatically upon connecting, + you may enable this option. + ------------- + #option autoclear + + Powwow normally erases the input line before executing commands + from spawned programs, but that is slow and causes flicker. + If autoclear is disabled flicker reduces to minimum, + on the other hand spawned programs must then execute #clear + before sending anything to screen. + ------------- + #option reprint + + If `reprint' is on (off by default), powwow prints again commands + sent to the mud but not yet executed. + WARNING: it works only if you use #prompts which correctly run + #isprompt. + + ++++ example: ++++ + *>look + south + down + + The High Path + + *>Path Climbing a Hill + + *> + Alas, you cannot go that way. + + *> + ++++ becomes: ++++ + *>look + south + down + + The High Path + + *>(south) + Path Climbing a Hill + + *>(down) + Alas, you cannot go that way. + + *> + ----------------------------------------------------------- + Show current version + #ver + + Displays the current version, some compile options and (if + your compiler supports it) when powwow was compiled. + ----------------------------------------------------------- + Multiple connections handling commands + #connect [session-id [initstr] [host port]] + connect a new session / list sessions + #snoop session-id toggle output display for session + #zap session-id disconnect a session + ##<session-id> set <session-id> as default session + ##<session-id> command execute command on <session-id> session + + No docs here. If multiplaying is allowed on you MUD (and many + do NOT allow) you can experiment a little to find how they work. + Or you can open two connections to two different MUDs :) + ----------------------------------------------------------- + Spawn an external program + #spawn session-id command + + Creates a new session, connected to a shell command instead of a MUD. + Writing to ##<session-id> sends data to the command's standard input, + while the command's standard output is executed as if typed + from keyboard. Useful if you are a programmer and you want to create + very complex filters or robots, for which #actions are too limited. + Command's standard output *MUST* terminate with a newline ('\n') in + order for powwow to execute it. + You can send multiple commands at once terminating each of them + by either a semi-colon ';' or a newline '\n', except for the last one + which (I repeat) *MUST* terminate with a newline. + + You can close these sessions with #zap and list them with #connect + as usual. + + Depending on how lazy you are, you can choose two different ways + to have spawned programs print to screen: + + The first is automatic, but slow: with `#option +autoclear' + powwow clears the input line before executing every line received + from the program. This is of course slow and causes flickering. + + The second is more complex, but faster and reduces flickering to the + minimum: set `#option -autoclear' from the beginning, then have + the program execute `#clear' before printing. + ----------------------------------------------------------- + Exit from powwow + #quit + + Very little to say here. Just remember that #quit brutally + closes all mud connections that are still open, without + renting your characters. Quite likely, you want to rent them all + before quitting. + ----------------------------------------------------------- + Set definition-file and save settings to it. + #save [definition-file] + + Useful after you write large chunks of code. + Remember anyway that powwow automatically saves the settings + before exiting. + + #save actually writes settings to a temporary file and overwrites + the definition file only if write succeeds. This is to avoid wiping out + definition file in case of `disk full' or other errors. + ----------------------------------------------------------- + Set definition-file and load settings from it. + #load [definition-file] + + Useful if you want to undo the changes in your settings. + + NOTE: current settings are completely erased before actually loading + from file. In case of errors, powwow reloads the default editing keys. + + If you just want to add the contents of a file to your current settings + use #exe <filename instead of #load. + ----------------------------------------------------------- + Set/show/clear definition-file name + #file [=[definition-file]] + + As default, the definition-file is the one loaded when you start + powwow. Remember that powwow automatically saves your settings to it + before exiting. If you want to disable this autosave, use #file = + ----------------------------------------------------------- + Various commands: + #net show amount of data transmitted to and received from + the remote host. + #cpu show the CPU time used by powwow. + (if powwow does not find the symbol CLOCKS_PER_SEC + defined at compile time, the result may not be in + seconds...) + #time show current time/date. Useful if you want to use #at. + + #beep ring your terminal's bell (like #print (*7)) + ----------------------------------------------------------- + List/delete/define/edit delayed commands + #at [label [(time-expression) [command]]] + or + #in [label [(delay in millisec.) [command]]] + + If you want to tell powwow to execute the command 'kill wolf' + 2 seconds after you type it, use this command: + #in attack (2000) kill wolf + Let's explain the command: + 'attack' is a label, exactly as in #actions, and is used only to have + a quick reference to the delayed command; + (2000) means wait 2000 millisec., i.e. 2 seconds; + 'kill wolf' simply executes kill wolf, as if typed from keyboard. + + Of course, you can use an expression (as complex as you like) + instead of the number in parentheses, + and the command can also be an alias, internal command or even + another #at or #in. (of course you can use multiple commands by + placing them in { } ) + + If you do not specify the command, powwow assumes the label is already + defined, and changes its delay. + A delay less than zero means the delayed label is disabled, + but still in powwow's memory, similar to what happems when you + turn off an #action. + A delay of zero deletes the delayed label. + + If you specify only a label, powwow lists it. + If you specify nothing, all delayed labels are listed. + + The #at command is nearly equal to #in, but assumes the expression + in ( ) is a time. For example (114520) means 11:45:20 , + and ("114520") is the same. + After evaluating the time, powwow converts it into a delay, + and places the delayed label in the same list of #in. + NOTE: it is not possible to delete a delayed label using #at, + since (0) means midnight. + One more thing: it is not possible do define disabled labels using #at, + because a time < 0 is an error, and a time < current-time is assumed + to be refering to the following day. + + Last note: after executing a delayed command, powwow does not delete + it, but simply disables it. + ----------------------------------------------------------- + Disable all delayed commands + #stop + + All active delayed commands are set to 'disabled', but are not deleted + from memory. Useful to stop infinite loops due to self-reactivating + delayed commands. + ----------------------------------------------------------- + Set save file options + #option [none]|[words][history] + + Controls wether command history and completion words shall be saved + in the save file. + + Without arguments, #option displays the current settings. + To turn off both words and history, use #option none; otherwise + use #option followed by words and/or history. + + ----------------------------------------------------------- + Evaluate expression with calculator, and trash result. + # (expression) or #(expression) + + ----------------------------------------------------------- + Print a text or result of an expression on screen. + (does NOT send it to the MUD) + #print [< | !][text | (expression)] + + If a string is specified, powwow simply prints it on screen. + If an expression is specified, powwow uses the inline calculator + to evaluate it, and then prints the result. + + If a #print without arguments is found, powwow prints the value + of the variable $0 (this is a special feature of #print, and is not + present in #exe, #send, #emulate or #var). + This is usually used to print a line from remote host that was + intercepted by an #action, in fact #action places the whole line in $0 + + If < precedes the text or expression, #print assumes text (or result + of expression) to be name of a file, and displays the contents of + that file. + + Instead if ! precedes the text or expression, #print assumes text (or + result of expression) to be a Bourne shell command, whose output is + displayed. + + Example: + + #action >disint ^&1 disintegrates &2=#print $1 DISINTEGRATES $2 + put the text in upper case + #action >disint ^&1 disintegrates &2=#print ($(1)+" DISINTEGRATES "+$(2)) + same thing, but using calculator + + #print <mytext display a text on screen + #print !("more mytext") same thing, but uses 'more' + as text viewer and alternate syntax + #print (@-7) print value of variable on screen + #print <($2) display the contents of file whose + name is in variable $2 + + Further feature: + + If < is specified, and you use an expression after it, you can also + specify starting and ending line of the file that you want to use, + in this way: + + #print <(string-expr;[start];[end]) + + Note: if you use a plain text as file name (like in #print <myfile ) + you cannot specify starting and ending line. + + If starting line is not specified, powwow begins from the first line, + if ending line is not specified, powwow stops at the end of the file: + + #print <("myfile";3;42) print lines from 3 to 42 of myfile + + #print <("myfile";;57) print lines from start of file to 57 + + #print <("myfile";;) print whole file + + Note that you can use expressions instead of filename, starting line + and ending line: + + #print <($5;4;3+@0) print file whose name is in variable $5 + from line 4 to line 3+@0 + + Of course, you can still use the whole file in the old way: + #print <("myfile") or #print <myfile + + + Further feature (another): + + The starting and ending line can be specified ALSO when you use a ! + before an expression: + + #print !(string-expr;[start];[end]) + + In this case, powwow executes the Bourne shell command contained in + the string, and prints ONLY lines from <start> to <end> of its output. + + Also here, you can use expressions instead of Bourne shell command, + start and end, and powwow still begins from first line if <start> + is not specified and/or stops at the end of the output if <end> + is not specified. + + Both these special features are supported ALSO in #send, #exe, + #emulate and #var. + ----------------------------------------------------------- + Send text or result of an expression to MUD + #send [< | !]{text | (expression)} + + The simplest use of #send is to evaluate an expression and to send + the result to the MUD. More generally, #send is very similar to #print, + with the only difference that the final text is sent to the MUD rather + than displayed on screen. + The meaning of < and ! is the same, and #send does the expected things + when they are used. + + Example: + + #send <mytext stuff a text into the mud + #send !awk ' {print "tell arthur " $0} ' file + say a file to your friend + #send ("say I have been playing for " + %(timer/86400000) + " hours") + timer is a variable holding the number of millisec + elapsed since last timer reset, and the big number + after it converts the elapsed time in hours. + ----------------------------------------------------------- + Execute text or result of an expression + #exe [< | !]{text | (expression)} + + Evaluate the expression and get result, + then execute result as if typed from keyboard. + If < or ! is specified, #exe behaves exactly like #print, + but executes the final text as if typed. + + Example: + #exe ("sigh") is the same as typing sigh from keyboard. + + #bind control_s=#exe ("#capture emergency" + %(@-7++)) + (control_s must be a user defined key) + safe capture to file: each time you press control_s, + a different file is opened as capture. + + #exe <mytext read the file mytext and execute all the + commands in it, one line at time. + Very useful to read a set of #alias for example + ----------------------------------------------------------- + Process a text/expression/file as if received from remote host + #emulate [< | !]{text | expression} + + Evaluate expression and get result, then process result as if received + from remote host + If < or ! is specified, #emulate behaves exactly like #print, + but processes the final text as if received from remote host + (check for matching #actions, extract prompt, etc.) + + This command is particularly useful to test and debug #actions. + Example: + + #emulate The assassin is dead! R.I.P. + #emulate <myfile + ----------------------------------------------------------- + Put a text or expression in a variable / delete a variable + #var variable[=[[< | !]{text | (expression)}]] + + Evaluate expression and get result, then put result + in the specified variable. + If < or ! is specified, #var behaves exactly like #print, + but puts the final text into the specified variable. + If you specify no right-hand expression, powwow puts the current value + of the variable on input line, to allow you edit it. + If you specify no right-hand expression, BUT YOU USE the =, powwow + deletes the variable and frees memory used by it. + + Note: If you use a numbered variable rather than a named one, + instead of a number you can place an expression after the $ or @ + and before the = + Example: + + #var @7=22 (same as #(@7=22) ) + #var $-4 = hello (note that you do not need quotes + since you are using a plain text) + #var $-4 = ("hello") (if you use parenthesis, you must also + use quotes) + #var $test= long sentence (all the spaces but the first following + the = are placed in the variable) + #var $(2+4) = <myfile (put the whole file in $6. Remember + that string variables cannot be longer + than 1024 characters...) + #alias calc=#var @-1 = !echo '$0' | bc -l + (place result from bc calculator into @-1) + + #var $target (put current value on input line) + + #var $my_variable= (delete $my_variable and free memory) + ----------------------------------------------------------- + Write text to a file + #write [> | !](expression ; file) + + Evaluate expression and get result, then write result into file. + By default, text is appended at the end of the file. + + If > is specified, #write deletes the contents of the file before + actually writing the text. + + If ! is specified, #write assumes second parameter to be + a Bourne shell command (instead of a file name) that is executed + using the text as its input. + + Example: + + #write ($test; "myfile") (append contents of $test to myfile) + + #write !("55+12";"bc -l") (execute 'bc -l' writing text to its + standard input) + + Advanced `#write' usage: + + If you are using a terminal allowing multiple windows (an X11 graphic + terminal for example) it is possible to duplicate/split powwow output + to multiple windows using #write. This is more a UNIX topic rather + than a powwow-specific one, but that's it. Here is a brief summary: + + First, compile the `catrw' mini-program i.e. type + $ make_it catrw + if the above worked, type + $ mkfifo fifo + This will create a special file named `fifo' in the directory + (any other name would do, of course) + Then you have to open another window. This depends on the terminal + you're using, but for X11 terminals the following works: + $ xterm & + On the second window, type + $ exec catrw fifo + (in case this gives you an error, try just `catrw fifo') + Now return to the first window and start powwow normally. + To send text to the second window from within powwow, type: + #write ("some text"; "fifo") + You should see `some text' (without the quotes) immediately + appear in the second window. + + Of course you may now want to send text automatically + to the second window: just use #write ( <your-text> ; "fifo") + from within an #alias, #action or whatever you like. + + P.S.: + for experienced users: if you are using the `bash' shell, + you don't need `catrw' as you can use + $ exec cat <> fifo + instead of the above + $ exec catrw fifo + ----------------------------------------------------------- + Set/show internal variables + #setvar name[={number|(expr)}] + + Evaluate the expression and get result, then set the internal + variable `name' to that value. + + Known internal variables are: + + buffer with `buffer' different from zero, powwow saves + the most recent text from the MUD in a circular list + (which is `buffer' bytes long) and writes it + at the beginning of #capture and #movie files when + you open them. This is useful if something important + happens suddenly and you want to log it somewhere: + you can start #capture and/or #movie even _after_ the event + has happened and it will still get written to the file. + + if `buffer' is zero (default), powwow starts logging + text from the MUD only at the moment you activate + #capture or #movie. + + To discard the text stored in memory by `buffer', + change its value (for example, set it to zero + and then back to a non-zero value). + + lines the number of lines your terminal has. Powwow usually + autodetects it correctly, but on few terminals you may + have to set it manually. + + mem the maximum length of a text or string, in bytes. + The default is 0 (zero) which means no limit. + I added it only to prevent bringing down the whole system + with things like + #while (1) #($foo += $foo + "x") + Consider it an emergency setting, as powwow _discards_ text + and strings longer than the limit. + The failsafe limit set when loading a savefile from an older + version is 1Megabyte, which won't give any problem + (like increased memory usage) as powwow allocates memory + only when it *has* to. + + timer the number of milliseconds since program start. + It can be changed to synchronize with an external clock + like MUD ticks. + + Example: + + #setvar timer=0 (reset internal timer to 0) + #setvar timer=20000 (make internal timer restart from + 20000 milliseconds) + #setvar timer (show timer and let you edit it) + + #setvar mem=1048576 (max strings length is now 1Megabyte) + ----------------------------------------------------------- + Send raw data to MUD + #rawsend {text | (expression)} + + This is mostly a MUD debugging tool, but it can be useful in some cases. + Like its cousin #send, #rawsend evaluates the expression (or unescapes + the text) and sends the result to the MUD. The difference is that + #rawsend does NOT add a final newline, nor does IAC escaping to protect + ASCII 255 characters. On the other hand, #rawsend can handle ASCII 0 + characters, while plain #send can't. + ----------------------------------------------------------- + Send raw data to screen + #rawprint {text | (expression)} + + Like its cousin #print, #rawprint evaluates the expression (or + unescapes the text) and sends the result to the screen. The difference + is that #rawprint does NOT add a final newline. On the other hand, + #rawprint can handle ASCII 0 characters, while plain #print can't. + ----------------------------------------------------------- + +INLINE CALCULATOR: + + The inline calculator is used to evaluate expressions inside + #(), #print (), #exe (), #send (), #if (), #while(), #for (), #do (), + expressions in pattern of #actions and in other commands allowing () + + The inline calculator recognizes the following objects: + + numbers (only integers are supported) + decimal numbers: + simply write them. + + hexadecimal numbers: + use '#' as prefix: #F is 15, #a0 is 160, and so on. + + numbers in any other base: + use base# as prefix: 2#101 means 101 in base 2 (that gives 5) + 7#14 gives 11, etc... + + if you use negative non-decimal numbers, you must put '-' + before the base: - 2#101 is -5, 2#-101 causes an error. + + it is possible to chain more than one '#': + 3#12#100 = (3#12)#100 = 5#100 = 25 + + both base and argument must be numbers, not variables: + things like 7#@count or @count#7 are not allowed, you will + have to use an #exe for that. + + quoted-strings (i.e.: strings in " ") + + NOTE: + since version 0.6d, powwow performs unescaping on quoted strings + when they are evaluated. For example "\"" is the string that contains + the character " only. + + timer (number of milliseconds since last timer reset) + + map (string containing the last 999 steps you walked, + as the #map command) + + variables: + @n with n within -50 and 9, are numeric-variables + $n with n within -50 and 9, are string-variables + + Since version 0.8, also named variables are supported: + + @any_name1 + $any_name2 + + The name following @ or $ can contain any of these chars: + uppercase or lowercase letters ('A'...'Z' and 'a'...'z') + underscore ('_') + numbers ('0'...'9') + Anyway, the first char of the name must NOT be a number. + + Remember that powwow is case sensitive: + $test and $Test are NOT the same variable + + Named variables are created the first time you use them + and can be deleted only using the #var command + + A special named variable is $prompt, which contains + the current prompt. It cannot be deleted. + Another special variable is $last_line, which contains + the last non-empty line received from the MUD. Again, + it cannot be deleted. + + Difference between the various kind of variables: + + Numbered variables with negative counter (@-50..@-1 and $-50..$-1) + and named variables are global: + They can be accessed at any time, but cannot be used for the + substitution performed by #alias, #action, #while and #for. + + Instead, numbered variables with positive counter (@0..@9 and + $0..$9) are local: + A new set is created (and initialized to zero) every time powwow + executes an #alias, #action, #while or #for, and the old set + is made invisible. After the #alias (or #action, #while, #for) + is executed, the old set is restored. + Note that also @0..@9 can be used for parameter substitution, + and not only $0..$9. + + Variable names as expressions: + + The symbols $ and @ are implemented as normal operators, + which means that variable names can be arbitrary expressions. + For example, + $(1-3) is the numbered variable $-2 + @("foo"+"bar") is the named variable @foobar + $$1 is the variable whose name is in $1 + + operators between numbers: + ++ -- + - + * / % + + - + << >> + < <= > >= == != + & | ^ + && || ^^ + = *= /= %= += -= <<= >>= &= ^= |= &&= ^^= ||= + , + ( ) + (% and %= always return non-negative values) + (no help on these operators, see a C-language manual) + (note: unlike C, operators &&, ^^ and || always eval both arguments) + + random number generator: + + rand positive-number (return a random number between 0 and n-1) + + operators between strings: + + chain two strings + = assign a string to a string-variable + += append a string to a string-variable + - compare two strings: result -1 if s1<s2, +1 if s1>s2, + 0 if s1==s2 + < <= > >= == != compare two strings + .? number of chars in a string + :? number of words in a string + ? position of first occurrence of second string in the first + * convert first char of a string into its ASCII code or vice versa + % convert string into its numeric value or vice versa + + operators between a string and a number: + (string is first argument) + : n-th word of a string + . n-th char of a string + :< :> <: >: .< .> <. >. return part of a string, in this way: + : before > or < means 'mark the n-th word from the left' + . before > or < means 'mark the n-th char from the left' + : after > or < means 'mark the n-th word from the right' + . after > or < means 'mark the n-th char from the right' + > means: return from marked word/char to end + < means: return from start to marked word/char + + so we get: + :< n first n words + :> n from the n-th word (include) to the end + <: n from the begin to the n-th word (included) + >: n last n words + + and similarly for .< .> <. >. + + * repeat a string n times: "ab" * 3 gives "ababab" + *= usual shortcut: `$x *= n' is the same as `$x = $x * n' + + functions for low-level color handling: + + noattr (string containing the escape sequence to reset terminal + colors and attributes -- bold, underline, inverse) + + attr "quoted-string" + (return the escape sequence needed to turn on + the attributes and colors in the string. + Syntax of the string is the same as #mark, #hilite, etc) + + + Examples: + + #print ($5="Hello, world") (assign "Hello, world" to $5 + and print it) + #print ("This is a test">:3) (print from the 3rd word from the right + till the end of the string) + Result: "is a test" is printed on screen + + #action >+exp ^You have scored $1 exp={#print;#print ("You gained " + + ( $1 - @-5) + " exp. points since last score"); #(@-5 = $1)} + + (when you type 'info' in MUME, one of the lines you get is: + You have scored xxx exp. points ... + The #action above intercepts this line, prints it, prints the + difference between your current score and the contents of + variable @-5, then copies your current score in @-5) + + #print ($5 = (attr "bold green") + "Hello, world!" + noattr) + + (same as first example, but with colors/attributes. + Rememeber to print noattr at the end of every colored line, + or everything appearing on the screen after your line + will be colored as well) + ----------------------------------------------------------- + +HOW INLINE CALCULATOR IS IMPLEMENTED + + Info and hints to get the most out of calculator and/or hack it. + + The structure `op_list[]' defined in xeval.c contains definitions for + all the implemented operators, one for each line. Have a look at it + to find things like: + + precedence (first number in each line) + associativity (LEFT or RIGHT) + LEFT means that 1+2+3 actually is (1+2)+3 + RIGHT means that 1+2+3 actually is 1+(2+3) + (replace numbers and operators with what you are actually using) + if it is unary, i.e. needs ONE argument + PRE_UNARY means that the operator comes before its argument, + POST_UNARY is the opposite + or binary i.e. needs TWO arguments + + Note that stuff like `attr', `rand', `@' and `$' are actually + implemented as PRE_UNARY operators (named variables are treated as an + exception to this), thus `$(1+5)' and `attr ("bold"+" "+"inverse")' + are fully allowed. Also note that using `$(5)' is a good way to avoid + the parameter substitution performed by aliases, #action, #for, #while + and use instead the actual variables. + + `timer', `map', `noattr' are implemented as read-only values: + the calculator simply substitutes them with their value + + Remember that there is a , (comma) operator: + Instead of `#(foo);#(bar)' you can use `#(foo, bar)' + Using comma operator is easier for both you and powwow, since it uses + a single command instead of two. + ----------------------------------------------------------- + +ATTRIBUTES: COLORS AND OTHER HILIGHTINGS + + Some commands use attributes to specify the visual appearance of text. + The following attributes are available: + bold, blink, underline, inverse + -- the obvious effects + reverse -- same as inverse + [color] [on color] -- foreground and/or background + Colors are: + black, red, green, yellow, blue, magenta, cyan, white and + BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, none + ('none' means to use default and is implemented as a color) + + Examples: The following are all valid attributes: + none -- no attribute, use default + green -- only foreground + on white -- only background + yellow on cyan -- foreground and background + inverse bold -- + blink red on blue -- you can use multiple attributes, + but you must put 'bold' 'inverse' + and/or 'underline' BEFORE colors + + Observe that bold, blink, underline and reverse work with all terminals + that support these attributes, but colors only on terminals that + support ANSI color escape sequences. + + Capitalized colors (BLACK..WHITE) are non-ANSI high intensity colors, + and will not work on all terminals (They work on the 'aixterm' terminal + emulator under AIX, but they may work on other terminals as well. + Let me know if you find other terminals that support them). + + Notes for IBM PC and compatibles with VGA or SVGA cards in text mode: + -- yellow is actually brown + -- bold is usually represented as high intensity + -- blink can be represented either with actual blink or + high intensity background - depends from card configuration + (it is possible to reprogram it - I can send details if asked) + ----------------------------------------------------------- + +HISTORY + + Powwow keeps in memory the last 127 lines you typed from keyboard. + If you want to recall one of them (to correct a mistake for example) + you just need to press your arrow-up key or control-p to scroll through + the whole history, one step at time (see COMMAND LINE EDITING below + in the text for details about editing keys). + + Another way to find a certain line in the history is to type the first + few chars of it, and then press M-TAB to tell powwow to complete the + line for you. If you hit M-TAB repeatedly, powwow will cycle + through all the possible completions. + + Also, you can use the '#put' command to add a line to history + as if you typed it (see above for help on #put). + ----------------------------------------------------------- + +WORD COMPLETION LIST + + Powwow also remembers the last 512 words you typed from keyboard. + This list of words is named `word completion list'. If you have already + typed a long or difficult word, you can type the first few chars of it + and then press TAB key to ask powwow to complete it for you. + Again, if you hit TAB repeatedly powwow will cycle through + all the possible completions. + + Powwow can also complete the name of any built-in command even if + not present in the word completion list. + + Also, you can use the '#add' command to add a word to word completion + list (see above for help on #add). + ----------------------------------------------------------- + +COMMAND LINE EDITING + + The default key bindings for line editing follow quite closely Emacs: + These are all the keys, together with the reserved names that identify + their function (they can be listed typing '#bind edit'): + + Key: Function name: Description: + + ^A &begin-of-line beginning of line + ^E &end-of-line end of line + ^B &prev-char backward one character + ^F &next-char forward one character + ^P &prev-line use previous line in history (step backward) + ^N &next-line use next line in history (step forward) + ^D &del-char-right delete character under cursor + BS &del-char-left delete character left of cursor + ^K &kill-to-eol kill to end of line + ^T &transpose transpose previous character with next + (if at the end of the line, the two last) + ^L &redraw-line redraw your command line. + This is useful if something garbles your input + line. + ^Q &clear-line clear input line. + ^W &to-history put current line in history and clear input + line. This is useful when you are typing a long + line and need to send another urgent command + first. + ^Z &suspend suspend powwow in the background + Tab &complete-word complete the word being typed to the last + matching word in the history (or added with an + #add command; see above). + Hit multiple times to browse the possible + completions. + This is similar to the GNU Emacs M-/ command. + M-Tab &complete-line complete the line being typed to the last + matching line in the history. + Hit multiple times to browse the possible + completions. + M-f &next-word forward one word + M-k &redraw-line-noprompt + redraw command line, discarding prompt + M-b &prev-word backward one word + M-d &del-word-right delete word right of cursor + M-BS &del-word-left delete word left of cursor + M-l &downcase-word turn word to lowercase + M-t &transpose-words transpose previous word with next + M-u &upcase-word turn word to uppercase + Ret &enter-line the most obvious: execute the typed line + LF &enter-line same thing, but for ^J key (some terminals + send this when you hit return) + (none) &insert-string insert on command line the specified chars + + M-x means pressing the META or Alt key at the same time as x, + or pressing and releasing the escape key, then typing x. The former + way doesn't work on all terminals. + + ^x means pressing the Control key at the same time as x. + + If your terminal has arrow keys, they can be used to move the + cursor and step around in history. In addition, you can define your + own key bindings for sending quick commands (see the #bind command). + If you have a vt100-compatible terminal, the numeric keypad is + predefined for movement (keys 2, 3, 4, 5, 6, 7, 8 and 9). + + Remember that ALL keys can be redefined... + + + A brief note about &insert-string: + + By default no key is bound to this function, and it works somewhat + differently than other editing functions. + + For example, say you don't have `{' and `}' on you keyboard + (it happens on all italian keyboards -- like mine -- and other ones). + Obviously, typing { or } gets quite difficult. A solution is: + + #bind F11=&insert-string \173 + #bind F12=&insert-string \175 + + where \173 and \175 are typed normally: a backslash and three digits. + Once you defined these two bindings, hitting F11 will be exactly like + typing { and hitting F12 will be exactly like typing } . + + Another possible use is to enter strange characters or strings: + + #bind F10=&insert-string Ro\353ntgen + does exactly what you expect: insert "Roëntgen" on the input line + ( ë is the ASCII char (octal)353 or (decimal)234 ) + as if you typed it (of course you could also type the first few chars + of the name then hit TAB if that name is already in the word completion + list...). + ----------------------------------------------------------- + +SECURITY + + When you define an #action that automatically sends something back to + the MUD you are connected to, you must be VERY careful since you may + allow other players to force you to execute commands. + Let's explain better: Suppose you define the following #action: + + #action >+autogroup ^&1 starts following you.={#print;group $1} + + Even though this may look harmless, such an action is potentially + lethal, for the following reason: + If you receive a text from the MUD containing something like + + Cauldron ;remove all;drop all;kill dragon starts following you. + (for example it may be an emote, many MUDs allow it) + + powwow will realize that the line matches with the action you defined + (remember that &n can match text of every length, even if containing + spaces or ; ) and will execute this: + + {#print;group Cauldron ;remove all;drop all;kill dragon} + + The consequences of such a command can be easily imagined... + There are two strategies to avoid such embarassing situations: + 1) Use #send and calculator. In fact this is NOT dangerous: + + #action >+autogroup ^&1 starts following you.= + {#print;#send ("group "+$(1))} + + (in the worst case you will send some semicolon-separated commands + to the MUD, but I saw no MUDs accepting multiple commands as clients + do...): + + 2) Try to use $n instead of &n, so that semicolons and spaces + are skipped. + + #action >+autogroup ^$1 starts following you.= + {#print;group $1} + + WARNING: + versions older than 0.7a were bugged and they did NOT skip + semicolons (but they skipped spaces), so also using $n was + dangerous! + + If you really need to use a &n, check you are not losing security, + and if you cannot write safe code, use calculator as in point 1). + Note that this is NOT dangerous too: + + #action >+autogroup ^&1 starts following you.=group $1 + + since if someone tries to force you as explained above + it will not work, because #action allows only ONE command to follow + the pattern and you did not place braces around "group $1", + so only the first command (in this case "group <name>") + will be executed. + + In every case, remember the best strategy is: check what you are doing, + and do not lose control. If you are not sure a command is safe, better + not to use it. + ----------------------------------------------------------- + +LIMITS + + Powwow has the following limitations: + + Numeric variables are defined as 'long', that means 32-bit integers + on most systems. + + String variables, text lines and commands by default have no length + limits. If you want, you _can_ set a max limit with `#setvar mem'. + Powwow discards text and strings longer than such a limit. + + Exceptions: the labels/patterns of #aliases, #actions, #prompts, + #marks, #in/#at etc. cannot be longer than 4095 chars. + The same limit (4095 chars) applies for the input line. + (the number can be changed by modifying the symbol BUFSIZE) + + Unnamed ('numbered') variables must have indexes from -50 to 9. + (the 50 can be changed modifying the symbol NUMVAR, the 9 cannot + be increased due to hardcoded limits) + + Inline calculator can hold up to 100 suspended operations, due to + parentheses and/or inverted priority of operators. + (the number can be changed by modifying the symbol MAX_STACK) + + The depth of nested/recursive aliases, actions, prompts, #while and + #for commands is limited to 100 nested calls. + (the number can be changed by modifying the symbol MAX_STACK) + + The number of loops of a #while or #for is limited to 10000. + (the number can be changed by modifying the symbol MAX_LOOP) + + Automap can be at most 999 steps. + (the number can be changed by modifying the symbol MAX_MAPLEN) + + History can contain at most 127 lines. + (the number can be changed by modifying the symbol MAX_HIST) + #history commands can execute other #history commands, up to + MAX_HIST levels of recursion. + + Word completion list can contain at most 512 words. + (the number can be changed by modifying the symbol MAX_WORDS) + + Up to 32 MUD (or spawned) connections can be open simultaneously. + (the number can be changed by modifying the symbol MAX_FDSCAN) + + For all other resources, the only limit is the available memory. + ----------------------------------------------------------- + +THE BREAK KEY + + It is usually Control-C or DEL (it depends from the terminal you use). + + Powwow cannot redefine it, but you need to hit it twice in a row + to actually stop powwow. + This is because hitting it only once is used to stop command parsing: + if you enter a long loop using internal commands + (for example: #while (1) drop 1 coin) + you can simply press your break key and powwow will immediatly exit + from the loop with this message: `#interrupted. Press again to quit.' + + If you press the break key again, you will exit powwow. + Otherwise, if you first type something, then you press break key once + more, you will get again: `#interrupted. Press again to quit.' + ----------------------------------------------------------- + +ADVANCED TOPIC: SUBSTITUTIONS AND UNESCAPING + + WARNING: + this is a bit complicated and not recommended for beginners, + as the explanation given at the beginning about $n and \'s might + suffice in many cases. So you might skip this paragraph if you want. + + Still reading? Ok, this is it: + + We described in the beginning that adding \'s to $n delays text + substitution in aliases and actions. Actually, every time powwow + is asked to execute a command, it can make one or more of the + following operations on the command itself before executing it: + + Step (a) : `PARAMETER SUBSTITUTION' or simply `substitution' + + (a1) place in $1..$9 the correct words + + (a2) replace every occurrence of $1..$9 with the contents of the + corresponding variable. Also replace every occurrence of @1..@9 + with the contents of the corresponding variable. + Note that if one or more \ are preceding a $n or @n, + it will be NOT substituted. + + Step (b) : `JUST IN TIME SUBSTITUTION' or `jit' in short + + (b1) replace every occurence of #{expression} with the value of the + expression. Also replace every occurrence of ${name} and @{name} + with the contents of the corresponding variable. Again, + if one or more \ are preceding a #{expr}, ${name} or @{name}, + it will NOT be substituted. This substitution works also + for numbered variables ${number} and @{number}. + + Step (c) : `UNESCAPING' + + (c1) Remove ONE \ from every list of consecutive escapes, + unless they are followed by one or more ` (i.e. reverse-escaped) + For example, \\\$1 is replaced with \\$1 + + (c2) Remove ONE ` from every list of consecutive escapes immediately + followed by a list of consecutive ` + For example, @``` is not modified, + while \\` is replaced with \\ + and \\``` is replaced with \\`` + + The steps actually executed vary from command to command, + but are always ran in order: + if both present, (a) always precedes (b) + if both present, (a) always precedes (c) + if both present, (b) always precedes (c). + + ----------------------------------------------------------- + + When each step is performed/not performed: + + Step (a) (substitution) is performed when executing one of the + following: + aliases, actions, prompts, #for or #while + + Step (b) (jit) is performed when executing _any_ command that allows + a single instruction, and is executed on that instruction before + running it. The list is: + #alias, #action, #prompt, #at, #bind, #connect, #do, #for, #identify, + #if-#else, #in, #init, #nice, #while. + + Also performed on normal (not yet implemented for regexp) patterns + of #actions before matching them. On regexp patterns, step (c) + is made instead. + + Step (c) (unescaping) is performed any time that step (a) + and/or step (b) are performed. + + In addition, unescaping is also performed on text + (not on expressions) following all #commands that allow plain text: + #add, #emulate, #exe, #mark, #print, #put, #send, #var + + on labels of all #commands that allow labels: + #alias, #action, #prompt, #at, #in + + and last, on text that is not a #command nor an alias + before sending it to the MUD, unless the last operation on the + text was _already_ an unescaping. + + Examples: + + #alias fb=cast 'fireball' ${target} + #var $target=troll + fb (effect: cast 'fireball' troll) + #var $target=dragon + fb (effect: cast 'fireball' dragon) + + #action >chase ^${target} leaves $1={#print; #alias f=$1} + (whenever `dragon' leaves the room, + the alias 'f' is set to follow it) + + #action >chase2 ^\${target} leaves $1={#print; #alias f=$1} + (the text `${target}' will be matched + literally) + WARNINGS: + + Step (b) is NOT automatically performed on text typed from the keyboard + so for example `#print ${target}' just prints literally `${target}' + and not the contents of the variable. + If you need step (b) on text you type, you can do something like: + #alias /=$0 + and then prepend all commands with `/ ' : + / #print ${target} + + Step (b) is not yet implemented for regexp actions/prompt due to + internal difficulties. As a workaround, step (c) (unescaping) + is instead performed on regexp patterns. + + Since powwow 1.1.3, unescaping is performed also on the text coming + from substition and jit. This causes subtle incompatibilities with + previous versions in case $n contains any \ or \` . + I tried to avoid this incompatibility, but it is really complicated + to do since I want the text coming from substitution to be subject + to jit as well. So you (and me) will have to live with it :-( + ----------------------------------------------------------- + +ADVANCED TOPIC: SPECIAL COMMAND #PROMPT + + Automatic command execution triggered on prompts + #prompt [[<|=|>|%][+|-]label] [{pattern | (expression)}=[command]] + + WARNING: + this is quite a complicated topic too. You will only need to read this + paragraph if you want to mess with prompts in strange ways, as powwow + usually handles prompts correctly. + + Second warning: + #prompt works only on the main MUD connection. + + O.K, since you are still reading, let's get a bit technical about + powwow internals: + + (WARNING: this changed since powwow 1.1.7:) + + Unless you use #actions, powwow sends immediately to the screen + whatever text it receives from the MUD. It sends to screen both + newline-ended lines (we'll name these `full lines') + and lines not ended with a newline (`incomplete lines'). + Now, there are two problems: + 1) there's no way to know whether an incomplete line is actually + finished or there is a continuation we still have to receive. + 2) powwow cannot know if the line, or an initial part of it, + is a prompt. + + When powwow receives a line (either full or incomplete), + its beginning part may be a prompt, so it matches #prompts on the line. + If the beginning part is _actually_ a prompt, #prompt should + execute #isprompt on it, to let powwow recognize the prompt as such. + + To be exact #isprompt must also specify how long the initial prompt is, + so that powwow can split it from the rest of the line. + For this reason, #isprompt is invoked with a numerical argument: + #isprompt <number> + or + #isprompt (expression) + + a)If the number (or the result of the expression) is positive + and equals to (n), #isprompt declares that the initial prompt + is (n) characters long. + b)If the number is negative and equals to (-n), #isprompt declares + that the initial prompt is the same length as the parameter $n. + c)If the number is 0 (or is missing), #isprompt declares + the whole line as a prompt. + + Also, if a #prompt does not run #isprompt, it is interpreted as + 'this text is not a prompt' + + Putting #isprompt in a #prompt inhibits further attempts to match + that part of the line against both #prompts and #actions + (so should be used only on a complete prompt, not on a part of it) + + NOTE: Since a prompt may be followed by other text, when using + regexp patterns in #prompt it is important not to end the pattern + with $ (which matches the 'end of line') + + Examples: + + On MUME the prompt starts with either `o' or `*' and finishes with `>' + So the regexp pattern ^[o\*].*> will match all prompts and nothing else + To do the same using normal patterns, one should use two patterns + (and two #prompts): ^o&1> and ^*&1> + + On other MUDs of course the possible prompts will vary, so one must + find which pattern (or patterns) will match all the possible prompts. + If it also matches strings that are not prompts, care is required + _not_ to run #isprompt in such cases. + + Let's continue with the MUME example: using regexp patterns, + a correct #prompt is: + + #prompt %default ^[o\\*][^>]*>= + {#isprompt -1; #($prompt = "xyz " + attr "bold" + $prompt + noattr)} + + Note that the pattern contains _two_ backslashes instead of one, + as powwow unescapes regexp patterns. + Also, [^>]*> is used instead of .*> to stop matching at the _first_ `>' + (regexp by default would match the longest text possible, + stopping at the _last_ `>' in the line) + + The #prompt above correctly matches every MUME prompt, + runs #isprompt -1 on it + (which declares that the prompt is as long as $1 + since in regexp patterns $1 is the whole match, it is a good choice) + then modifies the prompt in a custom way + (puts it in bold then appends it to "xyz ") + + Of course #prompts may do whatever one wants, but with a limitation: + they must run #isprompt _before_ modifying the prompt, or unpredictable + things could happen. + + To have the same effect with normal patterns, the following + would be needed: + + #prompt >default1 ^o&1>= + {#isprompt (2+.?$(1)); #($prompt = "xyz " + attr "bold" + $prompt + noattr)} + + #prompt >default2 ^*&1>= + {#isprompt (2+.?$(1)); #($prompt = "xyz " + attr "bold" + $prompt + noattr)} + + The expression after #isprompt meanxs "2 plus the length of $1" + which is obviously the correct length, as $1 does not contain + `o' (or `*') and `>'. + + Final note: + If the prompt is longer than a whole line, it may be drawn incorrectly + and may interfere with the input line (yep, it's a bug). + + MUME players who happen to own a Valar+ character will find this + useful too: + #prompt >default3 ^+&1>={#isprompt (2+.?$(1))} + or, to use regexp patterns: + #prompt %default ^[o\\*\\+][^>]*>={#isprompt -1} + + ----------------------------------------------------------- diff --git a/powwow.help b/powwow.help new file mode 100644 index 0000000..9262057 --- /dev/null +++ b/powwow.help @@ -0,0 +1,553 @@ +@alias +#alias [name[=[command]]] + +Aliases are abbreviations for longer, frequently used commands. +As all powwow commands, they are only recognized at the beginning +of a line or directly after a semicolon, an open or a closed brace. +When an alias is used, the first word following the alias name +is placed in the variable $1, the second in $2, etc... up to $9. +also, the whole string following alias name is placed in $0. + +Then, before executing <command>, every $n in <command> is replaced by its +value. Examples: + +#alias summ=cast 'summon' $0 (then "summ thor" is replaced by + "cast 'summon' thor") +#alias cs=cast '$1' $2 ("cs summon thor" is expanded to + "cast 'summon' thor") +#alias summ (lets you edit the definition of summ) +#alias summ= (removes the alias summ) +#alias (displays all defined aliases) +#alias ws={wake;stand} (note that you must use braces) + +Aliases are saved automatically if you started powwow with a file name as +argument. Aliases are not expanded in verbatim mode. +@action +#action [[<|=|>|%][+|-]label] [{pattern | (expression)}=[command]] + +When 'pattern' is found in a line from the remote host, the 'command' is +automatically executed. If the pattern contains $n, powwow matches one word +of the remote line and puts it in the variable $n. Instead, if pattern contains +&n, powwow places the shortest possible text (can be more than one word, less, +or even one word) in the corresponding $n (NOT in &n). + +As in #alias, before executing <command>, every $n in <command> is replaced +by its value. If the first character of the pattern is ^ (caret), the match +will only be possible at the beginning of a line. +If 'label' is specified, the action is labeled; otherwise it is numbered. +The match is case-sensitive. Examples: + +#action >fount ^There is a fountain here={#print;drink water} +#action -fount (turns off action) +#action +fount (turns it back on) +#action =fount (lets you edit it) +#action <fount (removes action) + +If you use % instead of >, you define an action that uses an Extended POSIX +regexp to match instead of the standard matcher. + +#action %first ^([[:alpha:]]+) ([[:digit:]]+)=#print $2 counted $3. + (matches abc 123) + +Note that if the pattern starts with '(', it is evaluated, which means that +a regexp that starts with '(' has to be surrounded by ("...") + +#action %second ("(..+)-\\1")=#print Double $1 + (matches xyz-xyz) +For regexp actions, $0 = the line, $1 = the whole match and $2... contain the +submatches. +@bind +#bind [edit|key[=[command]]] + +You can bind most function keys and control keys to enter a command for you +when the key is pressed. You cannot (yet) redefine a key already used for an +editing function (such as the arrow keys). 'key' is the name of the key you +want to define; When defining a new key, you will be asked to press it so +powwow can record the control sequence your terminal sends. Examples: + +#bind (lists all key bindings) +#bind f1=recite scroll of recall (you'll have to press f1 then) +#bind f1=cast 'sanctuary' (change exiting definition) +#bind f1 (lets you edit the definition) +#bind f1= (removes the key) +#bind edit (lists editing keys) + +By default, the vt100 numeric keypad is partially used to walk around +@key +#key name + +If 'name' is the name of one of the key defined with #bind, #key executes the +corresponding command. Example: + +#bind f1=flee (binds the f1 key to the 'flee' command) +At any time, then, you can either: +- Press your f1 key on you keyboard +- Execute the command '#key f1' +and powwow will execute the command 'flee' for you. +@reset +#reset {all|list-name} + +Argument: Effect: +all clear everything (apply all lines below this) +alias clear all aliases +action clear all actions +bind clear all key bindings and restart with default + settings. Note that also editing keys are resetted + to default function. +at clear all delayed commands +in (same thing) +mark clear all markers +var clear all variables +@mark +#mark [text[=[attribute]]] + +This command highlights a text in your output in the way you choose +(if your terminal supports it). Attributes: +one or more of bold, blink, inverse, underline and/or +[<foreground>] [on <background>], where the colors are: +black, red, green, yellow, blue, magenta, cyan, white and +BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, none. +Wildcards are allowed ($ for a single word, & for any string). Examples: + +#mark Sizzler=bold (mark Sizzler in bold) +#mark Sizzler (lets you edit the above definition) +#mark Sizzler= (Sizzler is no longer put in bold) +#mark (lists all markers) +#mark *&*=inverse (mark in reverse any string in * *) +@history +#history [number] + +#history alone shows you the last commands in history, up to the number +of lines in your screen. +#history -n shows the last n commands in history, and +#history n executes the n-th command of the history. + +#history commands are not placed in history. +@hilite +#hilite [attribute] + +This sets the attribute of your entered text to the given attribute. +Just #hilite turns it off. + +Attributes: one or more of bold, blink, inverse, underline and/or +[<foreground>] [on <background>], where the colors are: +black, red, green, yellow, blue, magenta, cyan, white and +BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, none. +@host +#host [hostname port] + +Sets the default host that powwow shall try to connect to when you use +#connect. +If you type #host without any arguments, the current host and port are +shown (provided that you have specified them). +@color +#color [attrib] + +(This command exists only if BUG_TELNET is defined, to cope with + deficiencies of NCSA telnet 2.2) +Set your standard foreground and background to the colours you specify. +#color sets default colors +@connect +#connect [session-id [initstr] [address port]] + +Connect a new session. + +To connect your first session, use: +#connect main <address> <port> +where <address> and <port> indicate the host you want to connect to. + +If no address/port is defined, you either get connected to the default +host and port (if you have no open connection) or a list of open +connections is shown. + +Last opened session will be the default one. + +If <initstr> is specified, it is sent to host on connection. +@keys +Default editing keys: + +^A &begin-of-line +^E &end-of-line +^B &prev-char M-b &prev-word +^F &next-char M-f &next-word +^P &prev-line +^N &next-line +^D &del-char-right M-d &del-word-right +BS &del-char-left M-BS &del-word-left +^K &kill-to-eol M-k &redraw-line-noprompt +^L &redraw-line M-l &downcase-word +^T &transpose M-t &transpose-words +^Q &clear-line + M-u &upcase-word +^W &to-history +^Z &suspend +Tab &complete-word M-Tab &complete-line +Ret &enter-line +LF &enter-line + +not assigned: &insert-string + +M-<key> means press escape and then <key>, or press meta/alt key at the same +time as <key>. ^ means control. +If your terminal has arrow keys, they are set for default to move cursor and to +step around history. +@wrap +#wrap [on|off] + +Normally, powwow wraps words that would have been cut by the right +margin to the next line. This command lets you turn it off and on. +@compact +#compact [on|off] + +Normally, powwow does not touch the prompts on screen while you play. +In #compact mode, instead, lines containing only a prompt are deleted when +further messages arrive from the remote host. +@echo +#echo [on|off] + +Normally, powwow echoes on your screen each command sent to remote +host but not directly typed (example: aliases and actions sending text +to the MUD). When #echo is off, such commands are still sent to host, +but not echoed on screen. +@info +#info [on|off] + +Normally, powwow prints on screen some messages each time you +define/edit/delete an #alias, #action, #bind and similar. +When #info is off, those messages are not typed at all. +(But errors are still printed on screen) +@debug +#debug [on|off] + +Normally, powwow does not print on screen the command lines it +executes. When #debug is on, every line executed by powwow is also +echoed on screen (warning: this prints LOTS of lines on your screen) +@delim +#delim [normal|program|{custom <chars>} + +By default, when powwow adds words to the word completion buffer, +it uses only SPACE (' ') and SEMI-COLON (';') as delimeters. You +can change this behaviour by specifying "program" or "custom" mode. +The "program" mode uses ' <>!=(),.;"'{}[]+-/*%=' as separators, which +is suitable if you are doing some kind of on-line programming. +You can also make a customized setting with the "custom" mode (space +is always used as a delimeter). +This setting also affects &transpose-words (usually bound as M-t) +@for +#for ([init];check;[loop]) command + +Directly copied from C language, this command evaluates 'init' +(if specified), then repeats the following cycle: + 1) evaluate 'check', if result is 0 (false) stop repetition + 2) execute 'command' + 3) evaluate 'loop' (if specified) + 4) restart from 1) + +As with #while, #for performs the parameter substitution in 'command'. Example: +#for (@0=32; @0<=47; @0++) read @0 (read messages 32-47) +@at +@in +#at [label [(time-expression) [command]]] +or +#in [label [(delay in millisec.) [command]]] + +If you want to tell powwow to execute the command 'kill wolf' +2 seconds after you type it, use this command: +#in attack (2000) kill wolf + +If you do not specify the command, powwow assumes the label is already +defined, and changes its delay. +A delay less than zero means the delayed label is disabled. +A delay of zero deletes the delayed label. + +If you specify only a label, powwow lists it. +If you specify nothing, all delayed labels are listed. + +The #at command is almost the same as #in, but assumes the expression +in ( ) is a time. +For example (114520) means 11:45:20 and ("114520") is the same. + +After executing a delayed command, powwow does not delete it, but simply +disables it. +@stop +#stop + +Disables all delayed commands (not delete). +Useful if you start an infinite loop with a self-reactivating delayed command +@add +#add {text|(expression)} + +Add the text or result of expression (calculator is used to evaluate the +expression) to the word completion list. Example: + +#action >reply ^$1 tells you={#print;#add $1} + (from now on, you can use TAB to complete that name) +@option +#option [none|[history][words][exit]] + +This command sets a number of options for powwow. + + history write history lines to the savefiles + words write words in completion buffer to the savefile + exit close powwow when the last connection is closes + none go figure (DEFAULT) +@put +#put {text|(expression)} + +If a text is specified, powwow puts it in history. If an expression is +specified, powwow uses the inline calculator to evaluate it, and then puts the +result in history. +@() +@ () +#(expression) or # (expression) + +Evaluate expression with calculator, and trash result. Examples: + +#(@7=45) (set value of variable @7 to 45) +#alias set=#($-1 = \$0) (copy parameter $0 of the alias into $-1) +@print +#print [<|!][string|(expression)] + +If a string is specified, powwow simply prints it on screen. If an expression +is specified, powwow uses the inline calculator to evaluate it, and then +prints the result. + +If a #print without arguments is found, powwow prints the value of the +variable $0 (this is a special feature of #print, and is not present in #send, +#exe, #emulate or #var). + +If < precedes the text or expression, #print assumes text (or result of +expression) to be name of a file, and displays the contents of that file. + +Instead if ! precedes the text or expression, #print assumes text (or result of +expression) to be a Bourne shell command, whose output is displayed. +Examples: + +#action disint ^&1 disintegrates &2=#print $1 DISINTEGRATES $2 +#action disint ^&1 disintegrates &2=#print (\$1+" DISINTEGRATES "+\$2) +#print <mytext (display a text on screen) +#print !more mytext (same thing, but uses 'more' as text viewer) +#print (@-7) (print value of variable on screen) +#print <($2) (display the contents of file whose name is in + variable $2) + +Further feature (supported also by #send, #exe, #emulate and #var): +If < or ! is specified, and you use an expression after it, you can also +specify starting and ending line of the file/command output that you want +to use (the other lines will be ignored), in this way: + +#print {<|!}(string-expr;[start];[end]) +@send +#send [<|!]{text|(string-expr)} + +The simplest use of #send is to evaluate an expression and to send +the result to the MUD. More generally, #send is very similar to #print, +with the only difference that the final text is sent to the MUD rather +than displayed on screen. +The meaning of < and ! is the same, and #send do the expected things +when they are used. Examples: + +#send <mytext (stuff a text into the mud) +#send !awk ' {print "tell arthur " $0} ' file (say a file to your friend) +#send ("say I have been playing for " + %(timer/86400000) + " hours") +@exe +#exe [<|!]{text|(expression)} + +Evaluate the expression and get result, then execute result as if typed from +keyboard. If < or ! is specified, #exe behaves exactly like #print, but +executes the final text as if typed. Examples: + +#exe ("sigh") (is the same as typing sigh from keyboard) +#bind control_s=#exe ("#capture emergency" + %(@-7++)) + (each time you press control_s, a different + file is opened as capture) +#exe <mytext (read the file mytext and execute it) +@emulate +#emulate [<|!]{text|(expression)} + +Evaluate the expression and get result, then parse result as if received from +remote host. If < or ! is specified, #emulate behaves exactly like #print, +but parses the final text as if received from host. Examples: + +#emulate The assassin is dead! R.I.P. (powwow reacts in the same way as + if received the text from remote host) +#emulate <mytext (read the file mytext and parse it as + if received) +@var +#var $number = [<|!]{text|(expression)} +#var @number = [<|!]{text|(expression)} + +Evaluate the expression and get result, then put result in the indicated +variable. If < or ! is specified, #var behaves exactly like #print, but puts +the final text in the variable. +You can also use an expression instead of 'number'. Examples: + +#var @(-1*4) = 27 (same as #(@(-1*4)=27) ) +#var @1=!echo '5.6+6.48' | bc -l (use bc calculator and put result in @1) +#var $test = this is a very very very long text (you do not need quotes) +#var $-6 = ("a short text") (since there are parentheses, you must + also use quotes as in calculator) +#var $-1 = <myfile (if myfile is longer than 1024 bytes, + powwow will read only the first 1024) + +#var variable +will let you edit the current value of the variable + +#var variable= +will delete the variable +@write +#write [>|!](text;name) + +Evaluate expression and get result, then append result to 'name' file. +If > is specified, 'name' file is truncated before actually writing result. + +If ! is specified, 'name' shell command is executed, and result is written +to its standard input. Examples: + +#write ($test; "myfile") (append contents of $test to the end of myfile) +#write !("55+12"; "bc -l") (eval 55+12 using bc program) +@if +#if (expression) command1 [#else command2] + +Evaluate the expression: if result is 'true' execute command1, +otherwise (if there is an #else) execute command2. +If expression is false and there is no #else, execute nothing. +remember that you must use braces {} if command1 or command2 +contain more than one instruction. +@settimer +#settimer (expr) + +Evaluate the expression and get result, then set 'timer' to restart from the +corresponding number of milliseconds. Examples: + +#settimer (0) (reset internal timer to 0) +#settimer (20000) (make internal timer restart from 20000 milliseconds) +@while +#while (expression) command + +This construct repeats a command while expression keeps true. As with #alias, +#action and #for, the $n and @n in command are replaced by their values. +Examples: + +#while (@0<13) {read @0;#(\@0++)} (read messages 0-12) + (As you can see, the last @0 is escaped to avoid it to be + substituted with its value - we want to decrease the variable!) +@math +The inline calculator is used to evaluate expressions inside +#(), #print (), #exe (), #send (), #if (), #while (), #for (), #do (), etc. +and (if you use this syntax) expressions in pattern of #actions + +The inline calculator recognizes the following objects: + +numbers (only integers are supported) + decimal numbers: + simply write them. + + hexadecimal numbers: + use '#' as prefix: #F is 15, #a0 is 160, and so on + + numbers in any other base: + use base# as prefix: 2#101 is 5, 7#14 is 11... + + if you use negative non-decimal numbers, you must put '-' + before the base: -2#101 is -5, 2#-101 causes an error. + +quoted-strings (i.e.: strings in " "). +NOTE: powwow unescapes them when they are evaluated + +timer (number of milliseconds since last timer reset) + +map (string containing the map shown by #map command) + +variables: + @n with n within -50 and 9, are numeric-variables + $n with n within -50 and 9, are string-variables + + Variables with negative index (@-1...@-50 and $-1...$-50) are global, + while variables with positive or zero index are parameters: they are local to + the #alias, #action, #while or #for powwow is executing, and each time + powwow executes one of these commands, a new set of parameters is created. + + @name are numeric-variables + $name are string-variables + + Every character of the name must be either: + a letter (uppercase or lowercase) + an underscore '_' + a number + Exception: the first char of the name must NOT be a number + +operators between numbers: + ++ -- + - + * / % + + - + << >> + < <= > >= == != + & | ^ + && || ^^ + = *= /= %= += -= <<= >>= &= ^= |= &&= ^^= ||= + , + ( ) +(no help on these operators, see a C-language manual) +(note: unlike C, operators && and || always eval both arguments) +(also, % and %= always return non-negative values) + +random number generator: + + rand positive-number (return a random number between 0 and n-1) + +operators between strings: + + chain two strings + = assign a string to a string-variable + += append a string to a string-variable + - compare two strings: result -1 if s1<s2, +1 if s1>s2, + 0 if s1==s2 + < <= > >= == != compare two strings + .? number of chars in a string + :? number of words in a string + ? position of first occurrence of second string in the first + * convert first char of a string into its ASCII code or vice versa + % convert string into its numeric value or vice versa + +operators between a string and a number: + (string is first argument) + : n-th word of a string + . n-th char of a string + :< :> <: >: .< .> <. >. return part of a string, in this way: + : before > or < means 'mark the n-th word from start' + . before > or < means 'mark the n-th char from start' + : after > or < means 'mark the n-th word from end' + . after > or < means 'mark the n-th char from end' + > means: return from marked word/char to end + < means: return from start to marked word/char + +Examples: + +#print($5="Hello, world") (assign "Hello, world" to $5 and print it) + +#action >+exp ^You have scored $1 exp={#print;#print ("You gained " + + %($1 - @-5) + " exp. points since last score"); #(@-5 = $1)} + (when you type 'score' in MUME, one of the lines you get is: + You have scored xxx experience points ... ) +@warranty + 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. @@ -0,0 +1,578 @@ +/* + * data.c -- basic data structures and functions to manipulate them + * + * Copyright (C) 1998 by Massimiliano Ghilardi + * + * 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. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <time.h> +#include <sys/time.h> + +#include "defines.h" +#include "main.h" +#include "utils.h" +#include "eval.h" + +/* + * create a new, empty ptr. + * return NULL if max == 0 + */ +ptr ptrnew __P1 (int,max) +{ + ptr p = (ptr)0; + + if (max == 0) + ; + else if (limit_mem && max > limit_mem) + error = MEM_LIMIT_ERROR; + else if (max < 0 || max + sizeofptr < max) /* overflow! */ + error = NO_MEM_ERROR; + else if ((p = (ptr)malloc(max + sizeofptr))) { + p->max = max; + ptrdata(p)[p->len = 0] = '\0'; + } else + error = NO_MEM_ERROR; + return p; +} + +/* + * create a new ptr giving an initial contents, + * which gets duplicated. + * + * warning: newmax could be so small that we must truncate the copied data! + */ +ptr ptrdup2 __P2 (ptr,src, int,newmax) +{ + ptr p = (ptr)0; + + if (newmax == 0) + ; + else if (newmax < 0 || newmax + sizeofptr < newmax) + error = NO_MEM_ERROR; + else if (limit_mem && newmax > limit_mem) + error = MEM_LIMIT_ERROR; + else if (!src) + p = ptrnew(newmax); + else if ((p = malloc(newmax + sizeofptr))) { + p->max = newmax; + if (newmax > ptrlen(src)) + newmax = ptrlen(src); + memmove(ptrdata(p), ptrdata(src), p->len = newmax); + ptrdata(p)[newmax] = '\0'; + } else + error = NO_MEM_ERROR; + return p; +} + +ptr ptrdup __P1 (ptr,src) +{ + if (!src) + return src; + return ptrdup2(src, ptrlen(src)); +} + +/* delete (free) a ptr */ +void ptrdel __P1 (ptr,p) +{ + if (p) + free((void *)p); +} + +/* clear a ptr */ +void ptrzero __P1 (ptr,p) +{ + if (p) { + p->len = 0; + ptrdata(p)[0] = '\0'; + } +} + +/* truncate a ptr to len chars */ +void ptrtrunc __P2 (ptr,p, int,len) +{ + if (p) { + if (len < 0 || len > ptrlen(p)) + return; + ptrdata(p)[p->len = len] = '\0'; + } +} + +/* shrink a ptr by len chars */ +void ptrshrink __P2 (ptr,p, int,len) +{ + if (p) { + if (len < 0 || len > ptrlen(p)) + return; + ptrdata(p)[p->len -= len] = '\0'; + } +} + +/* + * concatenate two ptr (ptrcat) or a ptr and a char* (ptrmcat) + * result may be a _newly_allocated_ ptr if original one + * is too small or if it is soooo big that we are wasting tons of memory. + * In both cases, the original one may get deleted (freed) + * You have been warned! Don't use any statically created ptr for + * write operations, and you will be fine. + */ +ptr __ptrmcat __P4 (ptr,dst, char *,src, int,len, int,shrink) +{ + int newmax, failmax, overlap; + char mustalloc; + + if (!src || len <= 0) + return dst; + if (len + sizeofptr < 0) { + /* overflow! */ + error = NO_MEM_ERROR; + return dst; + } + + if (!dst) { + failmax = len; + mustalloc = 1; + } else { + failmax = ptrlen(dst) + len; + mustalloc = ptrmax(dst) < ptrlen(dst) + len; + + if (shrink && ptrmax(dst) > PARAMLEN + && ptrmax(dst)/4 > ptrlen(dst) + len) + /* we're wasting space, shrink dst */ + mustalloc = 1; + } + + if (failmax + sizeofptr < 0) { + /* overflow! */ + error = NO_MEM_ERROR; + return dst; + } + + if (mustalloc) { + /* dst must be (re)allocated */ + ptr p; + + /* ugly but working: check for overlapping dst and src */ + if (dst && src >= ptrdata(dst) && src < ptrdata(dst) + ptrmax(dst)) + overlap = 1; + else + overlap = 0; + + /* find a suitable new size */ + if (limit_mem && failmax > limit_mem) { + error = MEM_LIMIT_ERROR; + return dst; + } + if (failmax < PARAMLEN / 2) + newmax = PARAMLEN; + else if (failmax / 1024 < PARAMLEN && failmax + PARAMLEN + sizeofptr > 0) + newmax = failmax + PARAMLEN; + else + newmax = failmax; + if (limit_mem && newmax > limit_mem) { + if (len + (dst ? ptrlen(dst) : 0) > limit_mem) + len = limit_mem - (dst ? ptrlen(dst) : 0); + if (len < 0) + len = 0; + newmax = limit_mem; + } + if ((p = (ptr)realloc((void *)dst, newmax + sizeofptr))) { + if (overlap) + src = ptrdata(p) + (src - ptrdata(dst)); + if (!dst) + p->len = 0; + p->max = newmax; + dst = p; + } else if ((p = ptrdup2(dst, newmax))) { + if (overlap) + src = ptrdata(p) + (src - ptrdata(dst)); + ptrdel(dst); + dst = p; + } else { + error = NO_MEM_ERROR; + return dst; + } + } + if (ptrdata(dst) + ptrlen(dst) != src) + memmove(ptrdata(dst) + ptrlen(dst), src, len); + dst->len += len; + ptrdata(dst)[ptrlen(dst)] = '\0'; + return dst; +} + +ptr ptrmcat __P3 (ptr,dst, char *,src, int,len) +{ + return __ptrmcat(dst, src, len, 1); +} + +ptr ptrcat __P2 (ptr,dst, ptr,src) +{ + if (src) + return __ptrmcat(dst, ptrdata(src), ptrlen(src), 1); + return dst; +} + +/* + * copy a ptr into another (ptrcpy), or a char* into a ptr (ptrmcpy); + * same warning as above if dst is too small or way too big. + */ +ptr __ptrmcpy __P4(ptr,dst, char *,src, int,len, int,shrink) +{ + int newmax, failmax = len, overlap; + char mustalloc; + + if (!src || len<=0) { + if (len>=0) + ptrzero(dst); + return dst; + } + if (failmax + sizeofptr < 0) { + /* overflow! */ + error = NO_MEM_ERROR; + return dst; + } + + if (!dst) { + mustalloc = 1; + } else { + mustalloc = ptrmax(dst) < len; + + if (shrink && ptrmax(dst) > PARAMLEN && ptrmax(dst)/4 > len) + /* we're wasting space, shrink dst */ + mustalloc = 1; + } + + if (mustalloc) { + /* dst must be (re)allocated */ + ptr p; + + /* ugly but working: check for overlapping dst and src */ + if (dst && src >= ptrdata(dst) && src < ptrdata(dst) + ptrmax(dst)) + overlap = 1; + else + overlap = 0; + + /* find a suitable new size */ + if (limit_mem && failmax > limit_mem) { + error = MEM_LIMIT_ERROR; + return dst; + } + if (failmax < PARAMLEN / 2) + newmax = PARAMLEN; + else if (failmax / 1024 < PARAMLEN && failmax + PARAMLEN + sizeofptr > 0) + newmax = failmax + PARAMLEN; + else + newmax = failmax; + if (limit_mem && newmax > limit_mem) { + if (len > limit_mem) + len = limit_mem; + newmax = limit_mem; + } + + if ((p = (ptr)realloc((void *)dst, newmax + sizeofptr))) { + if (overlap) + src = ptrdata(p) + (src - ptrdata(dst)); + if (!dst) + p->len = 0; + p->max = newmax; + dst = p; + } else if ((p = ptrdup2(dst, newmax))) { + if (overlap) + src = ptrdata(p) + (src - ptrdata(dst)); + ptrdel(dst); + dst = p; + } else { + error = NO_MEM_ERROR; + return dst; + } + } + if (ptrdata(dst) != src) + memmove(ptrdata(dst), src, len); + dst->len = len; + ptrdata(dst)[ptrlen(dst)] = '\0'; + return dst; +} + +ptr ptrmcpy __P3 (ptr,dst, char *,src, int,len) +{ + return __ptrmcpy(dst, src, len, 1); +} + +ptr ptrcpy __P2 (ptr,dst, ptr,src) +{ + if (src) + return __ptrmcpy(dst, ptrdata(src), ptrlen(src), 1); + ptrzero(dst); + return dst; +} + +/* enlarge a ptr by len chars. create new if needed */ +ptr ptrpad __P2 (ptr,p, int,len) +{ + if (!p) { + if (len<=0) + return p; + else + return ptrnew(len); + } + if (len > ptrmax(p) - ptrlen(p)) { + /* must realloc the ptr */ + len += ptrlen(p); + if (len < 0) { + /* overflow! */ + error = NO_MEM_ERROR; + return p; + } + /* + * cheat: we use ptrmcpy with src==dst + * and do an out-of-boud read of src. + * works since dst (==src) gets enlarged + * before doing the copy. + */ + p = ptrmcpy(p, ptrdata(p), len); + } else { + p->len += len; + ptrdata(p)[ptrlen(p)] = '\0'; + } + return p; +} + +/* set a ptr to be len chars at minimum. create new if needed */ +ptr ptrsetlen __P2 (ptr,p, int,len) +{ + if (!p) { + if (len<=0) + return p; + else { + if ((p = ptrnew(len))) + ptrdata(p)[p->len = len] = '\0'; + return p; + } + } + return ptrpad(p, len - ptrlen(p)); +} + +/* + * compare two ptr (ptrcmp) or a ptr and a char* (ptrmcmp) + * if one is a truncated copy of the other, the shorter is considered smaller + */ +int ptrmcmp __P3 (ptr,p, char *,q, int,lenq) +{ + int res; + if (!p || !ptrlen(p)) { + if (!q || lenq<=0) + /* both empty */ + res = 0; + else + res = -1; + } else if (!q || lenq<=0) + res = 1; + else if ((res = memcmp(ptrdata(p), q, MIN2(ptrlen(p), lenq)))) + ; + else if (ptrlen(p) < lenq) + res = -1; + else if (ptrlen(p) > lenq) + res = 1; + else + res = 0; + return res; +} + +int ptrcmp __P2 (ptr,p, ptr,q) +{ + if (q) + return ptrmcmp(p, ptrdata(q), ptrlen(q)); + else if (p) + return 1; + else + return 0; +} + +/* + * find first occurrence of c in p + * return NULL if none found. + */ +char *ptrchr __P2 (ptr,p, char,c) +{ + if (p) + return (char *)memchr(ptrdata(p), c, ptrlen(p)); + return (char*)p; /* shortcut for NULL */ +} + +/* + * find last occurrence of c in p + * return NULL if none found. + */ +char *memrchr __P3 (char *,p, int,lenp, char,c) +{ + char *v, *s = p; + + if (!p || lenp<=0) + return NULL; + + v = s + lenp - 1; + while (v != s && *v != c) { + v--; + } + if (v != s) + return v; + else + return NULL; +} + +char *ptrrchr __P2 (ptr,p, char,c) +{ + if (p) + return memrchr(ptrdata(p), ptrlen(p), c); + return (char*)p; /* shortcut for NULL */ +} + +#ifndef _GNU_SOURCE +/* + * find first occurrence of needle in hay + * + * GNU libc has memmem(), for others we do by hand. + */ +char *memfind __P4 (char *,hay, int,haylen, char *,needle, int,needlelen) +{ + char *tmp; + + if (!hay || haylen<=0 || needlelen<0) + return NULL; + if (!needle || !needlelen) + return hay; + + while (haylen >= needlelen) { + /* find a matching first char */ + if ((tmp = memchr(hay, *needle, haylen))) { + if ((haylen -= (tmp-hay)) < needlelen) + return NULL; + hay = tmp; + } else + return NULL; + + /* got a matching first char, + * check the rest */ + if (!memcmp(needle, tmp, needlelen)) + return tmp; + + hay++, haylen --; + } + + return NULL; +} +#endif /* !_GNU_SOURCE */ + +/* + * find first occurrence of q in p, + * return NULL if none found. + */ +char *ptrmfind __P3 (ptr,p, char *,q, int,lenq) +{ + if (p) { + if (q && lenq>0) + return (char *)memfind(ptrdata(p), ptrlen(p), q, lenq); + return ptrdata(p); + } + return (char*)p; /* shortcut for NULL */ +} + +char *ptrfind __P2 (ptr,p, ptr,q) +{ + if (p) { + if (q) + return (char *)memfind(ptrdata(p), ptrlen(p), ptrdata(q), ptrlen(q)); + return ptrdata(p); + } + return (char*)p; /* shortcut for NULL */ +} + + +/* + * Scan p for the first occurrence of one of the characters in q, + * return NULL if none of them is found. + */ +char *memchrs __P4 (char *,p, int,lenp, char *,q, int,lenq) +{ + char *endp; + + if (!q || lenq<=0) + return p; + if (!p || lenp<=0) + return NULL; + + endp = p + lenp; + + while (p < endp && !memchr(q, *p, lenq)) + p++; + + if (p == endp) + return NULL; + return p; +} + +char *ptrmchrs __P3 (ptr,p, char *,q, int,lenq) +{ + if (p) + return memchrs(ptrdata(p), ptrlen(p), q, lenq); + return (char*)p; /* shortcut for NULL */ +} + +char *ptrchrs __P2 (ptr,p, ptr,q) +{ + if (p) { + if (q) + return memchrs(ptrdata(p), ptrlen(p), ptrdata(q), ptrlen(q)); + return ptrdata(p); + } + return (char*)p; /* shortcut for NULL */ +} + + +/* + * Scan p for the last occurrence of one of the characters in q, + * return NULL if none of them is found. + */ +char *memrchrs __P4 (char *,p, int,lenp, char *,q, int,lenq) +{ + if (!p || lenp<=0) { + if (!q || lenq<=0) + return p; + else + return NULL; + } + + p += lenp; + if (!q || lenq<=0) + return p; + do { + lenp--, p--; + } while (lenp >= 0 && !memchr(q, *p, lenq)); + + if (lenp < 0) + return NULL; + return p; +} + +char *ptrmrchrs __P3 (ptr,p, char *,q, int,lenq) +{ + if (p) + return memrchrs(ptrdata(p), ptrlen(p), q, lenq); + return (char*)p; /* shortcut for NULL */ +} + +char *ptrrchrs __P2 (ptr,p, ptr,q) +{ + if (p && q) + return memrchrs(ptrdata(p), ptrlen(p), ptrdata(q), ptrlen(q)); + return p ? ptrdata(p) + ptrlen(p) : (char*)p; /* shortcut for NULL */ +} + @@ -0,0 +1,68 @@ +/* + * ptr.h -- type definitions for ptr (aka `pointer'), a char* replacement + * which allows for '\0' inside a string. + */ + +#ifndef _PTR_H_ +#define _PTR_H_ + +typedef struct s_ptr { + int len; + int max; +} _ptr; + +typedef _ptr * ptr; + +#define sizeofptr ((int)(1 + sizeof(_ptr))) + +/* the + 0 below is to prohibit using the macros for altering the ptr */ +#define ptrlen(p) ((p)->len + 0) +#define ptrmax(p) ((p)->max + 0) +#define ptrdata(p) ((char *)((ptr)(p) + 1)) +/* if p is a valid (ptr), ptrdata(p) is guaranteed to be a valid (char *) */ + +ptr ptrnew __P ((int max)); +ptr ptrdup2 __P ((ptr src, int newmax)); +ptr ptrdup __P ((ptr src)); +void ptrdel __P ((ptr p)); + +void ptrzero __P ((ptr p)); +void ptrshrink __P ((ptr p, int len)); +void ptrtrunc __P ((ptr p, int len)); +ptr ptrpad __P ((ptr p, int len)); +ptr ptrsetlen __P ((ptr p, int len)); + +ptr ptrcpy __P ((ptr dst, ptr src)); +ptr ptrmcpy __P ((ptr dst, char *src, int len)); + +ptr ptrcat __P ((ptr dst, ptr src)); +ptr ptrmcat __P ((ptr dst, char *src, int len)); + + +ptr __ptrcat __P ((ptr dst, char *src, int len, int shrink)); +ptr __ptrmcpy __P ((ptr dst, char *src, int len, int shrink)); + +int ptrcmp __P ((ptr p, ptr q)); +int ptrmcmp __P ((ptr p, char *q, int lenq)); + +char *ptrchr __P ((ptr p, char c)); +char *ptrrchr __P ((ptr p, char c)); + +char *ptrfind __P ((ptr p, ptr q)); +char *ptrmfind __P ((ptr p, char *q, int lenq)); + +char *ptrchrs __P ((ptr p, ptr q)); +char *ptrmchrs __P ((ptr p, char *q, int lenq)); +char *ptrrchrs __P ((ptr p, ptr q)); +char *ptrmrchrs __P ((ptr p, char *q, int lenq)); + +char *memrchr __P ((char *p, int lenp, char c)); +char *memchrs __P ((char *p, int lenp, char *q, int lenq)); +char *memrchrs __P ((char *p, int lenp, char *q, int lenq)); +#ifdef _GNU_SOURCE +# define memfind memmem +#else +char *memfind __P ((char *hay, int haylen, char *needle, int needlelen)); +#endif + +#endif /* _PTR_H_ */ @@ -0,0 +1,1022 @@ +/* + * tcp.c -- telnet protocol communication module for powwow + * + * Copyright (C) 1998,2002 by Massimiliano Ghilardi + * + * 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. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <netdb.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <arpa/telnet.h> +#ifndef TELOPT_NAWS +# define TELOPT_NAWS 31 +#endif +#include <arpa/inet.h> +#ifndef NEXT +# include <unistd.h> +#endif + +#ifdef TERM +# include "client.h" +#endif + +#include "defines.h" +#include "main.h" +#include "utils.h" +#include "tcp.h" +#include "tty.h" +#include "edit.h" +#include "beam.h" +#include "log.h" + +#ifdef TELOPTS +# define TELOPTSTR(n) ((n) > NTELOPTS ? "unknown" : telopts[n]) +#endif + +int tcp_fd = -1; /* current socket file descriptor + * -1 means no socket */ +int tcp_main_fd = -1; /* socket file descriptor of main connect. + * -1 means no socket */ +int tcp_max_fd = 0; /* highest used fd */ + +int tcp_count = 0; /* number of open connections */ +int tcp_attachcount = 0; /* number of spawned commands */ + +int conn_max_index; /* 1 + highest used conn_list[] index */ + +connsess conn_list[MAX_CONNECTS]; /* connection list */ + +byte conn_table[MAX_FDSCAN]; /* fd -> index translation table */ + +fd_set fdset; /* set of descriptors to select() on */ + +/* + * process suboptions. + * so far, only terminal type is processed but future extensions are + * window size, X display location, etc. + */ +static void dosubopt __P1 (byte *,str) +{ + char buf[256], *term; + int len, err; + + if (str[0] == TELOPT_TTYPE) { + if (str[1] == 1) { + /* 1 == SEND */ +#ifdef TELOPTS + tty_printf("[got SB TERMINAL TYPE SEND]\n"); +#endif + if (!(term = getenv("TERM"))) term = "unknown"; + sprintf(buf, "%c%c%c%c%.*s%c%c", IAC, SB, TELOPT_TTYPE, 0, + 256-7, term, IAC, SE); /* 0 == IS */ + + len = strlen(term) + 6; + while ((err = write(tcp_fd, buf, len)) < 0 && errno == EINTR) + ; + if (err != len) { + errmsg("write subopt to socket"); + return; + } +#ifdef TELOPTS + tty_printf("[sent SB TERMINAL TYPE IS %s]\n", term); +#endif + } + } +} + +/* + * send an option negotiation + * 'what' is one of WILL, WONT, DO, DONT + */ +static void sendopt __P2 (byte,what, byte,opt) +{ + static byte buf[3] = { IAC, 0, 0 }; + int i; + buf[1] = what; buf[2] = opt; + + while ((i = write(tcp_fd, buf, 3)) < 0 && errno == EINTR) + ; + if (i != 3) { + errmsg("write option to socket"); + return; + } + +#ifdef TELOPTS + tty_printf("[sent %s %s]\n", (what == WILL) ? "WILL" : + (what == WONT) ? "WONT" : + (what == DO) ? "DO" : (what == DONT) ? "DONT" : "error", + TELOPTSTR(opt)); +#endif +} + +/* + * connect to remote host + * Warning: some voodoo code here + */ +int tcp_connect __P2 (char *,addr, int,port) +{ + struct sockaddr_in address; + struct hostent *host_info; + int err, newtcp_fd; + + status(1); + + memzero((char *)&address, sizeof(address)); + /* + * inet_addr has a strange design: It is documented to return -1 for + * malformed requests, but it is declared to return unsigned long! + * Anyway, this works. + */ + +#ifndef TERM + address.sin_addr.s_addr = inet_addr(addr); + if (address.sin_addr.s_addr != (unsigned int)-1) + address.sin_family = AF_INET; + else + { + if (echo_int) + tty_printf("#looking up %s... ", addr); + tty_flush(); + host_info = gethostbyname(addr); + if (host_info == 0) { + if (!echo_int) { + tty_printf("#looking up %s... ", addr); + } + tty_printf("unknown host!\n"); + return -1; + } + memmove((char *)&address.sin_addr, host_info->h_addr, + host_info->h_length); + address.sin_family = host_info->h_addrtype; + if (echo_int) + tty_puts("found.\n"); + } + address.sin_port = htons(port); + + newtcp_fd = socket(address.sin_family, SOCK_STREAM, 0); + if (newtcp_fd == -1) { + errmsg("create socket"); + return -1; + } else if (newtcp_fd >= MAX_FDSCAN) { + tty_printf("#connect: #error: too many open connections\n"); + close(newtcp_fd); + return -1; + } + + tty_printf("#trying %s... ", addr); + tty_flush(); + + err = connect(newtcp_fd, (struct sockaddr *)&address, sizeof(address)); + + if (err == -1) { /* CTRL-C pressed, or other errors */ + errmsg("connect to host"); + close(newtcp_fd); + return -1; + } + +#else /* term */ + + if ((newtcp_fd = connect_server(0)) < 0) { + tty_puts("\n#powwow: unable to connect to term server\n"); + return -1; + } else { + if (newtcp_fd >= MAX_FDSCAN) { + tty_printf("#connect: #error: too many open connections\n"); + close(newtcp_fd); + return -1; + } + send_command(newtcp_fd, C_PORT, 0, "%s:%d", addr, port); + tty_puts("Connected to term server...\n"); +#ifdef TERM_COMPRESS + send_command(newtcp_fd, C_COMPRESS, 1, "y"); +#endif + send_command(newtcp_fd, C_DUMB, 1, 0); + } + +#endif /* term */ + + tty_puts("connected!\n"); + + + { + /* + * Now set some options on newtcp_fd : + * First, no-nagle + */ + int opt = 1; +# ifndef SOL_TCP +# define SOL_TCP IPPROTO_TCP +# endif + if (setsockopt(newtcp_fd, SOL_TCP, TCP_NODELAY, &opt, sizeof(opt))) + errmsg("setsockopt(TCP_NODELAY) failed"); + + /* + * Then, close-on-exec: + * we don't want children to inherit the socket! + */ + + fcntl(newtcp_fd, F_SETFD, FD_CLOEXEC); + } + + return newtcp_fd; +} + +/* + * we don't expect IAC commands here, except IAC IAC (a protected ASCII 255) + * which we replace with a single IAC (a plain ASCII 255) + */ +int tcp_unIAC __P2 (char *,buffer, int,len) +{ + char *s, *start, warnIACs = 1; + if (!memchr(buffer, IAC, len)) + return len; + + for (s = start = buffer; len > 0; buffer++, len--) { + if (buffer[0] == (char)(byte)IAC) { + if (len > 1 && buffer[1] == (char)(byte)IAC) + buffer++, len--; + else if (warnIACs) { + PRINTF("#warning: received IAC inside MPI message, treating as IAC IAC.\n"); + warnIACs = 0; + } + } + *s++ = *buffer; + } + return s - start; +} + +/* + * the reverse step: protect ASCII 255 as IAC IAC + * the dest buffer is assumed to be big enough to hold the whole data + */ +static int tcp_addIAC __P3 (char *,dest, char *,txt, int,len) +{ + char *s = dest; + while (len-- > 0) { + if ((*s++ = *txt++) == (char)(byte)IAC) + *s++ = (char)(byte)IAC; + } + return s - dest; +} + +/* + * read from an fd, protecting ASCII 255 as IAC IAC while we read. + * the buffer is assumed to be big enough to hold the whole file + */ +int tcp_read_addIAC __P3 (int,fd, char *,data, int,len) +{ + char *s = data; + char buf[BUFSIZE]; + int i; + + while (len > 0) { + while ((i = read(fd, buf, MIN2(len, BUFSIZE))) < 0 && errno == EINTR) + ; + if (i < 0) { + errmsg("read from file"); + return -1; + } else if (i == 0) + break; + s += tcp_addIAC(s, buf, i); + len -= i; + } + return s - data; +} + +/* + * read a maximum of size chars from remote host + * using the telnet protocol. return chars read. + */ +int tcp_read __P3 (int,fd, char *,buffer, int,maxsize) +{ + char state = CONN_LIST(fd).state; + int i; + static byte subopt[MAX_SUBOPT]; + static int subchars; + byte *p, *s, *linestart; + + while ((i = read(fd, buffer, maxsize)) < 0 && errno == EINTR) + ; + + if (i == 0) { + CONN_LIST(fd).state = NORMAL; + tcp_close(NULL); + return 0; + } + if (i < 0) { + errmsg("read from socket"); + return 0; + } + + /* + * scan through the buffer, + * interpret telnet protocol escapes and MUME MPI messages + */ + for (s = p = linestart = (byte *)buffer; i; s++, i--) { + switch (state) { + case NORMAL: + case ALTNORMAL: + case GOT_R: + case GOT_N: + /* + * Some servers like to send NULs and other funny chars. + * Clean up as much as possible. + */ + switch (*s) { + case IAC: + state = GOTIAC; + break; + case '\r': + /* start counting \r, unless just got \n */ + if (state == NORMAL || state == ALTNORMAL) { + /* + * ALTNORMAL is safe here: \r cannot be in MPI header, + * and any previous MPI header has already been rejected + */ + state = GOT_R; + } else if (state == GOT_N) + /* after \n\r, we forbid MPI messages */ + state = ALTNORMAL; + break; + case '\n': + state = GOT_N; + *p++ = *s; + linestart = p; + break; + case '\0': + /* skip NULs */ + break; + default: + /* first, flush any missing \r */ + if (state == GOT_R) + *p++ = '\r'; + + *p++ = *s; + + /* check for MUME MPI messages: */ + if (p - linestart == MPILEN && !memcmp(linestart, MPI, MPILEN)) { + if (!(CONN_LIST(fd).flags & IDEDITOR)) { + PRINTF("#warning: MPI message received without #request editor!\n"); + } else if (state == ALTNORMAL) { + /* no MPI messages after \n\r */ + PRINTF("#warning: MPI attack?\n"); + } else { + subchars = process_message(s+1, i-1); + /* no +MPILEN here, as it was already processed. */ + s += subchars; i-= subchars; + p = linestart; + } + } + + if (state != ALTNORMAL) + state = NORMAL; + break; + } + break; + + case GOTIAC: + switch (*s) { + case WILL: + state = GOTWILL; break; + case WONT: + state = GOTWONT; break; + case DO: + state = GOTDO; break; + case DONT: + state = GOTDONT; break; + case SB: /* BUG (multiple connections): */ + state = GOTSB; /* there is only one subopt buffer */ + subchars = 0; + break; + case IAC: + *p++ = IAC; + state = NORMAL; + break; + case GA: + /* I should handle GA as end-of-prompt marker one day */ + /* one day has come ;) - Max */ + prompt_set_iac(p); + state = NORMAL; + break; + default: + /* ignore the rest of the telnet commands */ +#ifdef TELOPTS + tty_printf("[skipped IAC <%d>]\n", *s); +#endif + state = NORMAL; + break; + } + break; + + case GOTWILL: +#ifdef TELOPTS + tty_printf("[got WILL %s]\n", TELOPTSTR(*s)); +#endif + switch(*s) { + case TELOPT_ECHO: + /* host echoes, turn off echo here + * but only for main connection, since we do not want + * subsidiary connection password entries to block anything + * in the main connection + */ + if (fd == tcp_main_fd) + linemode |= LM_NOECHO; + sendopt(DO, *s); + break; + case TELOPT_SGA: + /* this can't hurt */ + linemode |= LM_CHAR; + tty_special_keys(); + sendopt(DO, *s); + break; + default: + /* don't accept other options */ + sendopt(DONT, *s); + break; + } + state = NORMAL; + break; + + case GOTWONT: +#ifdef TELOPTS + tty_printf("[got WONT %s]\n", TELOPTSTR(*s)); +#endif + if (*s == TELOPT_ECHO) { + /* host no longer echoes, we do it instead */ + linemode &= ~LM_NOECHO; + } + /* accept any WONT */ + sendopt(DONT, *s); + state = NORMAL; + break; + + case GOTDO: +#ifdef TELOPTS + tty_printf("[got DO %s]\n", TELOPTSTR(*s)); +#endif + switch(*s) { + case TELOPT_SGA: + linemode |= LM_CHAR; + tty_special_keys(); + /* FALLTHROUGH */ + case TELOPT_TTYPE: + sendopt(WILL, *s); + break; + case TELOPT_NAWS: + sendopt(WILL, *s); + tcp_write_tty_size(); + break; + default: + /* accept nothing else */ + sendopt(WONT, *s); + break; + } + state = NORMAL; + break; + + case GOTDONT: +#ifdef TELOPTS + tty_printf("[got DONT %s]\n", TELOPTSTR(*s)); +#endif + if (*s == TELOPT_SGA) { + linemode &= ~LM_CHAR; + tty_special_keys(); + } + sendopt(WONT, *s); + state = NORMAL; + break; + + case GOTSB: + if (*s == IAC) { + state = GOTSBIAC; + } else { + if (subchars < MAX_SUBOPT) + subopt[subchars++] = *s; + } + break; + + case GOTSBIAC: + if (*s == IAC) { + if (subchars < MAX_SUBOPT) + subopt[subchars++] = IAC; + state = GOTSB; + } else if (*s == SE) { + subopt[subchars] = '\0'; + dosubopt(subopt); + state = NORMAL; + } else { + /* problem! I haven't the foggiest idea of what to do here. + * I'll just ignore it and hope it goes away. */ + PRINTF("#telnet: got IAC <%d> instead of IAC SE!\n", (int)*s); + state = NORMAL; + } + break; + } + } + CONN_LIST(fd).state = state; + + if (!(CONN_LIST(tcp_fd).flags & SPAWN)) { + log_write(buffer, (char *)p - buffer, 0); + } + + return (char *)p - buffer; +} + +void tcp_raw_write __P3 (int,fd, char *,data, int,len) +{ + int i; + tcp_flush(); + while (len > 0) { + while ((i = write(fd, data, len)) < 0 && errno == EINTR) + ; + if (i < 0) { + errmsg("write to socket"); + break; + } + data += i; + len -= i; + } +} + +/* + * Send current terminal size (RFC 1073) + */ +void tcp_write_tty_size __P0 (void) +{ + static byte buf[] = { IAC, SB, TELOPT_NAWS, 0, 0, 0, 0, IAC, SE }; + + buf[3] = cols >> 8; + buf[4] = cols & 0xff; + buf[5] = lines >> 8; + buf[6] = lines & 0xff; + + tcp_raw_write(tcp_main_fd, (char *)buf, 9); +#ifdef TELOPTS + tty_printf("[sent term size %d %d]\n", cols, lines); +#endif +} + +/* + * send a string to the main connection on the remote host + */ +void tcp_main_write __P1 (char *,data) +{ + tcp_write(tcp_main_fd, data); +} + + +static char output_buffer[BUFSIZE]; +static int output_len = 0; /* number of characters in output_buffer */ +static int output_socket = -1; /* to which socket buffer should be sent*/ + +/* + * put data in the output buffer for transmission to the remote host + */ +void tcp_write __P2 (int,fd, char *,data) +{ + char *iacs, *out; + int len, space, iacp; + len = strlen(data); + + if (tcp_main_fd != -1 && tcp_main_fd == fd) { + if (linemode & LM_NOECHO) + log_write("", 0, 1); /* log a newline only */ + else + log_write(data, len, 1); + reprint_writeline(data); + } + + /* must be AFTER reprint_writeline() */ + if (CONN_LIST(tcp_fd).flags & SPAWN) + status(1); + else + status(-1); + + if (fd != output_socket) { /* is there data to another socket? */ + tcp_flush(); /* then flush it */ + output_socket = fd; + } + + out = output_buffer + output_len; + space = BUFSIZE - output_len; + + while (len) { + iacs = memchr(data, IAC, len); + iacp = iacs ? iacs - data : len; + + if (iacp == 0) { + /* we're at the IAC, send it */ + if (space < 2) { + tcp_flush(); + out = output_buffer; + space = BUFSIZE; + } + *out++ = (char)IAC; *out++ = (char)IAC; output_len += 2; space -= 2; + data++; len--; + continue; + } + + while (space < iacp) { + memcpy(out, data, space); + data += space; len -= space; + iacp -= space; + output_len = BUFSIZE; + + tcp_flush(); + out = output_buffer; + space = BUFSIZE; + } + + if (iacp /* && space >= iacp */ ) { + memcpy(out, data, iacp); + out += iacp; output_len += iacp; space -= iacp; + data += iacp; len -= iacp; + } + } + if (!space) { + tcp_flush(); + out = output_buffer; + } + *out++ = '\n'; + output_len++; +} + +/* + * send all buffered data to the remote host + */ +void tcp_flush __P0 (void) +{ + int n; + char *p = output_buffer; + + if (output_len && output_socket == -1) { + clear_input_line(1); + PRINTF("#no open connections. Use '#connect main <address> <port>' to open a connection.\n"); + output_len = 0; + return; + } + + if (!output_len) + return; + + while (output_len) { + while ((n = write(output_socket, p, output_len)) < 0 && errno == EINTR) + ; + if (n < 0) { + output_len = 0; + errmsg("write to socket"); + return; + } + sent += n; + p += n; + output_len -= n; + } + + if (CONN_LIST(output_socket).flags & SPAWN) + status(1); + else + /* sent stuff, so we expect a prompt */ + status(-1); +} + +/* + * Below are multiple-connection support functions: + */ + +/* + * return connection's fd given id, + * or -1 if null or invalid id is given + */ +int tcp_find __P1 (char *,id) +{ + int i; + + for (i=0; i<conn_max_index; i++) { + if (CONN_INDEX(i).id && !strcmp(CONN_INDEX(i).id, id)) + return CONN_INDEX(i).fd; + } + return -1; +} + +/* + * show list of open connections + */ +void tcp_show __P0 (void) +{ + int i = tcp_count+tcp_attachcount; + + PRINTF("#%s connection%s opened%c\n", i ? "The following" : "No", + i==1 ? " is" : "s are", i ? ':' : '.'); + + + for (i=0; i<conn_max_index; i++) + if (CONN_INDEX(i).id && !(CONN_INDEX(i).flags & SPAWN)) { + tty_printf("MUD %sactive %s ##%s\t (%s %d)\n", + CONN_INDEX(i).flags & ACTIVE ? " " : "non", + i == tcp_main_fd ? "(default)" : " ", + CONN_INDEX(i).id, + CONN_INDEX(i).host, CONN_INDEX(i).port); + } + for (i=0; i<conn_max_index; i++) + if (CONN_INDEX(i).id && (CONN_INDEX(i).flags & SPAWN)) { + tty_printf("CMD %sactive %s ##%s\t (%s)\n", + CONN_INDEX(i).flags & ACTIVE ? " " : "non", + i == tcp_main_fd ? "(default)" : " ", + CONN_INDEX(i).id, CONN_INDEX(i).host); + } +} + +/* + * permanently change main connection + */ +void tcp_set_main __P1 (int,fd) +{ + /* GH: reset linemode and prompt */ + tcp_main_fd = fd; + if (linemode & LM_CHAR) + linemode = 0, tty_special_keys(); + else + linemode = 0; + status(-1); + reprint_clear(); +} + +/* + * open another connection + */ +void tcp_open __P4 (char *,id, char *,initstring, char *,host, int,port) +{ + int newtcp_fd, i; + + if (tcp_count+tcp_attachcount >= MAX_CONNECTS) { + PRINTF("#too many open connections.\n"); + return; + } + if (tcp_find(id)>=0) { + PRINTF("#connection `%s' already open.\n", id); + return; + } + + /* find a free slot */ + for (i=0; i<MAX_CONNECTS; i++) { + if (!CONN_INDEX(i).id) + break; + } + if (i == MAX_CONNECTS) { + PRINTF("#internal error, connection table full :(\n"); + return; + } + + if (!(CONN_INDEX(i).host = my_strdup(host))) { + errmsg("malloc"); + return; + } + if (!(CONN_INDEX(i).id = my_strdup(id))) { + errmsg("malloc"); + free(CONN_INDEX(i).host); + return; + } + + /* dial the number by moving the right index in small circles */ + if ((newtcp_fd = tcp_connect(host, port)) < 0) { + free(CONN_INDEX(i).host); + free(CONN_INDEX(i).id); + CONN_INDEX(i).id = 0; + return; + } + + conn_table[newtcp_fd] = i; + CONN_INDEX(i).flags = ACTIVE; + CONN_INDEX(i).state = NORMAL; + CONN_INDEX(i).port = port; + CONN_INDEX(i).fd = newtcp_fd; + + if (tcp_max_fd < newtcp_fd) + tcp_max_fd = newtcp_fd; + if (conn_max_index <= i) + conn_max_index = i+1; + + FD_SET(newtcp_fd, &fdset); /* add socket to select() set */ + tcp_count++; + + if (echo_int && tcp_count) { + PRINTF("#default connection is now `%s'\n", id); + } + tcp_set_main(tcp_fd = newtcp_fd); + if (opt_sendsize) + tcp_write_tty_size(); + + if (initstring) { + parse_instruction(initstring, 0, 0, 1); + history_done = 0; + } +} + +/* + * close a connection + */ +void tcp_close __P1 (char *,id) +{ + int i, sfd; + + status(1); + tty_puts(edattrend); + /* + * because we may be called from get_remote_input() + * if tcp_read gets an EOF, before edattrend is + * printed by get_remote_input() itself. + */ + + if (id) { /* #zap cmd */ + if ((sfd = tcp_find(id)) < 0) { + tty_printf("#no such connection: `%s'\n", id); + return; + } + } else + sfd = tcp_fd; /* connection closed by remote host */ + + shutdown(sfd, 2); + close(sfd); + + abort_edit_fd(sfd); + + tty_printf("#connection on `%s' closed.\n", CONN_LIST(sfd).id); + + if (sfd == tcp_main_fd) { /* main connection closed */ + if (tcp_count == 1) { /* was last connection */ + if (opt_exit) + exit_powwow(); + tty_puts("#no connections left. Type #quit to quit.\n"); + tcp_fd = tcp_main_fd = -1; + } else { + /* must find another connection and promote it to main */ + for (i=0; i<conn_max_index; i++) { + if (!CONN_INDEX(i).id || CONN_INDEX(i).fd == sfd + || (CONN_INDEX(i).flags & SPAWN)) + continue; + tty_printf("#default connection is now `%s'\n", CONN_INDEX(i).id); + tcp_main_fd = CONN_INDEX(i).fd; + break; + } + if (sfd == tcp_main_fd) { + tty_printf("#PANIC! internal error in tcp_close()\nQuitting.\n"); + syserr(NULL); + } + } + tcp_set_main(tcp_main_fd); + } + + if (tcp_fd == sfd) + tcp_fd = -1; /* no further I/O allowed on sfd, as we just closed it */ + + FD_CLR(sfd, &fdset); + if (CONN_LIST(sfd).flags & SPAWN) + tcp_attachcount--; + else + tcp_count--; + CONN_LIST(sfd).flags = 0; + CONN_LIST(sfd).state = NORMAL; + CONN_LIST(sfd).port = 0; + free(CONN_LIST(sfd).host); CONN_LIST(sfd).host = 0; + free(CONN_LIST(sfd).id); CONN_LIST(sfd).id = 0; + if (CONN_LIST(sfd).fragment) { + free(CONN_LIST(sfd).fragment); + CONN_LIST(sfd).fragment = 0; + } + + /* recalculate conn_max_index */ + i = conn_table[sfd]; + if (i+1 == conn_max_index) { + do { + i--; + } while (i>=0 && !CONN_INDEX(i).id); + conn_max_index = i+1; + } + + /* recalculate tcp_max_fd */ + for (i = tcp_max_fd = 0; i<conn_max_index; i++) { + if (CONN_INDEX(i).id && tcp_max_fd < CONN_INDEX(i).fd) + tcp_max_fd = CONN_INDEX(i).fd; + } +} + +/* + * toggle output display from another connection + */ +void tcp_togglesnoop __P1 (char *,id) +{ + int sfd; + + sfd = tcp_find(id); + if (sfd>=0) { + CONN_LIST(sfd).flags ^= ACTIVE; + if (echo_int) { + PRINTF("#connection %s is now %sactive.\n", + CONN_LIST(sfd).id, CONN_LIST(sfd).flags & ACTIVE ? "" : "non"); + } + } else { + PRINTF("#no such connection: %s\n", id); + } +} + +void tcp_spawn __P2 (char *,id, char *,cmd) +{ + int i, childpid, sockets[2]; + + if (tcp_find(id)>=0) { + PRINTF("#connection `%s' already open.\n", id); + return; + } + if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) < 0) { + errmsg("create socketpair"); + return; + } + unescape(cmd); + + switch (childpid = fork()) { + case 0: + /* child */ + close(0); close(1); close(2); + setsid(); + dup2(sockets[1], 0); + dup2(sockets[1], 1); + dup2(sockets[1], 2); + close(sockets[0]); + close(sockets[1]); + execl("/bin/sh", "sh", "-c", cmd, NULL); + syserr("execl"); + break; + case -1: + close(sockets[0]); + close(sockets[1]); + errmsg("fork"); + return; + } + close(sockets[1]); + + /* Again, we don't want children to inherit sockets */ + fcntl(sockets[0], F_SETFD, FD_CLOEXEC); + + /* now find a free slot */ + for (i=0; i<MAX_CONNECTS; i++) { + if (!CONN_INDEX(i).id) { + conn_table[sockets[0]] = i; + break; + } + } + if (i == MAX_CONNECTS) { + PRINTF("#internal error, connection table full :(\n"); + close(sockets[0]); + return; + } + + if (!(CONN_INDEX(i).host = my_strdup(cmd))) { + errmsg("malloc"); + close(sockets[0]); + return; + } + if (!(CONN_INDEX(i).id = my_strdup(id))) { + errmsg("malloc"); + free(CONN_INDEX(i).host); + close(sockets[0]); + return; + } + CONN_INDEX(i).flags = ACTIVE | SPAWN; + CONN_INDEX(i).state = NORMAL; + CONN_INDEX(i).port = 0; + CONN_INDEX(i).fd = sockets[0]; + + FD_SET(sockets[0], &fdset); /* add socket to select() set */ + tcp_attachcount++; + + if (tcp_max_fd < sockets[0]) + tcp_max_fd = sockets[0]; + if (conn_max_index <= i) + conn_max_index = i+1; + + if (echo_int) { + PRINTF("#successfully spawned `%s' with pid %d\n", id, childpid); + } + + /* + * when the child exits we also get an EOF on the socket, + * so no special care is needed by the SIGCHLD handler. + */ +} + @@ -0,0 +1,78 @@ +/* public things from tcp.c */ + +#ifndef _TCP_H_ +#define _TCP_H_ + +extern int tcp_fd; /* current socket file descriptor */ +extern int tcp_main_fd; /* main session socket */ +extern int tcp_max_fd; /* highest used fd */ + +extern int tcp_count; /* number of open connections */ +extern int tcp_attachcount; /* number of spawned or attached commands */ + +extern int conn_max_index; /* 1 + highest used conn_list[] index */ + + +/* multiple connections control */ + +/* state of telnet connection */ +#define NORMAL 0 +#define ALTNORMAL 1 +#define GOT_N 2 +#define GOT_R 3 +#define GOTIAC 4 +#define GOTWILL 5 +#define GOTWONT 6 +#define GOTDO 7 +#define GOTDONT 8 +#define GOTSB 9 +#define GOTSBIAC 10 + +/* connection flags: */ +/* ACTIVE: display remote output */ +/* SPAWN: spawned cmd, not a mud */ +/* IDEDITOR: sent #request editor */ +/* IDPROMPT: sent #request prompt */ +#define ACTIVE 1 +#define SPAWN 2 +#define IDEDITOR 4 +#define IDPROMPT 8 + +typedef struct { + char *id; /* session id */ + char *host; /* address of remote host */ + int port; /* port number of remote host */ + int fd; /* fd number */ + char *fragment; /* for SPAWN connections: unprocessed text */ + char flags; + char state; +} connsess; + +extern connsess conn_list[MAX_CONNECTS]; /* connection list */ + +extern byte conn_table[MAX_FDSCAN]; /* fd -> index translation table */ + +#define CONN_LIST(n) conn_list[conn_table[n]] +#define CONN_INDEX(n) conn_list[n] + +extern fd_set fdset; /* set of descriptors to select() on */ + +int tcp_connect __P ((char *addr, int port)); +int tcp_read __P ((int fd, char *buffer, int maxsize)); +void tcp_raw_write __P ((int fd, char *data, int len)); +void tcp_write_tty_size __P ((void)); +void tcp_write __P ((int fd, char *data)); +void tcp_main_write __P ((char *data)); +void tcp_flush __P ((void)); +void tcp_set_main __P ((int fd)); +void tcp_open __P ((char *id, char *initstring, char *host, int port)); +int tcp_find __P ((char *id)); +void tcp_show __P ((void)); +void tcp_close __P ((char *id)); +void tcp_togglesnoop __P ((char *id)); +void tcp_spawn __P ((char *id, char *cmd)); +int tcp_unIAC __P ((char *data, int len)); +int tcp_read_addIAC __P ((int fd, char *data, int len)); + +#endif /* _TCP_H_ */ + @@ -0,0 +1,774 @@ +/* + * tty.c -- terminal handling routines for powwow + * + * Copyright (C) 1998 by Massimiliano Ghilardi + * + * 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. + * + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <sys/types.h> +#include <unistd.h> + +#include "defines.h" +#include "main.h" +#include "edit.h" +#include "utils.h" +#include "list.h" +#include "tty.h" +#include "tcp.h" + +#ifndef USE_SGTTY +# ifdef APOLLO +# include "/sys5.3/usr/include/sys/termio.h" +# else +/* + * including both termio.h and termios.h might be an overkill, and gives + * many warnings, but seems to be necessary at times. works anyway. + */ +# include <termios.h> +# include <termio.h> +# endif +/* #else USE_SGTTY */ +#endif + +/* + * SunOS 4 doesn't have function headers and has the defs needed from + * ioctl.h in termios.h. Does it compile with USE_SGTTY? + */ +#if (defined(sun) && defined(sparc) && ! defined(__SVR4)) + extern int printf(); +#else +# include <sys/ioctl.h> +#endif + +#ifdef BSD_LIKE +# include <sys/ioctl_compat.h> +# define O_RAW RAW +# define O_ECHO ECHO +# define O_CBREAK CBREAK +#endif + +#if defined(TCSETS) || defined(TCSETATTR) +# ifndef TCSETS /* cc for HP-UX SHOULD define this... */ +# define TCSETS TCSETATTR +# define TCGETS TCGETATTR +# endif +typedef struct termios termiostruct; +#else +# define TCSETS TCSETA +# define TCGETS TCGETA +typedef struct termio termiostruct; +#endif + +#ifdef VSUSP +# define O_SUSP VSUSP +#else +# ifdef SWTCH +# define O_SUSP SWTCH +# else +# define O_SUSP SUSP +# endif +#endif + +/* int ioctl(); */ + +#ifdef USE_VT100 /* hard-coded vt100 features if no termcap: */ + +static char kpadstart[] = "", kpadend[] = "", begoln[] = "\r", + clreoln[] = "\033[K", clreoscr[] = "\033[J", + leftcur[] = "\033[D", rightcur[] = "\033[C", upcur[] = "\033[A", + modebold[] = "\033[1m", modeblink[] = "\033[5m", modeinv[] = "\033[7m", + modeuline[] = "\033[4m", modestandon[] = "", modestandoff[] = "", + modenorm[] = "\033[m", modenormbackup[4], + cursor_left[] = "\033[D", cursor_right[] = "\033[C", + cursor_up[] = "\033[A", cursor_down[] = "\033[B"; + +#define insertfinish (0) +static int len_begoln = 1, len_leftcur = 3, len_upcur = 3, gotocost = 8; + +#else /* not USE_VT100, termcap function declarations */ + +int tgetent(); +int tgetnum(); +int tgetflag(); +char *tgetstr(); +char *tgoto(); + +/* terminal escape sequences */ +static char kpadstart[CAPLEN], kpadend[CAPLEN], + leftcur[CAPLEN], rightcur[CAPLEN], upcur[CAPLEN], curgoto[CAPLEN], + delchar[CAPLEN], insstart[CAPLEN], insstop[CAPLEN], + inschar[CAPLEN], + begoln[CAPLEN], clreoln[CAPLEN], clreoscr[CAPLEN], + cursor_left[CAPLEN], cursor_right[CAPLEN], cursor_up[CAPLEN], + cursor_down[CAPLEN]; + +/* attribute changers: */ +static char modebold[CAPLEN], modeblink[CAPLEN], modeinv[CAPLEN], + modeuline[CAPLEN], modestandon[CAPLEN], modestandoff[CAPLEN], + modenorm[CAPLEN], modenormbackup[CAPLEN]; + +static int len_begoln, len_clreoln, len_leftcur, len_upcur, gotocost, + deletecost, insertcost, insertfinish, inscharcost; + +static int extract __P ((char *cap, char *buf)); + +#endif /* USE_VT100 */ + + +char *tty_modebold = modebold, *tty_modeblink = modeblink, + *tty_modeinv = modeinv, *tty_modeuline = modeuline, + *tty_modestandon = modestandon, *tty_modestandoff = modestandoff, + *tty_modenorm = modenorm, *tty_modenormbackup = modenormbackup, + *tty_begoln = begoln, *tty_clreoln = clreoln, + *tty_clreoscr = clreoscr; + +int tty_read_fd = 0; +static int wrapglitch = 0; + + +#ifdef USE_SGTTY +static struct sgttyb ttybsave; +static struct tchars tcsave; +static struct ltchars ltcsave; +#else /* not USE_SGTTY */ +static termiostruct ttybsave; +#endif /* USE_SGTTY */ + +/* + * Terminal handling routines: + * These are one big mess of left-justified chicken scratches. + * It should be handled more cleanly...but unix portability is what it is. + */ + +/* + * Set the terminal to character-at-a-time-without-echo mode, and save the + * original state in ttybsave + */ +void tty_start __P0 (void) +{ +#ifdef USE_SGTTY + struct sgttyb ttyb; + struct ltchars ltc; + ioctl(tty_read_fd, TIOCGETP, &ttybsave); + ioctl(tty_read_fd, TIOCGETC, &tcsave); + ioctl(tty_read_fd, TIOCGLTC, <csave); + ttyb = ttybsave; + ttyb.sg_flags = (ttyb.sg_flags|O_CBREAK) & ~O_ECHO; + ioctl(tty_read_fd, TIOCSETP, &ttyb); + ltc = ltcsave; + ltc.t_suspc = -1; + ioctl(tty_read_fd, TIOCSLTC, <c); +#else /* not USE_SGTTY */ + termiostruct ttyb; + ioctl(tty_read_fd, TCGETS, &ttyb); + ttybsave = ttyb; + ttyb.c_lflag &= ~(ECHO|ICANON); + ttyb.c_cc[VTIME] = 0; + ttyb.c_cc[VMIN] = 1; + /* disable the special handling of the suspend key (handle it ourselves) */ + ttyb.c_cc[O_SUSP] = 0; + ioctl(tty_read_fd, TCSETS, &ttyb); +#endif /* USE_SGTTY */ + + tty_puts(kpadstart); + tty_flush(); + +#ifdef DEBUG_TTY + setvbuf(stdout, NULL, _IONBF, BUFSIZ); +#else + setvbuf(stdout, NULL, _IOFBF, BUFSIZ); +#endif +} + +/* + * Reset the terminal to its original state + */ +void tty_quit __P0 (void) +{ +#ifdef USE_SGTTY + ioctl(tty_read_fd, TIOCSETP, &ttybsave); + ioctl(tty_read_fd, TIOCSETC, &tcsave); + ioctl(tty_read_fd, TIOCSLTC, <csave); +#else /* not USE_SGTTY */ + ioctl(tty_read_fd, TCSETS, &ttybsave); +#endif /* USE_SGTTY */ + tty_puts(kpadend); + tty_flush(); +} + +/* + * enable/disable special keys depending on the current linemode + */ +void tty_special_keys __P0 (void) +{ +#ifdef USE_SGTTY + struct tchars tc = {-1, -1, -1, -1, -1, -1}; + struct ltchars ltc = {-1, -1, -1, -1, -1, -1}; + struct sgttyb ttyb; + ioctl(tty_read_fd, TIOCGETP, &ttyb); + if (linemode & LM_CHAR) { + /* char-by-char mode: set RAW mode*/ + ttyb.sg_flags |= RAW; + } else { + /* line-at-a-time mode: enable spec keys, disable RAW */ + tc = tcsave; + ltc = ltcsave; + ltc.t_suspc = -1; /* suspend key remains disabled */ + ttyb.sg_flags &= ~RAW; + } + ioctl(tty_read_fd, TIOCSETP, &ttyb); + ioctl(tty_read_fd, TIOCSETC, &tc); + ioctl(tty_read_fd, TIOCSLTC, <c); +#else /* not USE_SGTTY */ + int i; + termiostruct ttyb; + ioctl(tty_read_fd, TCGETS, &ttyb); + if (linemode & LM_CHAR) { + /* char-by-char mode: disable all special keys and set raw mode */ + for(i = 0; i < NCCS; i++) + ttyb.c_cc[i] = 0; + ttyb.c_oflag &= ~OPOST; + } else { + /* line at a time mode: enable them, except suspend */ + for(i = 0; i < NCCS; i++) + ttyb.c_cc[i] = ttybsave.c_cc[i]; + /* disable the suspend key (handle it ourselves) */ + ttyb.c_cc[O_SUSP] = 0; + /* set cooked mode */ + ttyb.c_oflag |= OPOST; + } + ioctl(tty_read_fd, TCSETS, &ttyb); +#endif /* USE_SGTTY */ +} + +/* + * get window size and react to any window size change + */ +void tty_sig_winch_bottomhalf __P0 (void) +{ + struct winsize wsiz; + /* if ioctl fails or gives silly values, don't change anything */ + + if (ioctl(tty_read_fd, TIOCGWINSZ, &wsiz) == 0 + && wsiz.ws_row > 0 && wsiz.ws_col > 0 + && (lines != wsiz.ws_row || cols != wsiz.ws_col)) + { + lines = wsiz.ws_row; + cols_1 = cols = wsiz.ws_col; + if (!wrapglitch) + cols_1--; + + if (tcp_main_fd != -1) + tcp_write_tty_size(); + line0 += lines - olines; + + tty_gotoxy(0, line0); + /* so we know where the cursor is */ +#ifdef BUG_ANSI + if (edattrbg) + tty_printf("%s%s", edattrend, tty_clreoscr); + else +#endif + tty_puts(tty_clreoscr); + + olines = lines; + status(1); + } +} + +/* + * read termcap definitions + */ +void tty_bootstrap __P0 (void) +{ +#ifndef USE_VT100 + struct tc_init_node { + char cap[4], *buf; + int *len, critic; + }; + static struct tc_init_node tc_init[] = { + { "cm", curgoto, 0, 1 }, + { "ce", clreoln, &len_clreoln, 1 }, + { "cd", clreoscr, 0, 1 }, + { "nd", rightcur, 0, 1 }, + { "le", leftcur, &len_leftcur, 0 }, + { "up", upcur, &len_upcur, 0 }, + { "cr", begoln, &len_begoln, 0 }, + { "ic", inschar, &inscharcost, 0 }, + { "im", insstart, &insertcost, 0 }, + { "ei", insstop, &insertcost, 0 }, + { "dm", delchar, &deletecost, 0 }, + { "dc", delchar, &deletecost, 0 }, + { "ed", delchar, &deletecost, 0 }, + { "me", modenorm, 0, 0 }, + { "md", modebold, 0, 0 }, + { "mb", modeblink, 0, 0 }, + { "mr", modeinv, 0, 0 }, + { "us", modeuline, 0, 0 }, + { "so", modestandon, 0, 0 }, + { "se", modestandoff, 0, 0 }, + { "ks", kpadstart, 0, 0 }, + { "ke", kpadend, 0, 0 }, + { "kl", cursor_left, 0, 0 }, + { "kr", cursor_right, 0, 0 }, + { "ku", cursor_up, 0, 0 }, + { "kd", cursor_down, 0, 0 }, + { "", NULL, 0, 0 } + }; + struct tc_init_node *np; + char tcbuf[2048]; /* by convention, this is enough */ + int i; +#endif /* not USE_VT100 */ +#if !defined(USE_VT100) || defined(BUG_TELNET) + char *term = getenv("TERM"); + if (!term) { + fprintf(stderr, "$TERM not set\n"); + exit(1); + } +#endif /* !defined(USE_VT100) || defined(BUG_TELNET) */ +#ifdef USE_VT100 + cols = 80; +# ifdef LINES + lines = LINES; +# else /* not LINES */ + lines = 24; +# endif /* LINES */ +#else /* not USE_VT100 */ + switch(tgetent(tcbuf, term)) { + case 1: + break; + case 0: + fprintf(stderr, + "There is no entry for `%s' in the terminal data base.\n", term); + fprintf(stderr, + "Please set your $TERM environment variable correctly.\n"); + exit(1); + default: + syserr("tgetent"); + } + for(np = tc_init; np->cap[0]; np++) + if ((i = extract(np->cap, np->buf))) { + if (np->len) *np->len += i; + } else if (np->critic) { + fprintf(stderr, + "Your `%s' terminal is not powerful enough, missing `%s'.\n", + term, np->cap); + exit(1); + } + if (!len_begoln) + strcpy(begoln, "\r"), len_begoln = 1; + if (!len_leftcur) + strcpy(leftcur, "\b"), len_leftcur = 1; + + gotocost = strlen(tgoto(curgoto, cols - 1, lines - 1)); + insertfinish = gotocost + len_clreoln; + + /* this must be before getting window size */ + wrapglitch = tgetflag("xn"); + + tty_sig_winch_bottomhalf(); /* get window size */ + +#endif /* not USE_VT100 */ + strcpy(modenormbackup, modenorm); +#ifdef BUG_TELNET + if (strncmp(term, "vt10", 4) == 0) { + /* might be NCSA Telnet 2.2 for PC, which doesn't reset colours */ + sprintf(modenorm, "\033[;%c%d;%s%dm", + DEFAULTFG<LOWCOLORS ? '3' : '9', DEFAULTFG % LOWCOLORS, + DEFAULTBG<LOWCOLORS ? "4" : "10", DEFAULTBG % LOWCOLORS); + } +#endif /* BUG_TELNET */ +} + +/* + * add the default keypad bindings to the list + */ +void tty_add_walk_binds __P0 (void) +{ + /* + * Note: termcap doesn't have sequences for the numeric keypad, so we just + * assume they are the same as for a vt100. They can be redefined + * at runtime anyway (using #bind or #rebind) + */ + add_keynode("KP2", "\033Or", 0, key_run_command, "s"); + add_keynode("KP3", "\033Os", 0, key_run_command, "d"); + add_keynode("KP4", "\033Ot", 0, key_run_command, "w"); + add_keynode("KP5", "\033Ou", 0, key_run_command, "exits"); + add_keynode("KP6", "\033Ov", 0, key_run_command, "e"); + add_keynode("KP7", "\033Ow", 0, key_run_command, "look"); + add_keynode("KP8", "\033Ox", 0, key_run_command, "n"); + add_keynode("KP9", "\033Oy", 0, key_run_command, "u"); +} + +/* + * initialize the key binding list + */ +void tty_add_initial_binds __P0 (void) +{ + struct b_init_node { + char *label, *seq; + function_any funct; + }; + static struct b_init_node b_init[] = { + { "LF", "\n", enter_line }, + { "Ret", "\r", enter_line }, + { "BS", "\b", del_char_left }, + { "Del", "\177", del_char_left }, + { "Tab", "\t", complete_word }, + { "C-a", "\001", begin_of_line }, + { "C-b", "\002", prev_char }, + { "C-d", "\004", del_char_right }, + { "C-e", "\005", end_of_line }, + { "C-f", "\006", next_char }, + { "C-k", "\013", kill_to_eol }, + { "C-l", "\014", redraw_line }, + { "C-n", "\016", next_line }, + { "C-p", "\020", prev_line }, + { "C-t", "\024", transpose_chars }, + { "C-w", "\027", to_history }, + { "C-z", "\032", suspend_powwow }, + { "M-Tab", "\033\t", complete_line }, + { "M-b", "\033b", prev_word }, + { "M-d", "\033d", del_word_right }, + { "M-f", "\033f", next_word }, + { "M-k", "\033k", redraw_line_noprompt }, + { "M-t", "\033t", transpose_words }, + { "M-u", "\033u", upcase_word }, + { "M-l", "\033l", downcase_word }, + { "M-BS", "\033\b", del_word_left }, + { "M-Del", "\033\177", del_word_left }, + { "", "", 0 } + }; + struct b_init_node *p = b_init; + do { + add_keynode(p->label, p->seq, 0, p->funct, NULL); + } while((++p)->seq[0]); + + if (cursor_left ) add_keynode("Left" , cursor_left , 0, prev_char, NULL); + if (cursor_right) add_keynode("Right", cursor_right, 0, next_char, NULL); + if (cursor_up ) add_keynode("Up" , cursor_up , 0, prev_line, NULL); + if (cursor_down ) add_keynode("Down" , cursor_down , 0, next_line, NULL); +} + +#ifndef USE_VT100 +/* + * extract termcap 'cap' and strcat it to buf. + * return the lenght of the extracted string. + */ +static int extract __P2 (char *,cap, char *,buf) +{ + static char *bp; + char *d = buf + strlen(buf); + char *s = tgetstr(cap, (bp = d, &bp)); + int len; + if (!s) return (*bp = 0); + /* + * Remove the padding information. We assume that no terminals + * need padding nowadays. At least it makes things much easier. + */ + s += strspn(s, "0123456789*"); + for(len = 0; *s; *d++ = *s++, len++) + if (*s == '$' && *(s + 1) == '<') + if (!(s = strchr(s, '>')) || !*++s) break; + *d = 0; + return len; +} +#endif /* not USE_VT100 */ + +/* + * position the cursor using absolute coordinates + * note: does not flush the output buffer + */ +void tty_gotoxy __P2 (int,col, int,line) +{ +#ifdef USE_VT100 + tty_printf("\033[%d;%dH", line + 1, col + 1); +#else + tty_puts(tgoto(curgoto, col, line)); +#endif +} + +/* + * optimized cursor movement + * from (fromcol, fromline) to (tocol, toline) + * if tocol > 0, (tocol, toline) must lie on editline. + */ +void tty_gotoxy_opt __P4 (int,fromcol, int,fromline, int,tocol, int,toline) +{ + static char buf[BUFSIZE]; + char *cp = buf; + int cost, i, dist; + + CLIP(fromline, 0, lines-1); + CLIP(toline , 0, lines-1); + + /* First, move vertically to the correct line, then horizontally + * to the right column. If this turns out to be fewer characters + * than a direct cursor positioning (tty_gotoxy), use that. + */ + for (;;) { /* gotoless */ + if ((i = toline - fromline) < 0) { + if (!len_upcur || (cost = -i * len_upcur) >= gotocost) + break; + do { + strcpy(cp, upcur); + cp += len_upcur; + } while(++i); + } else if ((cost = 2 * i)) { /* lf is mapped to crlf on output */ + if (cost >= gotocost) + break; + do + *cp++ = '\n'; + while (--i); + fromcol = 0; + } + if ((i = tocol - fromcol) < 0) { + dist = -i * len_leftcur; + if (dist <= len_begoln + tocol) { + if ((cost += dist) > gotocost) + break; + do { + strcpy(cp, leftcur); + cp += len_leftcur; + } while(++i); + } else { + if ((cost += len_begoln) > gotocost) + break; + strcpy(cp, begoln); + cp += len_begoln; + fromcol = 0; i = tocol; + } + } + if (i) { + /* + * if hiliting in effect or prompt contains escape sequences, + * just use tty_gotoxy + */ + if (cost + i > gotocost || *edattrbeg || promptlen != col0) + break; + if (fromcol < col0 && toline == line0) { + strcpy(cp, promptstr+fromcol); + cp += promptlen-fromcol; + fromcol = col0; + } + my_strncpy(cp, edbuf + (toline - line0) * cols_1 + fromcol - col0, + tocol - fromcol); + cp += tocol - fromcol; + } + *cp = 0; + tty_puts(buf); + return; + } + tty_gotoxy(tocol, toline); +} + + +/* + * GH: change the position on input line (gotoxy there, and set pos) + * from cancan 2.6.3a + */ +void input_moveto __P1 (int,new_pos) +{ + /* + * FEATURE: the line we are moving to might be less than 0, or greater + * than lines - 1, if the display is too small to hold the whole editline. + * In that case, the input line should be (partially) redrawn. + */ + if (new_pos < 0) + new_pos = 0; + else if (new_pos > edlen) + new_pos = edlen; + if (new_pos == pos) + return; + + if (line_status == 0) { + int fromline = CURLINE(pos), toline = CURLINE(new_pos); + if (toline < 0) + line0 -= toline, toline = 0; + else if (toline > lines - 1) + line0 -= toline - lines + 1, toline = lines - 1; + tty_gotoxy_opt(CURCOL(pos), fromline, CURCOL(new_pos), toline); + } + pos = new_pos; +} + +/* + * delete n characters at current position (the position is unchanged) + * assert(n < edlen - pos) + */ +void input_delete_nofollow_chars __P1 (int,n) +{ + int r_cost, p = pos, d_cost; + int nl = pos - CURCOL(pos); /* this line's starting pos (can be <= 0) */ + int cl = CURLINE(pos); /* current line */ + + if (n > edlen - p) + n = edlen - p; + if (n <= 0) + return; + + d_cost = p + n; + if (line_status != 0) { + memmove(edbuf + p, edbuf + d_cost, edlen - d_cost + 1); + edlen -= n; + return; + } + + memmove(edbuf + p, edbuf + d_cost, edlen - d_cost); + memset(edbuf + edlen - n, (int)' ', n); + for (;; tty_putc('\n'), p = nl, cl++) { + d_cost = 0; + /* FEATURE: ought to be "d_cost = n > gotocost ? -gotocost : -n;" + * since redraw will need to goto back. Of little importance */ + if ((r_cost = edlen) > (nl += cols_1)) + r_cost = nl, d_cost = n + gotocost; + r_cost -= p; +#ifndef USE_VT100 + /* + * FEATURE: no clreoln is used (it might cost less in the occasion + * we delete more than one char). Simplicity + */ + if (deletecost && deletecost * n + d_cost < r_cost) { +#ifdef BUG_ANSI + if (edattrbg) + tty_puts(edattrend); +#endif + for (d_cost = n; d_cost; d_cost--) + tty_puts(delchar); +#ifdef BUG_ANSI + if (edattrbg) + tty_puts(edattrbeg); +#endif + + if (edlen <= nl) + break; + + tty_gotoxy(cols_1 - n, cl); + tty_printf("%.*s", n, edbuf + nl - n); + } else +#endif /* not USE_VT100 */ + { +#ifdef BUG_ANSI + if (edattrbg && p <= edlen - n && p + r_cost >= edlen - n) + tty_printf("%.*s%s%.*s", edlen - p - n, edbuf + p, + edattrend, + r_cost - edlen + p + n, edbuf + edlen - n); + else +#endif + tty_printf("%.*s", r_cost, edbuf + p); + + p += r_cost; + + if (edlen <= nl) { +#ifdef BUG_ANSI + if (edattrbg) + tty_puts(edattrbeg); +#endif + break; + } + } + } + edbuf[edlen -= n] = '\0'; + switch(pos - p) { + case 1: + tty_puts(leftcur); + break; + case 0: + break; + default: + tty_gotoxy_opt(CURCOL(p), cl, CURCOL(pos), CURLINE(pos)); + break; + } +} + +/* + * GH: print a char on current position (overwrite), advance position + * from cancan 2.6.3a + */ +void input_overtype_follow __P1 (char,c) +{ + if (pos >= edlen) + return; + edbuf[pos++] = c; + + if (line_status == 0) { + tty_putc(c); + if (!CURCOL(pos)) { +#ifdef BUG_ANSI + if (edattrbg) + tty_printf("%s\n%s", edattrend, edattrbeg); + else +#endif + tty_putc('\n'); + } + } +} + +/* + * insert n characters at input line current position. + * The position is set to after the inserted characters. + */ +void input_insert_follow_chars __P2 (char *,str, int,n) +{ + int r_cost, i_cost, p = pos; + int nl = p - CURCOL(p); /* next line's starting pos */ + int cl = CURLINE(p); /* current line */ + + if (edlen + n >= BUFSIZE) + n = BUFSIZE - edlen - 1; + if (n <= 0) + return; + + memmove(edbuf + p + n, edbuf + p, edlen + 1 - p); + memmove(edbuf + p, str, n); + edlen += n; pos += n; + + if (line_status != 0) + return; + + do { + i_cost = n; + if ((r_cost = edlen) > (nl += cols_1)) + r_cost = nl, i_cost += insertfinish; + r_cost -= p; +#ifndef USE_VT100 + /* FEATURE: insert mode is used only when one char is inserted + (which is probably true > 95% of the time). Simplicity */ + if (n == 1 && inscharcost && inscharcost + i_cost < r_cost) { + tty_printf("%s%c", inschar, edbuf[p++]); + if (edlen > nl && !wrapglitch) { + tty_gotoxy(cols_1, cl); + tty_puts(clreoln); + } + } else +#endif /* not USE_VT100 */ + { + tty_printf("%.*s", r_cost, edbuf + p); p += r_cost; + } + if (edlen < nl) + break; +#ifdef BUG_ANSI + if (edattrbg) + tty_printf("%s\n%s", edattrend, edattrbeg); + else +#endif + tty_puts("\n"); + p = nl; + if (++cl > lines - 1) { + cl = lines - 1; + line0--; + } + } while (edlen > nl); + + if (p != pos) + tty_gotoxy_opt(CURCOL(p), cl, CURCOL(pos), CURLINE(pos)); +} + @@ -0,0 +1,52 @@ +/* public definitions from tty.c */ + +#ifndef _TTY_H_ +#define _TTY_H_ + +extern int tty_read_fd; + +extern char *tty_clreoln, *tty_clreoscr, *tty_begoln, + *tty_modebold, *tty_modeblink, *tty_modeuline, + *tty_modenorm, *tty_modenormbackup, + *tty_modeinv, *tty_modestandon, *tty_modestandoff; + +void tty_bootstrap __P ((void)); +void tty_start __P ((void)); +void tty_quit __P ((void)); +void tty_special_keys __P ((void)); +void tty_sig_winch_bottomhalf __P ((void)); +void tty_add_walk_binds __P ((void)); +void tty_add_initial_binds __P ((void)); +void tty_gotoxy __P ((int col, int line)); +void tty_gotoxy_opt __P ((int fromcol, int fromline, int tocol, int toline)); + +void input_delete_nofollow_chars __P ((int n)); +void input_overtype_follow __P ((char c)); +void input_insert_follow_chars __P ((char *str, int n)); +void input_moveto __P ((int new_pos)); + +#if 1 + +#define tty_puts(s) fputs((s), stdout) +/* printf("%s", (s)); would be as good */ + +#define tty_putc(c) putc((int)(char)(c), stdout) +#define tty_printf printf +#define tty_read read +#define tty_gets(s,size) fgets((s), (size), stdin) +#define tty_flush() fflush(stdout) +#define tty_raw_write(s,size) do { tty_flush(); write(1, (s), (size)); } while (0) + +#else /* !1 */ + +void tty_puts __P ((char *s)); +void tty_putc __P ((char c)); +void tty_printf __P ((const char *format, ...)); +int tty_read __P ((int fd, char *buf, size_t count)); +void tty_gets __P ((char *s, int size)); +void tty_flush __P ((void)); +void tty_raw_write __P ((char *data, int len)); + +#endif /* 1 */ + +#endif /* _TTY_H_ */ @@ -0,0 +1,1279 @@ +/* + * utils.c -- miscellaneous utility functions + * + * Copyright (C) 1998,2002 by Massimiliano Ghilardi + * + * 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. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include <unistd.h> +#include <signal.h> +#include <time.h> + +#include "defines.h" +#include "main.h" +#include "utils.h" +#include "list.h" +#include "cmd.h" +#include "cmd2.h" +#include "beam.h" +#include "tty.h" +#include "edit.h" +#include "eval.h" +#include "log.h" + +#define SAVEFILEVER 6 + +static char can_suspend = 0; /* 1 if shell has job control */ + +/* + * GH: memory-"safe" strdup + */ +char *my_strdup __P1 (char *,s) +{ + if (s) { + s = strdup(s); + if (!s) + error = NO_MEM_ERROR; + } + return s; +} + +/* + * non-braindamaged strncpy: + * copy up to len chars from src to dst, then add a final \0 + * (i.e. dst[len] = '\0') + */ +char *my_strncpy __P3 (char *,dst, char *,src, int,len) +{ + int slen = strlen(src); + if (slen < len) + return strcpy(dst, src); + memcpy(dst, src, len); + dst[len] = '\0'; + return dst; +} + +/* + * Determine the printed length of a string. This can be less than the string + * length since it might contain escape sequences. Treated as such are + * "<esc> [ <non-letters> <letter>", "<esc> <non-[>", "<control-char>". + * This is not entirely universal but covers the most common cases (i.e. ansi) + */ +int printstrlen __P1 (char *,s) +{ + int l; + enum { NORM, ESCAPE, BRACKET } state = NORM; + for (l = 0; *s; s++) { + switch(state) { + case NORM: + if (*s == '\033') { + state = ESCAPE; + } else if ((*s & 0x80) || *s >= ' ') { + l++; + } else if (*s == '\r') + l = (l / cols) * cols; + break; + + case ESCAPE: + state = (*s == '[') ? BRACKET : NORM; + break; + + case BRACKET: + if (isalpha(*s)) + state = NORM; + break; + } + } + return l; +} + +/* + * return pointer to next non-blank char + */ +char *skipspace __P1 (char *,p) +{ + while (*p == ' ' || *p == '\t') p++; + return p; +} + +/* + * find the first valid (non-escaped) + * char in a string + */ +char *first_valid __P2 (char *,p, char,ch) +{ + if (*p && *p != ch) { + p++; + if (ch == ESC2 || ch == ESC) while (*p && *p != ch) + p++; + else while (*p && ((*p != ch) || p[-1] == ESC)) + p++; + } + return p; +} + +/* + * find the first regular (non-escaped, non in "" () or {} ) + * char in a string + */ +char *first_regular __P2 (char *,p, char,c) +{ + int escaped, quotes=0, paren=0, braces=0; + + while (*p && ((*p != c) || quotes || paren>0 || braces>0)) { + escaped = 0; + if (*p == ESC) { + while (*p == ESC) + p++; + escaped = 1; + } + if (*p == ESC2) { + while (*p == ESC2) + p++; + escaped = 0; + } + if (!*p) + break; + if (!escaped) { + if (quotes) { + if (*p == '\"') + quotes = 0; + } + else if (*p == '\"') + quotes = 1; + else if (*p == ')') + paren--; + else if (*p == '(') + paren++; + else if (*p == '}') + braces--; + else if (*p == '{') + braces++; + } + p++; + } + return p; +} + +/* + * remove escapes (backslashes) from a string + */ +int memunescape __P2 (char *,p, int,lenp) +{ + char *start, *s; + enum { NORM, ESCSINGLE, ESCAPE } state = NORM; + + if (!p || !*p) + return 0; + + start = s = p; + + while (lenp) switch (state) { + case NORM: + if (*s != ESC) { + *p++ = *s++, lenp--; + break; + } + state = ESCSINGLE, s++; + if (!--lenp) + break; + /* fallthrough */ + case ESCSINGLE: + case ESCAPE: + if (*s == ESC) + state = ESCAPE, *p++ = *s++, lenp--; + else if (*s == ESC2) + state = NORM, *p++ = ESC, s++, lenp--; + else { + if (state == ESCSINGLE && lenp >= 3 && + ISODIGIT(s[0]) && ISODIGIT(s[1]) && ISODIGIT(s[2])) { + + *p++ = ((s[0]-'0') << 6) | ((s[1]-'0') << 3) | (s[2]-'0'); + s += 3, lenp -= 3; + } else + *p++ = *s++, lenp--; + state = NORM; + } + break; + default: + break; + } + *p = '\0'; + return (int)(p - start); +} + +void unescape __P1 (char *,s) +{ + (void)memunescape(s, strlen(s)); +} + +void ptrunescape __P1 (ptr,p) +{ + if (!p) + return; + p->len = memunescape(ptrdata(p), ptrlen(p)); +} + +/* + * add escapes (backslashes) to src + */ +ptr ptrmescape __P4 (ptr,dst, char *,src, int,srclen, int,append) +{ + int len; + char *p; + enum { NORM, ESCAPE } state; + + if (!src || srclen <= 0) { + if (!append) + ptrzero(dst); + return dst; + } + + if (dst && append) + len = ptrlen(dst); + else + len = 0; + + dst = ptrsetlen(dst, len + srclen*4); /* worst case */ + if (MEM_ERROR) return dst; + + dst->len = len; + p = ptrdata(dst) + len; + + while (srclen) { + state = NORM; + if (*src == ESC) { + while (srclen && *src == ESC) + dst->len++, *p++ = *src++, srclen--; + + if (!srclen || *src == ESC2) + dst->len++, *p++ = ESC2; + else + state = ESCAPE; + } + if (!srclen) break; + + if (*src < ' ' || *src > '~') { + sprintf(p, "\\%03o", (int)(byte)*src++); + len = strlen(p); + dst->len += len, p += len, srclen--; + } else { + if (state == ESCAPE || strchr(SPECIAL_CHARS, *src)) + dst->len++, *p++ = ESC; + + dst->len++, *p++ = *src++, srclen--; + } + } + *p = '\0'; + return dst; +} + +ptr ptrescape __P3 (ptr,dst, ptr,src, int,append) +{ + if (!src) { + if (!append) + ptrzero(dst); + return dst; + } + return ptrmescape(dst, ptrdata(src), ptrlen(src), append); +} + +/* + * add escapes to protect special characters from being escaped. + */ +void escape_specials __P2 (char *,dst, char *,src) +{ + enum { NORM, ESCAPE } state; + while (*src) { + state = NORM; + if (*src == ESC) { + while (*src == ESC) + *dst++ = *src++; + + if (!*src || *src == ESC2) + *dst++ = ESC2; + else + state = ESCAPE; + } + if (!*src) break; + + if (*src < ' ' || *src > '~') { + sprintf(dst, "\\%03o", (int)(byte)*src++); + dst += strlen(dst); + } else { + if (state == ESCAPE || strchr(SPECIAL_CHARS, *src)) + *dst++ = ESC; + + *dst++ = *src++; + } + } + *dst = '\0'; +} + +/* + * match mark containing & and $ and return 1 if matched, 0 if not + * if 1, start and end contain the match bounds + * if 0, start and end are undefined on return + */ +static int match_mark __P2 (marknode *,mp, char *,src) +{ + char *pat = mp->pattern; + char *npat=0, *npat2=0, *nsrc=0, *prm=0, *endprm=0, *tmp, c; + static char mpat[BUFSIZE]; + int mbeg = mp->mbeg, mword = 0, p; + + /* shortcut for #marks without wildcards */ + if (!mp->wild) { + if ((nsrc = strstr(src, pat))) { + mp->start = nsrc; + mp->end = nsrc + strlen(pat); + return 1; + } + return 0; + } + + mp->start = NULL; + + if (ISMARKWILDCARD(*pat)) + mbeg = - mbeg - 1; /* pattern starts with '&' or '$' */ + + while (pat && (c = *pat)) { + if (ISMARKWILDCARD(c)) { + /* & matches a string */ + /* $ matches a single word */ + prm = src; + if (c == '$') + mword = 1; + else if (!mp->start) + mp->start = src; + ++pat; + } + + npat = first_valid(pat, '&'); + npat2 = first_valid(pat, '$'); + if (npat2 < npat) npat = npat2; + if (!*npat) npat = 0; + + if (npat) { + my_strncpy(mpat, pat, npat-pat); + /* mpat[npat - pat] = 0; */ + } else + strcpy(mpat, pat); + + if (*mpat) { + nsrc = strstr(src, mpat); + if (!nsrc) + return 0; + if (mbeg > 0) { + if (nsrc != src) + return 0; + mbeg = 0; /* reset mbeg to stop further start match */ + } + endprm = nsrc; + if (!mp->start) { + if (prm) + mp->start = src; + else + mp->start = nsrc; + } + mp->end = nsrc + strlen(mpat); + } else if (prm) /* end of pattern space */ + mp->end = endprm = prm + strlen(prm); + else + mp->end = src; + + + /* post-processing of param */ + if (mword) { + if (prm) { + if (mbeg == -1) { + if (!*pat) { + /* the pattern is "$", take first word */ + p = - 1; + } else { + /* unanchored '$' start, take last word */ + tmp = memrchrs(prm, endprm - prm - 1, DELIM, DELIM_LEN); + if (tmp) + p = tmp - prm; + else + p = -1; + } + mp->start = prm += p + 1; + } else if (!*pat) { + /* '$' at end of pattern, take first word */ + if ((tmp = memchrs(prm, strlen(prm), DELIM, DELIM_LEN))) + mp->end = endprm = tmp; + } else { + /* match only if param is single-worded */ + if (memchrs(prm, endprm - prm, DELIM, DELIM_LEN)) + return 0; + } + } else + return 0; + } + if (prm) + mbeg = mword = 0; /* reset match flags */ + src = nsrc + strlen(mpat); + pat = npat; + } + return 1; +} + +/* + * add marks to line. write in dst. + */ +ptr ptrmaddmarks __P3 (ptr,dst, char *,line, int,len) +{ + marknode *mp, *mfirst; + char begin[CAPLEN], end[CAPLEN], *lineend = line + len; + int start = 1, matchlen, matched = 0; + + ptrzero(dst); + + if (!line || len <= 0) + return dst; + + for (mp = markers; mp; mp = mp->next) + mp->start = NULL; + + do { + mfirst = NULL; + for (mp = markers; mp; mp = mp->next) { + if (mp->start && mp->start >= line) + matched = 1; + else { + if (!(matched = (!mp->mbeg || start) && match_mark(mp, line))) + mp->start = lineend; + } + if (matched && mp->start < lineend && + (!mfirst || mp->start < mfirst->start)) + mfirst = mp; + } + + if (mfirst) { + start = 0; + attr_string(mfirst->attrcode, begin, end); + + dst = ptrmcat(dst, line, matchlen = mfirst->start - line); + if (MEM_ERROR) break; + line += matchlen; + len -= matchlen; + + dst = ptrmcat(dst, begin, strlen(begin)); + if (MEM_ERROR) break; + + dst = ptrmcat(dst, line, matchlen = mfirst->end - mfirst->start); + if (MEM_ERROR) break; + line += matchlen; + len -= matchlen; + + dst = ptrmcat(dst, end, strlen(end)); + if (MEM_ERROR) break; + } + } while (mfirst); + + if (!MEM_ERROR) + dst = ptrmcat(dst, line, len); + + return dst; +} + +ptr ptraddmarks __P2 (ptr,dst, ptr,line) +{ + if (line) + return ptrmaddmarks(dst, ptrdata(line), ptrlen(line)); + ptrzero(dst); + return dst; +} + +/* + * write string to tty, wrapping to next line if needed. + * don't print a final \n + */ +static void wrap_print __P1 (char *,s) +{ + char *p, c, follow = 1; + char buf[BUFSIZE]; /* ASSERT(cols<BUFSIZE) */ + int l, m; + enum { NORM, ESCAPE, BRACKET } state; +#ifdef BUG_ANSI + int ansibug = 0; +#endif + + l = printstrlen(s); +#ifdef BUG_ANSI + if (l > cols_1 && l < (int)strlen(s)) + ansibug = 1; +#endif + + while (l >= cols_1 - col0) { + p = buf; m = 0; state = NORM; + + while (m < cols_1 - col0 && *s && *s != '\n') { + *p++ = c = *s++; + switch (state) { + case NORM: + if (c == '\033') + state = ESCAPE; + else if ((c & 0x80) || (c >= ' ' && c <= '~')) + m++, l--; + else if (c == '\r') + m = 0; + break; + case ESCAPE: + state = (c == '[') ? BRACKET : NORM; + break; + case BRACKET: + if (isalpha(c)) + state = NORM; + break; + } + } + + follow = *s; + + *p = '\0'; + tty_printf("%s%s", buf, follow ? "\n" : ""); + if (follow) + col0 = 0; + } +#ifdef BUG_ANSI + if (ansibug) + tty_printf("%s%s%s", follow ? s : "" , + tty_modenorm, tty_clreoln); + else +#endif + if (follow) + tty_puts(s); +} + +/* + * add marks to line and print. + * if newline, also print a final \n + */ +void smart_print __P2 (char *,line, char,newline) +{ + static ptr ptrbuf = NULL; + static char *buf; + + do { + if (!ptrbuf) { + ptrbuf = ptrnew(PARAMLEN); + if (MEM_ERROR) break; + } + ptrbuf = ptrmaddmarks(ptrbuf, line, strlen(line)); + if (MEM_ERROR || !ptrbuf) break; + + buf = ptrdata(ptrbuf); + + if (opt_wrap) + wrap_print(buf); + else { +#ifdef BUG_ANSI + int l; + l = printstrlen(buf); + if (l > cols_1 && l < ptrlen(ptrbuf)) + tty_printf("%s%s%s", buf, tty_modenorm, tty_clreoln); + else +#endif + tty_printf("%s", buf); + } + } while(0); + + if (MEM_ERROR) + print_error(error); + else if (newline) + col0 = 0, tty_putc('\n'); +} + +/* + * copy first word of src into dst, and return pointer to second word of src + */ +char *split_first_word __P3 (char *,dst, int,dstlen, char *,src) +{ + char *tmp; + int len; + + src = skipspace(src); + if (!*src) { + *dst='\0'; + return src; + } + len = strlen(src); + + tmp = memchrs(src, len, DELIM, DELIM_LEN); + if (tmp) { + if (dstlen > tmp-src+1) dstlen = tmp-src+1; + my_strncpy(dst, src, dstlen-1); + } else { + my_strncpy(dst, src, dstlen-1); + tmp = src + len; + } + if (*tmp && *tmp != CMDSEP) tmp++; + return tmp; +} + +static void sig_pipe_handler __P1 (int,signum) +{ + tty_puts("\n#broken pipe.\n"); +} + +static void sig_winch_handler __P1 (int,signum) +{ + sig_pending = sig_winch_got = 1; +} + +static void sig_chld_handler __P1 (int,signum) +{ + sig_pending = sig_chld_got = 1; +} + +static void sig_term_handler __P1 (int,signum) +{ + tty_printf("%s\n#termination signal.\n", edattrend); + exit_powwow(); +} + +static void sig_intr_handler __P1 (int,signum) +{ + if (confirm) { + tty_printf("%s\n#interrupted.%s\n", edattrend, tty_clreoln); + exit_powwow(); + } + + PRINTF("%s\n#interrupted. Press again to quit%s\n", edattrend, tty_clreoln); + tty_flush(); /* in case we are not in mainlupe */ + confirm = 1; + error = USER_BREAK; + + sig_oneshot(SIGINT, sig_intr_handler); +} + +/* + * suspend ourselves + */ +void suspend_powwow __P1 (int, signum) +{ + if (can_suspend) { + sig_permanent(SIGTSTP, SIG_DFL); + sig_permanent(SIGTERM, SIG_IGN); + sig_permanent(SIGINT, SIG_IGN); + tty_puts(edattrend); + tty_quit(); + + if (kill(0, SIGTSTP) < 0) { + errmsg("suspend powwow"); + return; + } + + signal_start(); + tty_start(); + tty_sig_winch_bottomhalf(); /* in case size changed meanwhile */ + } else + tty_puts("\n#I don't think your shell has job control.\n"); + status(1); +} + +/* + * GH: Sets a signal-handler permanently (like bsd signal()) + * from Ilie + */ +function_signal sig_permanent __P2 (int,signum, function_signal,sighandler) +{ + struct sigaction act; + function_signal oldhandler; + + if (sigaction(signum, NULL, &act)) + return SIG_ERR; + oldhandler = act.sa_handler; + act.sa_handler = sighandler; +#ifdef SA_RESTART + act.sa_flags = SA_RESTART; +#else + act.sa_flags = 0; +#endif + if (sigaction(signum, &act, NULL)) + return SIG_ERR; + return oldhandler; +} + +/* + * One-shot only signal. Hope it will work as intended. + */ +#ifdef SA_ONESHOT +function_signal sig_oneshot __P2 (int,signum, function_signal,sighandler) +{ + struct sigaction act; + function_signal oldhandler; + + if (sigaction(signum, NULL, &act)) + return SIG_ERR; + oldhandler = act.sa_handler; + act.sa_handler = sighandler; + act.sa_flags = SA_ONESHOT; + if (sigaction(signum, &act, NULL)) + return SIG_ERR; + return oldhandler; +} +#endif + + +/* + * set up our signal handlers + */ +void signal_start __P0 (void) +{ + if (sig_permanent(SIGTSTP, SIG_IGN) == SIG_DFL) { + sig_permanent(SIGTSTP, suspend_powwow); + can_suspend = 1; + } + sig_permanent(SIGCHLD, sig_chld_handler); + sig_permanent(SIGQUIT, sig_intr_handler); + sig_permanent(SIGTERM, sig_term_handler); + sig_permanent(SIGPIPE, sig_pipe_handler); + sig_permanent(SIGWINCH, sig_winch_handler); + /* + * this must not be permanent, as we want + * to be able to interrupt system calls + */ + sig_oneshot(SIGINT, sig_intr_handler); +} + +void sig_bottomhalf __P0 (void) +{ + if (sig_chld_got) + sig_chld_bottomhalf(); + if (sig_winch_got) + tty_sig_winch_bottomhalf(); + + sig_pending = sig_chld_got = sig_winch_got = 0; +} + +void errmsg __P1 (char *,msg) +{ + if (!msg) + msg = ""; + + clear_input_line(opt_compact); + if (!opt_compact) { + tty_putc('\n'); + status(1); + } + if (errno == EINTR) { + tty_printf("#user break: %s (%d: %s)\n", + msg, errno, strerror(errno)); + } else if (errno) { + tty_printf("#system call error: %s (%d", msg, errno); + if (errno > 0) + tty_printf(": %s)\n", strerror(errno)); + else + tty_puts(")\n"); + } else if (error == NO_MEM_ERROR) { + tty_printf("#system call error: %s (%d", msg, ENOMEM); + tty_printf(": %s)\n", strerror(ENOMEM)); + } + tty_flush(); +} + +/* + * print system call error message and terminate + */ +void syserr __P1 (char *,msg) +{ + if (msg && *msg) { + clear_input_line(opt_compact); + if (!opt_compact) { + tty_putc('\n'); + /* status(1); */ + } + tty_flush(); + + fprintf(stderr, "#powwow: fatal system call error:\n\t%s (%d", msg, errno); + if (errno > 0) + fprintf(stderr, ": %s", strerror(errno)); + fprintf(stderr, ")\n"); + } + +#ifdef SAVE_ON_SYSERR + /* Try to do an emergency save. This can wreak havoc + * if called from the wrong place, like + * read_settings() or save_settings(), + * thus is executed only if you add -DSAVE_ON_SYSERR + * to CF flags in make_it + */ + (void)save_settings(); +#else + tty_puts("#settings NOT saved to file.\n"); +#endif + + tty_quit(); + exit(1); +} + +static void load_missing_stuff __P1 (int,n) +{ + char buf[BUFSIZE]; + + if (n < 1) { + tty_add_walk_binds(); + tty_puts("#default keypad settings loaded\n"); + } + if (n < 2) { + tty_add_initial_binds(); + tty_puts("#default editing keys settings loaded\n"); + } + if (n < 5) { + static char *str[] = { "compact", "debug", "echo", "info", + "keyecho", "speedwalk", "wrap", 0 }; + int i; + for (i=0; str[i]; i++) { + sprintf(buf, "#%s={#if ($(1)==\"on\") #option +%s; #else #if ($(1)==\"off\") #option -%s; #else #option %s}", + str[i], str[i], str[i], str[i]); + parse_alias(buf); + } + tty_printf("#compatibility aliases loaded:\n\t%s\n", + "#compact, #debug, #echo, #info, #keyecho, #speedwalk, #wrap"); + } + if (n < 6) { + sprintf(buf, "#lines=#setvar lines=$0"); + parse_alias(buf); + sprintf(buf, "#settimer=#setvar timer=$0"); + parse_alias(buf); + limit_mem = 1048576; + tty_printf("#compatibility aliases loaded:\n\t%s\n", "#lines, #settimer"); + tty_puts("#max text/strings length set to 1048576 bytes\n\tuse `#setvar mem' to change it\n\n#wait..."); + tty_flush(); + sleep(1); + tty_puts("ok\n"); + } +} + +/* + * read definitions from file + * return > 0 if success, < 0 if fail. + * NEVER call syserr() from here or powwow will + * try to save the definition file even if it got + * a broken or empty one. + */ +int read_settings __P0 (void) +{ + FILE *f; + char *buf, *p, *cmd, old_nice = a_nice; + int failed = 1, n, savefilever = 0, left, len, limit_mem_hit = 0; + varnode **first; + ptr ptrbuf; + + if (!*deffile) { + PRINTF("#warning: no save-file defined!\n"); + return 0; + } + + f = fopen(deffile, "r"); + if (!f) { + PRINTF("#error: cannot open file `%s': %s\n", deffile, strerror(errno)); + return 0; + } + + ptrbuf = ptrnew(PARAMLEN); + if (MEM_ERROR) { + print_error(error); + return 0; + } + buf = ptrdata(ptrbuf); + left = ptrmax(ptrbuf); + len = 0; + + echo_int = a_nice = 0; + + for (n = 0; n < MAX_HASH; n++) { + while (aliases[n]) + delete_aliasnode(&aliases[n]); + } + while (actions) + delete_actionnode(&actions); + while (prompts) + delete_promptnode(&prompts); + while (markers) + delete_marknode(&markers); + while (keydefs) + delete_keynode(&keydefs); + for (n = 0; n < MAX_HASH; n++) { + while (named_vars[0][n]) + delete_varnode(&named_vars[0][n], 0); + first = &named_vars[1][n]; + while (*first) { + if (is_permanent_variable(*first)) + first = &(*first)->next; + else + delete_varnode(first, 1); + } + } + + for (n = 0; n < NUMVAR; n++) { + *var[n].num = 0; + ptrdel(*var[n].str); + *var[n].str = NULL; + } + + while (left > 0 && fgets(buf+len, left+1, f)) { + /* WARNING: accessing private field ->len */ + len += n = strlen(buf+len); + ptrbuf->len = len; + left -= n; + + /* Clear all \n prefixed with a literal backslash '\\' */ + while( cmd = strstr( buf, "\\\n" ) ) { + cmd[ 0 ] = ' '; + cmd[ 1 ] = ' '; + } + + cmd = strchr(buf, '\n'); + + if (!cmd) { + if (feof(f)) { + PRINTF("#error: missing newline at end of file `%s'\n", deffile); + break; + } + /* no newline yet. increase line size and try again */ + ptrbuf = ptrpad(ptrbuf, ptrlen(ptrbuf) >> 1); + if (MEM_ERROR) { + limit_mem_hit = 1; + print_error(error); + break; + } + ptrtrunc(ptrbuf,len); + buf = ptrdata(ptrbuf); + left = ptrmax(ptrbuf) - len; + continue; + } + /* got a full line */ + *cmd = '\0'; + cmd = buf; + left += len; + len = 0; + + cmd = skipspace(cmd); + if (!*cmd) + continue; + + error = 0; + if (*(p = first_regular(cmd, ' '))) { + *p++ = '\0'; + if (!strcmp(cmd, "#savefile-version")) { + savefilever = atoi(p); + continue; + } + *--p = ' '; + } + parse_user_input(cmd, 1); + } + + if (error) + failed = -1; + else if (ferror(f) && !feof(f)) { + PRINTF("#error: cannot read file `%s': %s\n", deffile, strerror(errno)); + failed = -1; + } else if (limit_mem_hit) { + PRINTF("#error: cannot load save-file: got a line longer than limit\n"); + failed = -1; + } else if (savefilever > SAVEFILEVER) { + PRINTF("#warning: this powwow version is too old!\n"); + } else if (savefilever < SAVEFILEVER) { + PRINTF("\n#warning: config file is from an older version\n"); + load_missing_stuff(savefilever); + } + + fclose(f); + a_nice = old_nice; + + if (ptrbuf) + ptrdel(ptrbuf); + + return failed; +} + +static char tmpname[BUFSIZE]; + +static void fail_msg __P0 (void) +{ + PRINTF("#error: cannot write to temporary file `%s': %s\n", tmpname, strerror(errno)); +} + +/* + * save settings in definition file + * return > 0 if success, < 0 if fail. + * NEVER call syserr() from here or powwow will + * enter an infinite loop! + */ +int save_settings __P0 (void) +{ + FILE *f; + int l; + aliasnode *alp; + actionnode *acp; + promptnode *ptp; + marknode *mp; + keynode *kp; + varnode *vp; + ptr pp = (ptr)0; + extern char *full_options_string; + int i, flag, failed = 1; + + if (REAL_ERROR) { + PRINTF("#will not save after an error!\n"); + return -1; + } + error = 0; + + if (!*deffile) { + PRINTF("#warning: no save-file defined!\n"); + return -1; + } + + /* + * Create a temporary file in the same directory as deffile, + * and write settings there + */ + strcpy(tmpname, deffile); + l = strlen(tmpname) - 1; + while (l && tmpname[l] != '/') + l--; + if (l) + l++; + + sprintf(tmpname + l, "tmpsav%d%d", getpid(), rand() >> 8); + if (!(f = fopen(tmpname, "w"))) { + fail_msg(); + return -1; + } + + pp = ptrnew(PARAMLEN); + if (MEM_ERROR) failed = -1; + + failed = fprintf(f, "#savefile-version %d\n", SAVEFILEVER); + if (failed > 0 && *hostname) + failed = fprintf(f, "#host %s %d\n", hostname, portnumber); + + if (failed > 0) { + if (delim_mode == DELIM_CUSTOM) { + pp = ptrmescape(pp, DELIM, strlen(DELIM), 0); + if (MEM_ERROR) failed = -1; + } + if (failed > 0) + failed = fprintf(f, "#delim %s%s\n", delim_name[delim_mode], + delim_mode == DELIM_CUSTOM ? ptrdata(pp) : "" ); + } + + if (failed > 0 && *initstr) + failed = fprintf(f, "#init =%s\n", initstr); + + if (failed > 0 && limit_mem) + failed = fprintf(f, "#setvar mem=%d\n", limit_mem); + + if (failed > 0 && (i = log_getsize())) + failed = fprintf(f, "#setvar buffer=%d\n", i); + + if (failed > 0) { + reverse_sortedlist((sortednode **)&sortedaliases); + for (alp = sortedaliases; alp && failed > 0; alp = alp->snext) { + pp = ptrmescape(pp, alp->name, strlen(alp->name), 0); + if (MEM_ERROR) { failed = -1; break; } + failed = fprintf(f, "#alias %s%s%s=%s\n", ptrdata(pp), + alp -> group == NULL ? "" : "@", + alp -> group == NULL ? "" : alp -> group, + alp->subst); + } + reverse_sortedlist((sortednode **)&sortedaliases); + } + + for (acp = actions; acp && failed > 0; acp = acp->next) { + failed = fprintf(f, "#action %c%c%s%s%s %s=%s\n", + action_chars[acp->type], acp->active ? '+' : '-', + acp->label, + acp -> group == NULL ? "" : "@", + acp -> group == NULL ? "" : acp -> group, + acp->pattern, acp->command); + } + + for (ptp = prompts; ptp && failed > 0; ptp = ptp->next) { + failed = fprintf(f, "#prompt %c%c%s %s=%s\n", + action_chars[ptp->type], ptp->active ? '+' : '-', + ptp->label, ptp->pattern, ptp->command); + } + + for (mp = markers; mp && failed > 0; mp = mp->next) { + pp = ptrmescape(pp, mp->pattern, strlen(mp->pattern), 0); + if (MEM_ERROR) { failed = -1; break; } + failed = fprintf(f, "#mark %s%s=%s\n", mp->mbeg ? "^" : "", + ptrdata(pp), attr_name(mp->attrcode)); + } + /* save value of global variables */ + + for (flag = 0, i=0; i<NUMVAR && failed > 0; i++) { + if (var[i].num && *var[i].num) { /* first check was missing!!! */ + failed = fprintf(f, "%s@%d = %ld", flag ? ", " : "#(", + i-NUMVAR, *var[i].num); + flag = 1; + } + } + if (failed > 0 && flag) failed = fprintf(f, ")\n"); + + for (i=0; i<NUMVAR && failed > 0; i++) { + if (var[i].str && *var[i].str && ptrlen(*var[i].str)) { + pp = ptrescape(pp, *var[i].str, 0); + if (MEM_ERROR) { failed = -1; break; } + failed = fprintf(f, "#($%d = \"%s\")\n", i-NUMVAR, ptrdata(pp)); + } + } + + if (failed > 0) { + reverse_sortedlist((sortednode **)&sortednamed_vars[0]); + for (flag = 0, vp = sortednamed_vars[0]; vp && failed > 0; vp = vp->snext) { + if (vp->num) { + failed = fprintf(f, "%s@%s = %ld", flag ? ", " : "#(", + vp->name, vp->num); + flag = 1; + } + } + reverse_sortedlist((sortednode **)&sortednamed_vars[0]); + } + if (failed > 0 && flag) failed = fprintf(f, ")\n"); + + if (failed > 0) { + reverse_sortedlist((sortednode **)&sortednamed_vars[1]); + for (vp = sortednamed_vars[1]; vp && failed > 0; vp = vp->snext) { + if (!is_permanent_variable(vp) && vp->str && ptrlen(vp->str)) { + pp = ptrescape(pp, vp->str, 0); + if (MEM_ERROR) { failed = -1; break; } + failed = fprintf(f, "#($%s = \"%s\")\n", vp->name, ptrdata(pp)); + } + } + reverse_sortedlist((sortednode **)&sortednamed_vars[1]); + } + + /* GH: fixed the history and word completions saves */ + if (failed > 0 && opt_history) { + l = (curline + 1) % MAX_HIST; + while (failed > 0 && l != curline) { + if (hist[l] && *hist[l]) { + pp = ptrmescape(pp, hist[l], strlen(hist[l]), 0); + if (MEM_ERROR) { failed = -1; break; } + failed = fprintf(f, "#put %s\n", ptrdata(pp)); + } + if (++l >= MAX_HIST) + l = 0; + } + } + + if (failed > 0 && opt_words) { + int cl = 4, len; + l = wordindex; + flag = 0; + while (words[l = words[l].next].word) + ; + while (words[l = words[l].prev].word && failed > 0) { + if (~words[l].flags & WORD_RETAIN) { + pp = ptrmescape(pp, words[l].word, strlen(words[l].word), 0); + len = ptrlen(pp) + 1; + if (cl > 4 && cl + len >= 80) { + cl = 4; + failed = fprintf(f, "\n"); + flag = 0; + } + if (failed > 0) + failed = fprintf(f, "%s %s", flag ? "" : "#add", ptrdata(pp)); + cl += len; + flag = 1; + } + } + if (failed > 0 && flag) + failed = fprintf(f, "\n"); + } + + for (kp = keydefs; kp && failed > 0; kp = kp->next) { + if (kp->funct==key_run_command) + failed = fprintf(f, "#bind %s %s=%s\n", kp->name, + seq_name(kp->sequence, kp->seqlen), kp->call_data); + else + failed = fprintf(f, "#bind %s %s=%s%s%s\n", kp->name, + seq_name(kp->sequence, kp->seqlen), + internal_functions[lookup_edit_function(kp->funct)].name, + kp->call_data ? " " : "", + kp->call_data ? kp->call_data : ""); + } + + if (failed > 0) + failed = + fprintf(f, full_options_string, + opt_exit ? '+' : '-', + opt_history ? '+' : '-', + opt_words ? '+' : '-', + opt_compact ? '+' : '-', + opt_debug ? '+' : '-', + echo_ext ? '+' : '-', + echo_int ? '+' : '-', + echo_key ? '+' : '-', + opt_speedwalk ? '+' : '-', + opt_wrap ? '+' : '-', + opt_autoprint ? '+' : '-', + opt_reprint ? '+' : '-', + opt_sendsize ? '+' : '-', + opt_autoclear ? '+' : '-', + "\n"); + + fclose(f); + + if (error) + errmsg("malloc"); + else if (failed <= 0) + fail_msg(); + else { + failed = rename(tmpname, deffile); + if (failed == -1) { + PRINTF("#error: cannot move temporary file `%s' to `%s': %s\n", + tmpname, deffile, strerror(errno)); + } else + failed = 1; + } + + if (pp) + ptrdel(pp); + + return failed > 0 ? 1 : -1; +} + +/* + * update `now' to current time + */ +void update_now __P0 (void) +{ + if (!now_updated) { + gettimeofday(&now, NULL); + now_updated = 1; + } +} + +/* + * terminate powwow as cleanly as possible + */ +void exit_powwow __P0 (void) +{ + log_flush(); + if (capturefile) fclose(capturefile); + if (recordfile) fclose(recordfile); + if (moviefile) fclose(moviefile); + (void)save_settings(); + show_stat(); + tty_quit(); + exit(0); +} @@ -0,0 +1,48 @@ +/* public declarations from utils.c */ + +#ifndef _UTILS_H_ +#define _UTILS_H_ + +char *my_strdup __P ((char *s)); +char *my_strncpy __P ((char *dst, char *src, int len)); +int printstrlen __P ((char *s)); + +void ptrunescape __P ((ptr p)); +int memunescape __P ((char *p, int lenp)); + +ptr ptrescape __P ((ptr dst, ptr src, int append)); +ptr ptrmescape __P ((ptr dst, char *src, int srclen, int append)); + +ptr ptraddmarks __P ((ptr dst, ptr line)); +ptr ptrmaddmarks __P ((ptr dst, char *line, int len)); + +void put_marks __P ((char *dst, char *line)); +void smart_print __P ((char *line, char newline)); +char *split_first_word __P ((char *dst, int dstlen, char *src)); +char *first_valid __P ((char *p, char ch)); +char *first_regular __P ((char *p, char c)); +void unescape __P ((char *s)); +void escape_specials __P ((char *str, char *p)); +char *skipspace __P ((char *p)); +void exit_powwow __P ((void)); +void suspend_powwow __P ((int signum)); +function_signal sig_permanent __P ((int signum, function_signal sighandler)); + +#ifdef SA_ONESHOT + function_signal sig_oneshot __P ((int signum, function_signal sighandler)); +#else +# define sig_oneshot signal +#endif + +void signal_start __P ((void)); +void sig_bottomhalf __P ((void)); +void errmsg __P ((char *msg)); +void syserr __P ((char *msg)); +int read_settings __P ((void)); +int save_settings __P ((void)); +void movie_write __P ((char *str, int newline)); + +void update_now __P ((void)); + +#endif /* _UTILS_H_ */ + |