aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AUTHORS0
-rw-r--r--COPYING348
-rw-r--r--ChangeLog.old746
-rw-r--r--Config.demo401
-rw-r--r--Hacking67
-rw-r--r--INSTALL229
-rw-r--r--Makefile.am20
-rw-r--r--Makefile.in658
-rw-r--r--NEWS0
-rw-r--r--README140
-rw-r--r--README.follow18
-rw-r--r--README.term26
-rw-r--r--TODO46
-rw-r--r--aclocal.m41020
-rw-r--r--beam.c438
-rw-r--r--beam.h17
-rw-r--r--catrw.c39
-rw-r--r--cmd.c2464
-rw-r--r--cmd.h21
-rw-r--r--cmd2.c1665
-rw-r--r--cmd2.h32
-rwxr-xr-xconfigure5415
-rw-r--r--configure.in49
-rw-r--r--debian/changelog9
-rw-r--r--debian/control12
-rwxr-xr-xdebian/rules78
-rw-r--r--defines.h367
-rwxr-xr-xdepcomp464
-rw-r--r--edit.c886
-rw-r--r--edit.h75
-rw-r--r--eval.c1450
-rw-r--r--eval.h58
-rw-r--r--follow.c166
-rwxr-xr-xinstall-sh294
-rw-r--r--list.c679
-rw-r--r--list.h47
-rw-r--r--log.c322
-rw-r--r--log.h22
-rw-r--r--main.c1995
-rw-r--r--main.h117
-rw-r--r--map.c193
-rw-r--r--map.h15
-rwxr-xr-xmissing336
-rwxr-xr-xmkinstalldirs111
-rw-r--r--movie.c93
-rw-r--r--muc.c298
-rw-r--r--plugtest.c18
-rw-r--r--powwow.6115
-rw-r--r--powwow.doc2152
-rw-r--r--powwow.help553
-rw-r--r--ptr.c578
-rw-r--r--ptr.h68
-rw-r--r--tcp.c1022
-rw-r--r--tcp.h78
-rw-r--r--tty.c774
-rw-r--r--tty.h52
-rw-r--r--utils.c1279
-rw-r--r--utils.h48
58 files changed, 28683 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/AUTHORS
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..4e55b6d
--- /dev/null
+++ b/COPYING
@@ -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
diff --git a/Hacking b/Hacking
new file mode 100644
index 0000000..d91a52f
--- /dev/null
+++ b/Hacking
@@ -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).
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..54caf7c
--- /dev/null
+++ b/INSTALL
@@ -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:
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/NEWS
diff --git a/README b/README
new file mode 100644
index 0000000..8731061
--- /dev/null
+++ b/README
@@ -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...)
+
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..91012de
--- /dev/null
+++ b/TODO
@@ -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
+
diff --git a/beam.c b/beam.c
new file mode 100644
index 0000000..da92ed9
--- /dev/null
+++ b/beam.c
@@ -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;
+ }
+ }
+ }
+}
+
diff --git a/beam.h b/beam.h
new file mode 100644
index 0000000..cd1ce09
--- /dev/null
+++ b/beam.h
@@ -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_ */
+
diff --git a/catrw.c b/catrw.c
new file mode 100644
index 0000000..164d2a3
--- /dev/null
+++ b/catrw.c
@@ -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;
+}
+
diff --git a/cmd.c b/cmd.c
new file mode 100644
index 0000000..45ca1c0
--- /dev/null
+++ b/cmd.c
@@ -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, &param)))
+ 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);
+}
+
+
diff --git a/cmd.h b/cmd.h
new file mode 100644
index 0000000..c19f45f
--- /dev/null
+++ b/cmd.h
@@ -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_ */
+
diff --git a/cmd2.c b/cmd2.c
new file mode 100644
index 0000000..b43f68b
--- /dev/null
+++ b/cmd2.c
@@ -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, &params)))
+ 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, &params))) {
+ 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);
+ }
+}
+
diff --git a/cmd2.h b/cmd2.h
new file mode 100644
index 0000000..abc456a
--- /dev/null
+++ b/cmd2.h
@@ -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_ */
+
diff --git a/depcomp b/depcomp
new file mode 100755
index 0000000..51606f8
--- /dev/null
+++ b/depcomp
@@ -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
diff --git a/edit.c b/edit.c
new file mode 100644
index 0000000..463f318
--- /dev/null
+++ b/edit.c
@@ -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();
+}
+
diff --git a/edit.h b/edit.h
new file mode 100644
index 0000000..a81b97c
--- /dev/null
+++ b/edit.h
@@ -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_ */
diff --git a/eval.c b/eval.c
new file mode 100644
index 0000000..8105e47
--- /dev/null
+++ b/eval.c
@@ -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);
+}
+
diff --git a/eval.h b/eval.h
new file mode 100644
index 0000000..67041d1
--- /dev/null
+++ b/eval.h
@@ -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, &ltcsave);
+ 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, &ltc);
+#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, &ltcsave);
+#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
+}
diff --git a/list.c b/list.c
new file mode 100644
index 0000000..eb2fe51
--- /dev/null
+++ b/list.c
@@ -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;
+ }
+}
diff --git a/list.h b/list.h
new file mode 100644
index 0000000..24588d3
--- /dev/null
+++ b/list.h
@@ -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_ */
+
diff --git a/log.c b/log.c
new file mode 100644
index 0000000..f4cc90c
--- /dev/null
+++ b/log.c
@@ -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;
+}
+
diff --git a/log.h b/log.h
new file mode 100644
index 0000000..0fe3a54
--- /dev/null
+++ b/log.h
@@ -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_ */
+
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..547ec72
--- /dev/null
+++ b/main.c
@@ -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 = &paramstk.p[0][j].num;
+ VAR[j].str = &paramstk.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 = &paramstk.p[paramstk.curr][i].num) = 0;
+ ptrzero(*(VAR[i].str = &paramstk.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 = &paramstk.p[paramstk.curr][i].num;
+ VAR[i].str = &paramstk.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);
+}
diff --git a/main.h b/main.h
new file mode 100644
index 0000000..3258988
--- /dev/null
+++ b/main.h
@@ -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_ */
diff --git a/map.c b/map.c
new file mode 100644
index 0000000..8b88269
--- /dev/null
+++ b/map.c
@@ -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;
+}
+
diff --git a/map.h b/map.h
new file mode 100644
index 0000000..97c0edf
--- /dev/null
+++ b/map.h
@@ -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_ */
+
diff --git a/missing b/missing
new file mode 100755
index 0000000..6a37006
--- /dev/null
+++ b/missing
@@ -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
diff --git a/movie.c b/movie.c
new file mode 100644
index 0000000..093fd31
--- /dev/null
+++ b/movie.c
@@ -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;
+ }
+}
+
diff --git a/muc.c b/muc.c
new file mode 100644
index 0000000..37cc660
--- /dev/null
+++ b/muc.c
@@ -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.
diff --git a/ptr.c b/ptr.c
new file mode 100644
index 0000000..2c63c3e
--- /dev/null
+++ b/ptr.c
@@ -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 */
+}
+
diff --git a/ptr.h b/ptr.h
new file mode 100644
index 0000000..a90bf63
--- /dev/null
+++ b/ptr.h
@@ -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_ */
diff --git a/tcp.c b/tcp.c
new file mode 100644
index 0000000..3d0a3fe
--- /dev/null
+++ b/tcp.c
@@ -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.
+ */
+}
+
diff --git a/tcp.h b/tcp.h
new file mode 100644
index 0000000..1813980
--- /dev/null
+++ b/tcp.h
@@ -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_ */
+
diff --git a/tty.c b/tty.c
new file mode 100644
index 0000000..c2d0cb7
--- /dev/null
+++ b/tty.c
@@ -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, &ltcsave);
+ 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, &ltc);
+#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, &ltcsave);
+#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, &ltc);
+#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));
+}
+
diff --git a/tty.h b/tty.h
new file mode 100644
index 0000000..ab22d90
--- /dev/null
+++ b/tty.h
@@ -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_ */
diff --git a/utils.c b/utils.c
new file mode 100644
index 0000000..8ec96eb
--- /dev/null
+++ b/utils.c
@@ -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);
+}
diff --git a/utils.h b/utils.h
new file mode 100644
index 0000000..1386301
--- /dev/null
+++ b/utils.h
@@ -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_ */
+