Merge branch 'patches/010_makefile-destdir-support' into patches/020_man-hyphen-quoting
[ckermit.git] / ckermit90.txt
diff --git a/ckermit90.txt b/ckermit90.txt
new file mode 100644 (file)
index 0000000..adf6ee3
--- /dev/null
@@ -0,0 +1,2152 @@
+
+   [1]The Columbia Crown The Kermit Project | Columbia University
+   612 West 115th Street, New York NY 10025 USA o [2]kermit@columbia.edu
+   ...since 1981
+   [3]Home [4]Kermit 95 [5]C-Kermit [6]Scripts [7]Current [8]New [9]FAQ
+   [10]Support
+
+
+      [11]CLICK HERE to read about some of these items.
+
+          [12]Table of platforms   [13]Book: Using C-Kermit   [14]Download
+                                                              C-Kermit 9.0
+
+C-Kermit 9.0 Update Notes
+
+   Note:   C-Kermit 9.0.301 contains a correction that applies only to
+   Solaris 10 and 11.
+     C-Kermit 9.0.302 contains corrections that apply only to FreeBSD 8
+   and 9.
+     * [15]Large Files
+     * [16]How to Test Large-File Transfer
+     * [17]Arithmetic with Large Integers
+     * [18]FORCE-3 Packet Protocol
+     * [19]Variable Evaluation
+
+     * [20]The RENAME Command You Always Wanted
+     * [21]Other New Features
+     * [22]Incompatibilities
+     * [23]What's Not In C-Kermit 9.0
+     * [24]And a Loose End
+
+     * [25]Demonstration: Secure POP mail fetcher
+     * [26]Demonstration: HP Switch Configuration Backup
+     * [27]Demonstration: HP iLO Blade Configuration
+     * [28]Demonstration: IBM/Rolm/Siemens CBX Management
+     * [29]Demonstration: CSV and TSV Files
+     * [30]Demonstration Scripts for Webmasters
+
+   This is the third supplement to [31]Using C-Kermit, Second Edition. I
+   apologize for the scattered nature of the information and I hope I can
+   organize it and gather it all into one place for easy and definitive
+   reference some day. It's a big job so it depends on the demand. For the
+   time being the definitive reference and introduction is the book (which
+   is now available also in a [32]Kindle Edition), plus the [33]C-Kermit
+   7.0 update, [34]C-Kermit 8.0 update, and now this one. Plus tons of
+   other web pages on this site, sample script programs, and so on.
+
+   In version 6.0, C-Kermit was a pretty powerful and flexible
+   communication program with scripting capabilities. By version 9.0, I'd
+   like to think of it more as a scripting language with built-in
+   communications. You can get an idea of the kinds of programs you can
+   write in Kermit language [35]here. You can develop programs quickly
+   because it's an interactive program, not a compiler. The scripting
+   language is the command language. Kind of like the Unix shell but
+   "somewhat" less cryptic, including concepts not only from C but from
+   PL/I, Snobol, LISP, Bliss, and Smalltalk. The language itself is built
+   upon the command language of the much-loved [36]DECSYSTEM-20 from the
+   1970s and 80s, the Clipper Ship of the Text Era. (Text is not a bad
+   word. Those of us who can touch-type and who are proficient in
+   text-based computing environments like Unix shell or VMS DCL are likely
+   to be orders of magnitude more productive than users of GUIs.)
+
+   Thanks to (at least) Jeff Altman, William Bader, Ian Beckwith, Nelson
+   Beebe, Gerry Belanger, Joop Boonen, Rob Brown, Christian Corti, Alexey
+   Dokuchaev, John Dunlap, Peter Eichhorn, Carl Friedberg, Terry Kennedy,
+   Günter Knauf, Jason Lehr, Arthur Marsh, Lewis McCarthy, Gary Mills, Ed
+   Ravin, Jonathan Reams, Mike Rechtman, Mark Sapiro, Steven Schweda
+   (SMS), Kinjal Shah, Michael Sokolov, Andy Tanenbaum, Seth Theriault,
+   Zach A. Thomas, Martin Vorländer, and Eric Weaver for assistance, and
+   to Hewlett-Packard Company for support.
+
+     - Frank da Cruz   [37]fdc@columbia.edu, 30 June 2011
+
+   P.S. It occurred to me just before the end of the day that maybe I
+   should back up the Kermit website on DVD, just in case. Using
+   [38]Kermit 95 on the desktop over an SSH connection to the Unix file
+   system where the website resides, I made a fresh directory on the PC,
+   CD'd to it, and on Unix cd'd to the Website directory, and told
+   C-Kermit 9.0 to:
+
+C-Kermit> send /recursive /dotfiles /nobackup *
+
+   and it re-created the website directory tree in the PC directory, text
+   files correctly converted to Windows format and binary files correctly
+   left as-is. The /dotfiles switch means to include files such as
+   .htaccess whose names start with a dot (period), and the /nobackup
+   switch means to skip backup files created by EMACs (such as
+   index.html.~243~). And then I did the same with the FTP sites, about
+   8GB in all. Watching the file-transfer display was kind of like having
+   30 years of my life flash before my eyes in a few minutes. Then I
+   copied the two directories to DVD (the FTP site had to be split over 2
+   DVDs). The whole operation took under half an hour. The directory tree
+   on the CD is directly usable in Windows, Unix, or any other operating
+   system (unlike if I had transferred the files all in binary mode or all
+   in text mode, or if I had made, say, a gzipped tar archive or a zip
+   archive). I believe that, to this day, Kermit is the only software that
+   can do this. If someday I have to upload from these DVDs to Unix, VMS,
+   or any other operating system, it can be done exactly the same way,
+   with any necessary conversions on text files done automatically, and
+   binary files left intact, recursively through a whole very large
+   directory tree.
+
+What's New in General
+
+   Very briefly, the major items:
+     * [39]Open Source license.
+     * [40]64-bit file access and transfer and 64-bit integer arithmetic
+       on most common platforms.
+     * Support for recent releases of Linux, Mac OS X, *BSD, etc ([41]see
+       table).
+     * Support for newer OpenSSL releases up to and including 1.0.0d
+       ([42]see table).
+     * [43]Strengthened error checking for file transfer under extremely
+       harsh conditions.
+     * [44]Simplified semantics for variables used in scripts.
+     * Super-handy [45]extensions to the RENAME command.
+     * Other scripting improvements including support for reading and
+       writing [46]CSV and TSV files.
+     * [47]MIME character-set names are now recognized.
+     * Improved logging and debugging (see demo [48]here).
+     * Lots more described or listed below, and [49]here.
+
+Open Source License
+
+   C-Kermit 9.0 has the [50]Revised 3-Clause BSD License, an open source
+   license approved by OSI, the [51]Open Source Initiative.
+
+Large Files
+
+   Kermit is, first and foremost, a file-transfer program. One might
+   expect it to be able to transfer any kind of file, but that has been
+   decreasingly the case as file sizes began to cross the 2 gigabyte
+   threshold.
+
+   The biggest change since C-Kermit 8.0.211 is support for large files on
+   platforms that support them. A "large file" is one whose size is
+   greater than 2^31-1 (2,147,483,647) bytes (2GB-1); that is, one whose
+   size requires more than 31 bits to represent. Before now, Kermit was
+   able to access such files only on 100% 64-bit platforms such as Digital
+   Unix, later known as Tru64 Unix. In the new release, Kermit takes
+   advantage of the X/Open Single UNIX Specification Version 2 (UNIX 98)
+   Large File Support (LFS) specification, which allows 32-bit platforms
+   to create, access, and manage files larger than 2GB.
+
+   Accommodating large files required code changes in many modules,
+   affecting not only file transfer, but also file management functions
+   from directory listings to local file manipulation, plus the user
+   interface itself to allow entry and display of large numbers. All this
+   had to be done in a way that would not affect pure 32-bit builds on
+   platforms that do not support large files. Large file support is
+   summarized in the [52]Table of Platforms; entries in Yellow (32-bit
+   builds that support 64-bit integers) and Green (64-bit builds) support
+   large files.
+
+   Note that VMS C-Kermit and Kermit 95 for Windows have always been able
+   to transfer large files. However their user interface used 32-bit
+   integers for statistics and the file transfer display. In C-Kermit 9.0
+   Alpha.03, VMS C-Kermit on 64-bit platforms (Alpha and Itanium) should
+   now give correct statistics and progress displays. (We'll see about
+   Kermit 95 later.)
+
+How to Test Large-File Transfer
+
+   Several methods are available for testing large-file transfers:
+     * By transferring a real file that is more than 2147483648 bytes long
+       (a file whose length requires more than 31 bits to express); or to
+       be totally sure, that is longer than 4294967296 bytes (32 bits or
+       more). Or to be double super sure, longer than 8589934592 (33
+       bits).
+     * If you don't have such a file or there is not sufficient disk space
+       for such a file, you can create a special kind of file that takes
+       up one block on the disk but appears to be 4.3GB long by compiling
+       and running [53]THIS C PROGRAM on Linux, Solaris, HP-UX, or other
+       Unix platform that supports large files. Kermit or FTP or any other
+       file transfer program will transfer the result (BIGFILE) in such a
+       way as to actually put 4.3GB (or other desired size; see source) on
+       the wire.
+     * You can use Kermit's CALIBRATE feature to transfer a large file
+       that doesn't exist. At the receiver, use RECEIVE /CALIBRATE. At the
+       sender, use SEND /CALIBRATE:length, e.g.:
+
+     (At remote kermit...)
+     $ kermit -Y
+     C-Kermit> receive /calibrate
+     (Return to local kermit...)
+     Ctrl-\c
+     C-Kermit> send /calibrate:4300000000
+       This sends a simulated file 4.3GB in length, that does not exist on
+       the sender and will not take up any disk space on the receiver.
+       SEND /CALIBRATE: accepts big numbers only in Kermit versions that
+       support them (this does not include Kermit 95 on Windows). This
+       method tests only Kermit's ability to express and understand large
+       file sizes, but does not test Kermit's file-system interface, since
+       no files are involved.
+
+Arithmetic with Large Integers
+
+   Because large file support requires the availability of a 64-bit signed
+   integer data type, other aspects of C-Kermit were adapted to use it
+   too, most notably Kermit's algebraic expression evaluator and its
+   [54]S-Expression interpreter, on all platforms that support large files
+   (those listed as 64 or 32/64 in the Word column of the [55]table). In
+   fact, every Kermit command that parses a number in any field can now
+   parse a large number on those platforms.
+
+   S-Expressions can now be forced to operate with integers only, without
+   floating-point conversion or having to explicitly truncate each result;
+   as an example. see the revised [56]Easter date calculation script.
+
+FORCE-3 Packet Protocol
+
+   The Kermit protocol has proven itself over the past 30 years to be
+   robust in terms of surviving harsh transmission environments and
+   delivering the data correctly and completely. In these times of
+   Internet everywhere and error-correcting modems in the few places where
+   the Internet isn't, few people even recall the kinds of difficult
+   conditions that were common when the Kermit protocol was first
+   developed: noisy telephone lines, serial interfaces that drop
+   characters, lack of transparency to control or 8-bit characters,
+   absence of flow control, "bare" modems without error correction.
+
+   But the Internet is not everywhere, and not all modems are
+   error-correcting. Perhaps the most difficult trial so far for Kermit or
+   any other protocol is the [57]EM-APEX project, in which floats are
+   dropped into the ocean from an aircraft into the path of a hurricane;
+   these floats dive into the water measuring current, temperature, and
+   salinity at different depths and then surface to phone home, sending
+   the data to land stations using Kermit protocol over
+   non-error-correcting 300bps [58]Iridium satellite modems, with high
+   seas and winds battering the floats and heavy ([59]sometimes
+   electrical) storms between the modem and the satellite.
+
+   Because of the transmission speed and long distances involved, the
+   transfers were very slow. The Kermit software in the floats is
+   [60]Embedded Kermit, which did not implement sliding windows, which
+   would have sped up the flow considerably. John Dunlap, engineer at the
+   University of Washington's Applied Physics Laboratory, undertook the
+   task of adding sliding windows to E-Kermit. For testing, he rigged up a
+   [61]simulator in which Kermit transfers take place over a connection
+   with different amounts of noise and delay. He found that occasionally,
+   a transfer would appear to succeed, but the received file would be
+   corrupt.
+
+   According to the Kermit protocol definition, the first packet always
+   has block-check type 1, a 6-bit checksum, which is the only block check
+   type that all Kermit implementations are required to support; thus any
+   Kermit partner can process this packet. This packet itself can
+   negotiate a higher level of checking, such that subsequent packets have
+   (say) block-check type 3, a 16-bit cyclic redundancy check (CRC)
+   encoded as three printable 7-bit ASCII characters. The 16-bit CRC can
+   catch all errors of certain kinds (single-bit, double-bit, bursts of 16
+   bits or less), and more than 99.9984741210937% of all other possible
+   errors.
+
+   John's simulations revealed that file corruption could occur undetected
+   when the initial packet was corrupted in such a way that a parameter or
+   capability byte was changed and the checksum also changed to make the
+   packet appear to be correct, thus allowing the transfer to proceed with
+   the two Kermit partners out of sync as to packet encoding and
+   interpretation (the chances of two such errors producing a seemingly
+   valid packet are about 1 in 6000 when using the 6-bit checksum). For
+   example, the compression technique might be misnegotiated and then the
+   receiver might store incoming data without decompressing it.
+
+   The solution is a new option, selected by:
+
+     BLOCK-CHECK TYPE 5
+
+   to require a type 3 block check (16-bit CRC) on every packet, including
+   the initial ones, thus reducing the probability of a misnegotiation by
+   many orders of magnitude. THIS PARAMETER CAN NOT BE NEGOTIATED. Each
+   Kermit program must be given the "set block 5" command prior to
+   transfer. That's because normally every Kermit program expects the
+   first packet to have a 6-bit checksum, and if the first packet has a
+   3-byte, 16-bit CRC, the packet receiver will think it is corrupted.
+
+   In practice, however, it is possible to code the packet receiver
+   "cheat" by reading the packet data before verifying the block check.
+   Thus when the receiver is C-Kermit 9.0 or later or E-Kermit 1.7 or
+   later, it is only necessary to give the "set block 5" command to the
+   file sender, and the receiver will check for a FORCE-3 first packet. If
+   the receiver does not support this feature, however, the initial packet
+   will be be rejected (after several retries) and the file transfer will
+   not take place. There is no attempt to "back off" to normal behavior.
+
+   CAPTION: Table 4. Kermit Protocol Packet Block Check Types
+
+   Type Command Bytes Status Explanation
+   1 SET BLOCK 1 1 Required in all Kermit implementations. Negotiated.
+   6-bit checksum, suitable for good connections.
+   2 SET BLOCK 2 2 Optional, negotiated. 12-bit checksum. 64 times
+   stronger than type 1.
+   3 SET BLOCK 3 3 Optional, negotiated. 16-bit CRC.
+   BLANK-FREE-2 SET BLOCK 4 2 Optional, negotiated. 12-bit checksum, two
+   nonblank bytes.
+   FORCE-3 SET BLOCK 5 3 Optional, not negotiated. 16-bit CRC forced all
+   packets.
+
+   BLANK-FREE-2 is for environments where Kermit packets are treated as
+   lines of text, and in which trailing blanks can be stripped; for
+   example, when transferring files with an IBM mainframe through a 3270
+   protocol converter.
+   [62]E-Kermit 1.7
+
+Variable Evaluation
+
+     Does the strange behavior of Kermit's \%x variables puzzle or annoy
+     you?
+
+   Kermit software development has been a collaborative project over the
+   years, with contributions coming in from almost every country and every
+   sector of the economy - academic, corporate, government. Thus not all
+   versions, and not all features of a given version, are a product of
+   systematic design.
+
+   One example was the introduction of variables for text substitution,
+   first in a version of MS-DOS Kermit that was sent in by someone
+   somewhere (I could look it up, but no time...) Although the design of
+   the notation for variable names (table below) is mine, the underlying
+   code was contributed. In that code there was only one kind of variable,
+   and if I recall correctly the variable name was a backslash followed by
+   a single letter, for example \a, \b, etc. The contributed code
+   evaluated these variables recursively, meaning if the definition of a
+   variable contained variable references, then these were resolved when
+   dereferencing the variable, and the process would continue as deep down
+   as necessary to resolve the thing fully.
+
+   This was sometimes handy, but it had one severe drawback: There was no
+   way to use variables in a straightforward way to represent strings that
+   contained literal backslashes; for example, DOS or Windows pathnames.
+   This gave rise to all kinds of quoting rules and conventions (e.g.
+   doubling backslashes or forcing single-level evaluation with
+   \\fcontents()), and also to the introduction of other kinds of
+   variables that were evaluated one level deep, rather than recursively.
+
+   To accommodate coexistence of different kinds of variables as well as
+   "escape sequences" for representing control and 8-bit characters, the
+   syntax for variable names was extended to include three elements: the
+   leading backslash, then a single character indicating the type of
+   variable, and then the name of the variable in a format corresponding
+   to the type designator, as shown in this somewhat simplified table:
+
+   CAPTION: Table 1. Variable-name Syntax in Kermit
+
+   Notation Meaning
+   \000 - \255 8-bit character constant (decimal)
+   \d000 - \d255 Alternative notation for 8-bit character (byte) constant
+   (decimal)
+   \o000 - \o377 8-bit character constant (octal)
+   \x00 - \xff 8-bit character constant (hexadecimal)
+   \%a - \%z Scalar variable, evaluated recursively.
+   \%0 - \%9 Macro argument, scalar, evaluated recursively.
+   \&a - \%& Array name
+   \&a[x] Array reference, evaluated recursively (x is any constant or
+   variable)
+   \v(name) Built-in scalar variable, evaluated one level deep.
+   \m(name) User-defined scalar variable, evaluated one level deep.
+   \$(name) An environment variable, evaluated one level deep.
+   \s(name[n:m]) Compact substring notation, evaluated one level deep.
+   \fname(args...) Built-in function with zero or more arguments.
+   \\ Literal backslash
+   \N OUTPUT command only: NUL, ASCII 0
+   \B OUTPUT command only: BREAK (250ms, for serial connections)
+   \L OUTPUT command only: Long BREAK (1.5sec, ditto)
+
+   Variable names in Kermit are case-independent. The simplifications in
+   the table are that the notation for decimal and octal bytes can have
+   from one to three digits, and can include braces to separate them from
+   text digits, e.g. \7, \{123}, \o{50}. Hex bytes too, except they must
+   always have exactly two hex digits, 0-9a-f. Array indices must be, or
+   must evaluate to, numbers (floating point numbers are truncated).
+   Associative arrays are also available (dynamic arrays with arbitrary
+   text as subscript), but they are really just a variation on \m()
+   variables (read about associative arrays [63]here). Also, there are
+   some alternative notations for compact substring notation.
+
+   We didn't want to have lots of "distinguished" characters, as the UNIX
+   shell does; one is enough, clarity over brevity. Although the notation
+   can be a bit cumbersome, we can use the \m(name) form to circumvent the
+   overevaluation in most contexts. But macro arguments are always
+   assigned to the \%0-9 variables, and thus always evaluated recursively,
+   making it difficult and confusing to pass (e.g.) Windows pathnames as
+   arguments to macros. The same is true for array elements, especially in
+   contexts where they are used to return results from built-in functions
+   (for example, \fsplit() used to return the elements of a
+   [64]comma-separated value list if any of the values contained
+   backslashes). An even worse scenario is when macro arguments are passed
+   from one macro to another; for some graphic illustrations see
+   [65]Taming the Wild Backslash - Part Deux from the [66]C-Kermit 7.0
+   Update Notes.
+
+   We can't just change how variables are evaluated because that would
+   break existing scripts. But we can always add Yet Another SET Command:
+
+     SET COMMAND VARIABLE-EVALUATION { RECURSIVE, SIMPLE }
+
+   This applies only to \%a-z and \%0-9 variables and to \&a-z[] arrays
+   (since all other kinds of variables are evaluated only one level deep).
+   The default, of course, for backwards compatibility, is RECURSIVE.
+   SIMPLE forces the evaluation of these variables to return their literal
+   contents, without further evaluation:
+
+     * An exception is made in the case of array subscripts, because
+       changing how they are evaluated could break a lot of scripts, and
+       anyway there should never be any harm in evaluating them
+       recursively because their final value is always (or should be)
+       numeric, not some string that might contain backslashes.
+     * The VARIABLE-EVALUATION setting is on the command stack. Thus you
+       can give this command in a macro, command file, or user-defined
+       function without affecting the calling environment.
+     * The new \frecurse() function forces recursive evaluation of its
+       argument regardless of the VARIABLE-EVALUATION setting. The
+       argument can be any string (or nothing at all); all the variables
+       in the string, even \m() ones, are evaluated recursively:
+
+def \%a 1 \%b 3
+def \%b 2
+def xx easy as \%a
+show mac xx
+echo \frecurse(\m(xx))
+easy as 1 2 3
+echo \frecurse(it's as easy as \m(xx))
+it's as easy as easy as 1 2 3
+
+     * The new \v(vareval) built-in variable contains the current setting
+       (recursive or simple) at the current command-stack level.
+
+   Here's a short script for illustration:
+
+define path c:\users\fdc\somefile.txt
+define test1 {        # Normal recursive argument evaluation
+  echo \%0: arg=\%1
+}
+define test2 {        # Simple argument evaluation
+  set var simple
+  echo \%0: arg=\%1
+}
+test1 \m(path)
+test2 \m(path)
+exit
+
+   And here's the result:
+
+?<ERROR:NO_SUCH_FUNCTION:\fdc\somefile.txt()>
+test2: arg=c:\users\fdc\somefile.txt
+
+   The first line might seem surprising, but under the normal rules (see
+   table above) \f indicates a function call, with the letters following
+   the 'f' being the name of the function. But there is no function by
+   that name... and if there were, you probably didn't intend to call it!
+
+   SET COMMAND VARIABLE-EVALUATION SIMPLE has no effect on constants, only
+   on variables. Note how \m(path) is defined. The DEFINE command assigns
+   the literal value of its argument to the named variable (see Table 3
+   below), thus in this case no special syntax is needed. But in other
+   contexts, you must double the backslashes or use the \fliteral()
+   function to use literal backslashes in data:
+
+test2 c:\\users\\fdc\\somefile.txt
+test2 \fliteral(c:\users\fdc\somefile.txt)
+
+   C-Kermit 9.0 adds a new notation for \fliteral() which also has certain
+   advantages over it: \q(string):
+
+test2 \q(c:\users\fdc\somefile.txt)
+
+   Since \fliteral() is a function, its argument list (the text within
+   parentheses) has special syntax of its own, in which commas and braces
+   are treated specially and introduce another set of quoting problems.
+   \q(string) doesn't have these problems. The only consideration is that
+   parentheses must be balanced or else quoted (preceded by backslash), or
+   represented as numeric character entities (left paren = \40, (right
+   paren = \41).
+
+   Or else hold the value in a simple variable as we did with \\m(path)
+   above.
+
+   SET COMMAND VARIABLE-EVALUATION SIMPLE is a big change and might have
+   repercussions that didn't show up in the initial tests; a lot more
+   testing is needed.
+
+   On the topic of variables, let's summarize in one place the ways in
+   which values can be explicitly assigned to variables. There is nothing
+   new here except the table itself:
+
+   CAPTION: Table 2. Variable Assignment in Kermit
+
+   Command Shorthand Explanation
+   DEFINE name value .name = value The literal value becomes the contents
+   of the named variable; variables names in the value are copied without
+   evaluation. This command is for defining macros that take parameters,
+   as well as for defining simple variables, especially if the values
+   contain backslashes.
+   _DEFINE name value   Like DEFINE but the name is evaluated before use.
+   ASSIGN name value .name := value The value is evaluated and the result
+   becomes the contents of the named variable.
+   _ASSIGN name value   Like ASSIGN but the name is evaluated before use.
+   EVALUATE name expression .name ::= value The expression (in regular
+   algebraic notation) is evaluated arithmetically and the result becomes
+   the contents of the named variable. If the expression contains any
+   variables they are evaluated first.
+   _EVALUATE name expression   Like EVALUATE but the name is evaluated
+   before use.
+   INCREMENT name expression   Evaluates the variables in the expression,
+   then evaluates the expression arithmetically, and then adds the value
+   to the contents of the named variable, which must be a number or an
+   algebraic expression. If the expression is empty, a value of 1 is used.
+   _INCREMENT name expression   Like INCREMENT but the name is evaluated
+   before use.
+   DECREMENT name expression   Evaluates the variables in the expression,
+   then evaluates the expression arithmetically, and then subtracts the
+   value from the contents of the named variable, which must be a number
+   or an algebraic expression. If the expression is empty, a value of 1 is
+   used.
+   _DECREMENT name expression   Like DECREMENT but the name is evaluated
+   before use.
+   DECLARE name = list   An array declaration can include an initializer
+   list; items in the list are evaluated before assignment. This can be
+   defeated by doubling any backslashes or enclosing individual arguments
+   in \fliteral().
+   DO name arguments name arguments When invoking a macro with a DO
+   command (or an implied one), the arguments are evaluated, then assigned
+   to \%1, \%2, etc, and the macro's name to \%0.
+   (SETQ name value)   Kermit also includes a mini-[67]LISP interpreter
+
+   Variables are evaluated automatically in Kermit commands simply by
+   referencing them, according to rules given in Table 1. The following
+   functions can be used to change how a a particular variable is
+   evaluated:
+
+   CAPTION: Table 3. Kermit Functions for Evaluating Variables
+
+   Function Argument Description
+   \fcontents() \%x or \&x[y] Evaluates the variable or array element
+   (which normally would be evaluated recursively) one level deep.
+   \fdefinition() name If the argument is a \%x variable or an array
+   element, it is evaluated to get the name; otherwise the argument is the
+   name. Its definition is returned with no recursion.
+   \m() name Equivalent to \fdefinition().
+   \frecurse() \m(name) Forces recursive evaluation of a macro definition
+   (a.k.a. long variable name). NOTE: \frecurse() can operate on any kind
+   of variable as well as on any string containing any mixture of
+   variables.
+
+C-Kermit's RENAME Command
+
+   C-Kermit's RENAME command, which is used for changing the names of
+   local files or for moving files locally, has two basic forms:
+
+   RENAME [ optional-switches ] oldfilename newfilename
+          This form lets you change the name of a single file from
+          oldfilename to newfilename. Example:
+          rename thismonth.log lastmonth.log
+
+   RENAME [ optional-switches ] filespec directoryname
+          This form lets you move (without renaming) one or more files
+          (all the files that match the filespec, which may contain
+          wildcard characters such as "*") to the given directory.
+          Example:
+          rename *.txt ~/textfiles/
+
+   Traditionally, the optional switches have been:
+
+   RENAME /LIST oldname newname
+          Display the old and new name for each file while renaming.
+          Synonyms: /LOG, /VERBOSE. Example:
+          rename /list *.txt ~/textfiles/
+
+   RENAME /NOLIST oldname newname
+          Don't display the old and new name for each file while renaming.
+          This is the default behavior. Synonyms: /NOLOG, /QUIET. Example:
+          rename /nolist *.txt ~/textfiles/
+
+   Reminder: Every switch starts with a slash (/) and must be preceded by
+   a space.
+
+New RENAME Features for C-Kermit 9.0
+
+   A series of new options (switches) have been added to let you change
+   the names of multiple files at once by case conversion, string
+   substitution, or character-set conversion, and optionally also move
+   them to a different directory:
+
+     /LOWER:      Convert the filename to lowercase
+     /UPPER:      Convert the filename to uppercase
+     /CONVERT:    Change the filename's character encoding
+     /REPLACE:    Do string substitutions on the filename
+
+   If the source-file specification includes a path or directory, any
+   changes are applied to the filenames only, not to the directory or path
+   specification.
+
+   Since name changes, when applied to many files at once, can have
+   consequences that are not easily undone, there are also some new
+   controls, safeguards, and conveniences:
+
+   RENAME /SIMULATE
+          This switch tells Kermit to show you what the RENAME command
+          would do without actually doing it. /SIMULATE implies /LIST.
+
+   RENAME /COLLISION:{FAIL,SKIP,OVERWRITE}
+          This switch governs Kermit's behavior when renaming multiple
+          files, and any of the names would collide with the name of a
+          file that already exists. The default, for compatibility with
+          earlier releases of C-Kermit, is OVERWRITE, i.e. write over the
+          existing file. The other two protect existing files. SKIP means
+          to skip (not rename) the file that would cause the collision,
+          and proceed to the next file, if any. FAIL means that no files
+          will be renamed if there would be any collisions; for this
+          Kermit makes two passes, checking each new name it constructs
+          for existence before starting the second pass (however, there is
+          no guarantee that in the second pass, it won't create the same
+          new name for more than one file; in that case, it will stop
+          before executing the second rename). Example:
+          rename /simulate /collision:proceed * ~/tmp/
+
+   Reminder: In switches such as /COLLISION that take arguments
+   (operands), the switch name and its argument(s) are separated by a
+   colon (:) with no intervening spaces. Also remember that Kermit
+   keywords can always be abbreviated by leaving off characters from the
+   right, as long as the result is still unique in its context. Thus "ren
+   /col:f" would be equivalent to "rename /collision:fail".
+
+   You can change the following preferences for the RENAME command with
+   the new SET RENAME command:
+
+   SET RENAME LIST { ON, OFF }
+          Tells the RENAME command whether to list its actions if you
+          don't include a /LIST or /NOLIST or equivalent switch.
+
+   SET RENAME COLLISION { FAIL, OVERWRITE, SKIP }
+          Tells the RENAME command how to handle filename collisions in
+          the absence of a /COLLISION switch. That is, it replaces the
+          default action of OVERWRITE with action of your choosing, which
+          is then used in any RENAME command that does not include an
+          explicit /COLLISION switch.
+
+   SHOW RENAME
+          Displays the current SET RENAME settings.
+
+Changing the Case of Filenames
+
+   RENAME /UPPER:{ALL,LOWER} filespec [ directory ]
+          RENAME /LOWER:{ALL,UPPER} filespec [ directory ]
+          These switches let you change the alphabetic case of letters in
+          all the files whose names match the filespec. If a directory
+          name is given after the filespec, then the files are also moved
+          to the given directory.
+
+   By default, all files that match the given filespec have their names
+   changed (if necessary). This is what the ALL argument means, e.g.:
+
+     RENAME /LOWER:ALL *
+     RENAME /LOWER *
+
+   You can use either form: RENAME /LOWER is equivalent to RENAME
+   /LOWER:ALL. The other argument (/LOWER:UPPER or /UPPER:LOWER) means to
+   leave mixed-case filenames alone, and rename only those files whose
+   names contain letters of only the given case. Examples:
+
+   RENAME /UPPER:ALL foo.bar
+          Changes the filename to FOO.BAR.
+
+   RENAME /UPPER foo.bar
+          Same as "rename /upper:all foo.bar".
+
+   RENAME /UPPER foo.bar ~/old/
+          Renames foo.bar to FOO.BAR and moves it to the user's old
+          directory (Unix).
+
+   RENAME /LOWER *
+          Changes the names of all files to have only lowercase letters.
+
+   RENAME /LOWER:UPPER *
+          Changes the names of only those files whose names contain no
+          lowercase letters to have only lowercase letters. For example,
+          FOO.BAR would be changed, Foo.Bar would not be changed. foo.bar
+          would not be changed either because it's already all lowercase.
+
+   RENAME /LOWER:UPPER * ~/new/
+          Same as the previous example, but also moves each file to the
+          user's new directory (whether it was renamed or not).
+
+   Case conversion works reliably for ASCII characters only. Kermit uses
+   the C library for this, which on any given platform might or might not
+   handle non-ASCII letters, and if it does, then how it works would
+   normally depend on your locale definitions (the LC_CTYPE and/or LANG
+   environment variable in Unix). When non-ASCII letters are not handled
+   by the C library, the RENAME command does change their case. For
+   example, Olga_Tañón.txt might become OLGA_TAñóN.TXT.
+
+String Replacement in Filenames
+
+   The RENAME command also lets you change filenames by string
+   substitution.
+
+   RENAME /FIXSPACES[:String] filespec [ directory ]
+          Replaces all spaces in each matching filename by the given
+          string, if any, or if none is given, by underscore. Examples:
+
+     RENAME /FIX *
+     RENAME /FIXSPACES:_ *
+     RENAME /FIXSPACES:"" *
+     RENAME /FIXSPACES:<040> *
+
+          The first two are equivalent, replacing each space with
+          underscore; a file called "My Favorite Photo.jpg" becomes
+          "My_Favorite_Photo.jpg". The third example removes all spaces
+          ("MyFavoritePhoto.jpg"). The fourth replaces each space with the
+          string "<040>" ("My<040>Favorite<040>Photo.jpg").
+
+   RENAME /REPLACE:{{String1}{String2}} filespec [ directory ]
+          Renames each matching file by changing occurrences of String1 in
+          its name to String2. If a directory specification is included,
+          the file is also moved to the given directory (even if the name
+          was not changed). Note that in this case, the curly braces are
+          part of the command. Example:
+
+     RENAME /REPLACE:{{.jpeg}{.jpg}} *
+
+          changes all *.jpeg files to *.jpg.
+
+   By default, RENAME /REPLACE changes all occurrences of String1 in each
+   filename to String2 so, for example, if you had a file called
+   abcjpegxyz.jpeg, the command just shown would change its name to
+   abcjpgxyz.jpg.
+
+   For greater control and flexibility, the /REPLACE: switch argument can
+   take several distinct forms:
+
+   RENAME /REPLACE:String1 filespec [ directory ]
+          This means to remove all occurrences of String1 from the given
+          filenames name. It is equivalent to /REPLACE:{{String1}{}}. A
+          handy use for this option is to remove spaces from filenames.
+
+   RENAME /REPLACE:{{String1}{String2}} filespec [ directory ]
+          As already noted, this replaces every occurrence of String1 with
+          String2 in each filename. Alphabetic case in string matching is
+          done according to the current SET CASE setting.
+
+   RENAME /REPLACE:{{ }{_}} filespec [ directory ]
+          This replaces all spaces in the given filenames with underscore,
+          equivalent to RENAME /FIXSPACES.
+
+   RENAME /REPLACE:{{String1}{String2}{Options}} filespec [ directory ]
+          Options can be included that add more control to the process.
+          The option string is a sequence of characters; each character in
+          the string is an option. The choices are:
+
+   A String matching is to be case-sensitive, regardless of SET CASE.
+   a String matching is to be case-independent, regardless of SET CASE.
+   ^ String replacement will occur only at the beginning of the filename.
+   $ String replacement will occur only at the end of the filename.
+   1 Only the first occurrence of the string will be replaced.
+   2 Only the second occurrence of the string will be replaced.
+   3 4 5 6 7 8 ...
+   9 Only the ninth occurrence of the string will be replaced.
+   - (hyphen, minus sign) Before a digit: occurrences will be counted from
+   the right.
+   ~ (tilde) Before digit or minus sign: all occurrences but the given one
+   will be replaced.
+
+   The tilde modifier works only with single-byte character sets such as
+   ASCII, CP437, ISO 8859-1, etc, but not with multibyte character sets
+   such as UCS2, UTF8, or any of the Japanese Kanji sets.
+
+   Here are some examples showing how to use the /REPLACE options:
+
+   RENAME /REPLACE:{{foo}{bar}{^}} *
+          For all files whose names start with "foo", replaces the "foo"
+          at the beginning with "bar".
+
+   RENAME /REPLACE:{{}{New-}{^}} *
+          Prepends "New-" to the name of each file.
+
+   RENAME /REPLACE:{{.jpeg}{.jpg}{$}} *
+          Replaces ".jpeg" at the end of each filename with ".jpg".
+
+   RENAME /REPLACE:{{}{-Old}{$}} *
+          Appends "-Old" to the name of each file.
+
+   RENAME /REPLACE:{{foo}{bar}{a}} *
+          Replaces "foo", "FOO", "Foo", "fOO", etc, with "bar" in each
+          filename.
+
+   RENAME /REPLACE:{{foo}{bar}{A}} *
+          Replaces only (lowercase) "foo" in filenames with "bar".
+
+   RENAME /REPLACE:{{a}{XX}} *
+          Changes every "a" to "XX". For example a file called "a.a.a.a"
+          would become "XX.XX.XX.XX".
+
+   RENAME /REPLACE:{{a}{X}{2}}
+          Changes only the second "a" to "X". For example a file called
+          "a.a.a.a" would become "a.X.a.a".
+
+   RENAME /REPLACE:{{a}{X}{-1}}
+          Changes only the final "a" in the filename (it doesn't have to
+          be at the end) to "X". For example a file called "a.b.a.c.a.d"
+          would become "a.b.a.c.X.d".
+
+   RENAME /REPLACE:{{foo}{NOTFOO}{-2}}
+          Changes the second-to-last "foo" (if any) in the filename to
+          "NOTFOO".
+
+   RENAME /REPLACE:{{foo}{}{-2}}
+          Deletes the second-to-last "foo" (if any) from the filename.
+
+   RENAME /REPLACE:{{.}{_}{~1}}
+          Changes all but the first period to an underscore; for example,
+          "a.b.c.d.e" would become "a.b_c_d_e".
+
+   RENAME /REPLACE:{{.}{_}{~-1}}
+          Changes all but the final period to an underscore; for example,
+          "a.b.c.d.e" would become "a_b_c_d.e".
+
+   In the Options field, digits (and their modifiers), ^, and $ are
+   mutually exclusive. If you include more than one of these in the option
+   string, only the last one is used. Similarly for 'a' and 'A':
+
+   RENAME /REPLACE:{{foo}{bar}{Aa2$^}} *
+          This replaces "foo" with "bar" no matter what combination of
+          upper and lower case letters are used in "foo" ('a' overrides
+          'A' in the option string), but only if "foo" is at the beginning
+          of the filename ('^' overrides '$' and '2').
+
+   If you give an /UPPER or /LOWER switch and a /REPLACE switch in the
+   same RENAME command, the /REPLACE action occurs first, then the case
+   conversion:
+
+   RENAME /REPLACE:{{foo}{bar}} /UPPER * /tmp
+          For each file: changes all occurrences of "foo" in the name to
+          "bar", then converts the result to uppercase, and then moves the
+          file to the /tmp directory. So (for example) "foot.txt" would
+          become "/tmp/BART.TXT".
+
+Changing the Character Encoding of Filenames
+
+   As you know, text is represented on the computer as a series of
+   numbers, with a given number corresponding to a given character
+   according to some convention or standard. Filenames are represented the
+   same way. The trouble is, different computers, or even different
+   applications on the same computer, might use different standards or
+   conventions ("character sets") for representing the same characters.
+   Usually ASCII is safe, but anything beyond that -- non-ASCII characters
+   such as accented or non-Roman letters -- is likely to vary. Sometimes
+   you have text that's in the "wrong" character set and you need to
+   convert it to something you can can use. Kermit has always been able to
+   handle this as part of file transfer and terminal emulation, as well as
+   being able to convert text files locally with its TRANSLATE command.
+   Now there's a way to convert filenames too, for example after copying
+   files from a CD that uses a different encoding:
+
+   RENAME /CONVERT:charset1:charset2 filespec [ directory ]
+          Converts filenames from the first character set to the second
+          one. The two character sets can be chosen from the SET FILE
+          CHARACTER-SET list; for complete details see [68]this page. For
+          example suppose you have a file called "Olga_Tañón.txt" on a
+          computer where ISO 8859-1 Latin Alphabet 1 is used, and you have
+          transported it (e.g. on CDROM) to another computer where the
+          text encoding is UTF8. Maybe you also have a lot of other files
+          with similar names in the same directory. You can convert the
+          filenames to UTF8 like this:
+
+     RENAME /CONVERT:latin1:utf8 *
+
+   /CONVERT can not be combined with /UPPER, /LOWER, or /REPLACE.
+
+   You should NOT use UCS2 for filenames since this encoding is not
+   compatible with C strings used in Unix and elsewhere.
+
+   RENAME /CONVERT affects only the filename, not the file's contents. You
+   can use the TRANSLATE command to convert the encoding of the contents
+   of a text file.
+
+Other New Features
+
+   See the [69]C-Kermit Daily Builds page for details. Very briefly:
+
+     * Perhaps most important, modernized makefile targets for the major
+       Unix platforms: Linux, Mac OS X, AIX, Solaris, etc. These are
+       somewhat automated; not autoconf exactly, but they cut down
+       significantly on redundant targets. For example, one single "linux"
+       target works on many (hopefully all) different Linux
+       configurations, where before different targets were required for
+       different combinations of (e.g.) curses / ncurses / no curses;
+       32-bit / 64-bit; different feature sets and library locations.
+       (Separate targets are still required for Kerberos and/or SSL
+       builds, but they are "subroutinized".)
+     * Bigger buffers, more storage for commands, macros, scripts,
+       strings, and filename expansion in 64-bit versions and in 32-bit
+       versions that support large files.
+     * User-settable FTP timeout, works on both the data and control
+       connection.
+     * FTP access to ports higher than 16383.
+     * Built-in FTP client for VMS. This is the [70]same FTP client Unix
+       C-Kermit has had since version 8.0, minimally adapted to VMS by
+       SMS, supporting binary and Stream_LF file transfer only (in other
+       words, nothing to handle RMS files), but otherwise fully functional
+       (and scriptable) and theoretically capable of making connections
+       secured by SSL (at least it compiles and links OK with SSL - HP SSL
+       1.3 in this case).
+     * Large file support in VMS, also by SMS. Alpha and Itanium only (not
+       VAX). VMS C-Kermit was already able to transfer large files, but
+       the file-transfer display (numbers and progress bar) and statistics
+       were wrong because they used ints. In the present Alpha test
+       release, this is an optional feature requested by including the "f"
+       option in P1.
+     * New PUTENV command that allows Kermit to pass environment variables
+       to subprocesses (Unix only, "help putenv").
+     * New TOUCH command, many file selection options ("help touch").
+     * New DIRECTORY command options and switches (/TOP, /COUNT;
+       HDIRECTORY, WDIRECTORY...). To see the ten biggest files in the
+       current directory: "dir /top:10 /sort:size /reverse *" or
+       equivalently, "hdir /top:10 *". WDIR lists files in reverse
+       chronological order, shorthand for "dir /sort:date /reverse".
+     * New command FSEEK /FIND:string-or-pattern, seeks to the first line
+       in an FOPEN'd file that contains the given string or matches the
+       given pattern. Example: Suppose you have a file of lines like this:
+
+     quantity   description...
+       in which the first "word" is a number, followed by a description
+       (for example, the name of an item). Here is how to use FSEEK to
+       quickly get the total quantity of any given item, which is passed
+       as a parameter (either a literal string or a pattern) on the
+       command line:
+
+#!/usr/local/bin/kermit +
+if not def \%1 exit 1 Usage: \fbasename(\%0) string-or-pattern
+
+.filename = /usr/local/data/items.log        # Substitute the actual filename
+set case off                                 # Searches are case-independent
+fopen /read \%c \m(filename)                 # Open the file
+if fail exit 1 "\m(filename): \v(errstring)" # Fail: exit with error message
+.total = 0                                   # OK: Initialize the total
+echo Searching "\%1"...
+
+while true {
+    fseek /line /relative /find:\%1 \%c 0    # Get next line that has target
+    if fail break                            # Failure indicates EOF
+    fread /line \%c line                     # Read it
+    if fail break                            # (shouldn't happen)
+    increment total \fword(\m(line),1)       # Increment the total
+}
+fclose \%c                                   # Close the file
+echo Total for "\%1" : \m(total)             # Print the result
+exit 0
+
+       The syntax of the FSEEK command in this example indicates that each
+       search should start relative to the current file line. Since Kermit
+       is an interpretive language, FSEEK is a lot faster than FREAD'ing
+       each line and checking it for the target, especially for big files.
+       An especially handy use for FSEEK is for use with potentially huge
+       sequentially timestamped logs, to seek directly to the date-time
+       where you want to start processing. Some other improvements for the
+       FOPEN/FREAD/FWRITE/FCLOSE family of commands are included also
+       (performance, bug fixes, convenience features), listed in the
+       [71]change log. (Prior to 9.0.299 Alpha.02, the FSEEK /FIND:
+       command always started from the top.)
+     * MIME synonyms for character-set names: A new equivalence between
+       MIME names and Kermit names for character sets, with a new table
+       showing the supported sets [72]HERE (this feature is also
+       illustrated in the [73]Weblog script).
+     * Unix C-Kermit SET TERMINAL TYPE now passes its arguments to
+       subprocesses as an environment variable.
+     * SET SESSION-LOG TEXT now strips out ANSI escape sequences from the
+       session log.
+     * For interacting with POP servers over clear-text or SSL-secured
+       connections:
+          + New SSL and TLS "raw" connections (no Telnet protocol).
+          + New INPUT command options for reading and capturing (perhaps
+            while scanning) continuous incoming text, such as INPUT
+            /NOWRAP (explained [74]HERE).
+          + New \femailaddress() command to extract the e-mail address
+            from an Internet mail message To: or From: line, used in
+            fetching mail from POP servers.
+          + Improved date parsing commands and functions for parsing the
+            different date formats that can appear in e-mail.
+          + Production scripts for fetching mail from a secure POP server,
+            available [75]HERE.
+     * Various features added to make Kermit more useful for writing CGI
+       scripts such as INPUT /COUNT:n to INPUT exactly n characters
+       (useful for reading form data).
+     * New \fpictureinfo() function for getting orientation and dimensions
+       of JPG and GIF images, described [76]HERE.
+     * New \fgetpidinfo() function for testing whether a given process
+       exists.
+     * \fkwdvalue() function fixed to allow multiword values.
+     * New function \fcount(s1,s2) to tell the number of occurrences of s1
+       in s2.
+     * New \flopx() function returns rightmost field from string (such as
+       a file's extension).
+     * New function \ffunction(s1) to tell whether a built-in s1 function
+       exists.
+     * New \fsqueeze(s1) function removes leading and trailing whitespace
+       from string s1, changes tabs to spaces, squeezing each run of
+       repeated whitespace characters to a single space.
+     * Compact substring notation: \s(somestring[12:18]) is the same as
+       \fsubstring(\m(somestring),12,18), i.e. the substring starting at
+       position 12, 18 characters long. \s(somestring[12_18]) means
+       characters 12 through 18 of the string (7 characters). Also,
+       \s(somestring[17.]) returns character number 17 of somestring.
+     * The string indexing functions now accept an optional trailing
+       argument specifying the occurrence number of the target string.
+       Likewise, \fword() can fetch words from the right as well as the
+       left.
+     * The COPY command in Unix C-Kermit has a new /PRESERVE switch,
+       equivalent to Unix "cp -p".
+     * ASKQ /ECHO:c can be used to make the characters the user types echo
+       as the character c, e.g. asterisk when typing a password.
+     * IF LINK filename to test if the filename is a symlink.
+     * Ctrl-K, when typed at the command parser, replaces itself with most
+       recently entered file specification.
+     * In Unix, the ability to log a terminal session to a serial port,
+       for use with speaking devices or serial printers; described
+       [77]HERE. Also for the same purpose, SET SESSION-LOG
+       NULL-PADDED-LINES for a speech synthesizer than needed this.
+     * Adaptation to OpenSSL 0.9.8 and 1.0.0.
+     * Lifted the restriction on having a remote Kermit program send
+       REMOTE commands to the local. A very big ex-client needed to be
+       able to do this (branches would connect to headquarters and upload
+       files; HQ would then download patches, a REMOTE HOST command was
+       necessary to allow the remote headquarters machines to install the
+       patches on the local client; of course the client first has to
+       ENABLE HOST because this is a risky scenario). The reason for the
+       restriction was that the server, upon receiving any REMOTE command
+       would send the results (output) back to the client as a file
+       transfer with "destination screen", but of course the remote has no
+       screen.
+     * Added XMESSAGE, which is to [78]MESSAGE as XECHO is ECHO: it
+       outputs a string with no line terminator DEBUG MESSAGE is ON.
+     * Fixed \frecurse() to not dump core when invoked with no arguments.
+     * Improved text for HELP FUNCTION SPLIT and HELP FUNCTION WORD.
+     * Patches for Debian 6.0 "Squeeze" from Ian Beckwith.
+     * \fcontents(\&a[3]) got an error if the array was declared but its
+       dimension was less than 3. Now it simply returns and empty string.
+     * \fsplit(), when parsing lines from CSV and TSV files, was treating
+       backslash in the data the same way it treats backslash in Kermit
+       commands. This was fixed to treat backslash like any other
+       character.
+     * Builds for Solaris 9 and later now use streams ptys rather then the
+       old BSD-style ptys. Thanks to Gary Mills for this one, who noticed
+       that he couldn't have more than 48 C-Kermit SSH sessions going at
+       once and figured out why.
+     * As noted [79]below DES encryption is being retired from many
+       platforms and libraries that once used it. I changed the Solaris
+       and Linux OpenSSL builds to account for this by testing for it. I
+       probably should also add a OMITDES option to omit DES even if it is
+       installed, but "KFLAGS=-UCK_DES" seems to do the job for now.
+     * I changed the Linux build to test for the OpenSSL version (like the
+       Solaris version already did), rather than assuming OpenSSL 0.9.7.
+     * A couple minor changes for Tru64 Unix 5.1B from Steven Schweda but
+       we still have some trouble on that platform. As a workaround "make
+       osf1" can be used there.
+     * Unix makefile and man page are now included in the Zip
+       distribution.
+     * \fjoin(), which is the inverse function of fsplit() now accepts CSV
+       and TSV as a second argument, to transform an array into a
+       comma-separated or tab-separated value list, as described [80]HERE.
+     * Even in 2010, Unix distributions continue to change their UUCP
+       lockfile conventions. C-Kermit 9.0 contains support from Joop
+       Boonen for OpenSuSE >= 11.3 and recent Debian, which no longer have
+       baudboy.h, which first appeared in Red Hat 7.2 in 2003.
+     * From Lewis McCarthy:
+
+     Based on code inspection, C-Kermit appears to have an SSL-related
+     security vulnerability analogous to that identified as CVE-2009-3767
+     (see e.g.
+     [81]http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-3767).
+
+     I'm attaching a patch for this issue relative to the revision of
+     ck_ssl.c obtained from a copy of
+     [82]http://www.columbia.edu/kermit/ftp/test/tar/x.zip downloaded on
+     2010/07/30, which I believe is the latest.
+     When this flaw was first widely publicized at last year's Black Hat
+     conference, it was claimed that some public certificate authorities
+     had indeed issued certificates that could be used to exploit this
+     class of vulnerability. As far as I know they have not revealed
+     specifically which public CA(s) had been found issuing such
+     certificates. Some references:
+          + [83]http://www.mseclab.com/?p=180
+          + [84]http://www.theregister.co.uk/2009/07/30/universal_ssl_cert
+            ificate/
+
+     * Peter Eichhorn reported that "RENAME ../x ." didn't work; fixed
+       now.
+     * If only one file is FOPEN'd, FCLOSE given with no arguments would
+       close it; this was a "convenience feature" that turned out to be
+       dangerous. For safety FCLOSE has to require a specific channel
+       number or the word ALL.
+     * Added \fstrcmp(s1,s2,case,start,length), which has the advantage
+       over IF EQU,LGT,LLT that case sensitivity can be specified as a
+       function arg, and also substrings can be specified.
+     * New built-in functions:
+
+        \fcvtcsets(string,cs1,cs2)
+                Function to convert a string from one character set to
+                another.
+
+        \fdecodehex(string[,prefix])
+                Function to decode a string containing hex escapes.
+
+        \fstringtype(string)
+                Function to tell whether a string is 7-bit, 8-bit, or
+                UTF-8.
+
+       For the motivation for these features and an application that uses
+       them to analyze web logs, see the Weblog script below.
+     *
+
+        Lazy IF Conditions: Now you can do this:
+                define foo some number
+                if foo command
+
+        instead of this:
+                define foo some number
+                if \m(foo) command
+
+       Of course the old way still works too. But watch out because if the
+       variable name is the same as a symbolic IF condition (for example
+       COUNT), it won't do what you expected. (IF COUNT was used for loop
+       control in early versions of MS-DOS Kermit, before it got real FOR
+       and WHILE loops; it was added to C-Kermit for compatibility, and it
+       can't be removed because that could break existing scripts).
+     * Escape sequences are now stripped from text-mode session logs not
+       only in CONNECT sessions but also in whatever is logged by the
+       INPUT command; described in the [85]next section.
+     * New commands for selectively issuing progress or debugging messages
+       from scripts, also described in the next section.
+     * Fix from [86]John Dunlap to prevent the fixed packet-timeout
+       interval from going to an unexpected value.
+     * Alpha.04 fixes a problem with FTP connections made from 64-bit Unix
+       platforms. All the other changes in this section were to Alpha.03.
+     * Relaunching a closed SSH connection with the CONNECT command is now
+       possible, as it always has been with Telnet and other connection
+       types; suggested by Peter Eichhorn (needs testing).
+     * A symbol conflict fixed that prevented successful build on
+       [87]FreeBSD 8.0.
+     * Fixes from Christian Corti for building on SunOS 4.1.
+     * New aixg target for building on AIX with gcc.
+     * New aix+ibmssl target. This is nice because the IBM-supplied SSL
+       libraries and header files are in a known location; no need to
+       [88]set environment variables giving their locations.
+     * "Large File Support" is now included by default on Alpha and IA64
+       hardware on VMS 7.3 and later, and it should work much better than
+       before.
+     * Kermit's internal FTP client is now included by default in any
+       build that also includes TCP/IP networking. At present, the FTP
+       client seems to work well for binary-mode transfers; text (ASCII)
+       mode transfers still need some work. In builds that also include
+       Secure Sockets Layer (SSL) security (next item) the FTP client
+       should be able to make securely authenticated and encrypted
+       connections.
+     * In network builds that request OpenSSL support, e.g.:
+
+     $ @ckvker  ""  ""  "CK_SSL"
+       the OpenSSL version is detected automatically and the appropriate
+       compile-time options are emitted (such as
+       OPENSSL_DISABLE_OLD_DES_SUPPORT).
+     * Preliminary / limited support for the ODS-5 file system on VMS 7.2
+       and later, Alpha and Itanium only (needs testing): Filenames can be
+       mixed case and can be longer.
+     * Support for older and older VMS versions.
+     * In the VMS build procedure, CKVKER.COM, the "i" option in P1 now
+       means don't include the internal FTP client, and the "f" option
+       means do not include "Large File" support. Large File support in
+       VMS really only applies to the file-transfer display and
+       statistics, which would go out of whack as soon as the byte count
+       overflowed 31 bits because this is C-Kermit, built with the C
+       compiler and the C library (runtime system), which did not support
+       long integers until VMS 7.3.
+     * The [89]LISP Operator ROUND now takes an optional second argument
+       that specifies the number of places to round to, e.g.
+       (ROUND dollars 2) rounds dollars to 2 decimal places.
+     * Improved pattern matching in many commands for both strings and
+       filenames.
+     * Various minor new features, plus numerous bug fixes and speedups.
+
+Incompatibilities
+
+   A top priority for new Kermit software releases has always been
+   backwards compatibility. A script written for a previous Kermit release
+   should run the same way in the new release.
+
+   There's one exception this time. The [90]\fsplit() function is
+   incredibly handy, it can do almost anything, up to and including
+   parsing a LISP program (the underlying code is the basis of the
+   [91]S-Expression interpreter). But did you ever try to use it to parse
+   (say) a Tab-Separated-List (TSV file) or Comma-Separated-List (CSV)? It
+   works as expected as long as the data contains only 7-bit characters.
+   But if your data contains (say) Spanish or German or Russian text
+   written in an 8-bit character set such as ISO 8859-1, every 8-bit
+   character (any value 128-255) is treated as a break character. This is
+   fixed in C-Kermit 9.0 by treating all 8-bit bytes as "include"
+   characters rather than break characters, a total reversal of past
+   behavior. I don't think it will affect anyone though, because if this
+   had happened to anyone, I would have heard about it!
+
+   Since most standard 8-bit character sets have control characters in
+   positions 128-160, it might have made sense to keep 128-160 in the
+   break set, but with the proliferation of Microsoft Windows code pages,
+   there is no telling which 8-bit character is likely to be some kind of
+   text, e.g. "smart quotes" or East European or Turkish accented letters.
+
+What's Not In C-Kermit 9.0
+
+   Some large projects that were contemplated have not been done,
+   including:
+     * IPv6. Honestly, there has been zero demand for this, and it would
+       be a lot of work and disruption to the code base. Volunteers
+       welcome, I guess. It could be a CS project.
+     * A database interface - MySQL or ODBC. For this one, there is some
+       demand but I haven't had a chance to even look into it.
+     * There's a looming issue with DES encryption; major vendors are
+       removing it from their platforms, starting with Apple in Mac OS X
+       10.6, with Microsoft to follow suit. A secure version of Kermit can
+       be built without DES, but in limited testing successful connections
+       were spotty (e.g. with Kerberos 5).
+     * Cleaning up the Unix makefile. It has 25 years' worth of targets in
+       it. It is very likely safe to remove most of them, since (a) most
+       old platforms have gone away by now, or have been upgraded, due to
+       hacking vulnerabilities; (b) the market has consolidated
+       considerably; and (c) most of the new features of C-Kermit 9.0,
+       such as large files, won't be of any use on older platforms and
+       previous C-Kermit versions will remain available.
+     * Packages. Everybody wants an install package custom made for their
+       own computer, Linux RPMs being the prime example but far from the
+       only one. These will come, I suppose (especially with some Linux
+       sites having a policy against installing any application that does
+       not come as an RPM). In the meantime, here's a page that describes
+       some Kermit-specific issues in package construction:
+       [92]ckpackages.html.
+
+And a Loose End...
+Using External File-Transfer Protocols on Secure Connections
+
+   After C-Kermit 8.0.212 Dev.27 (2006/12/22), I spent a big chunk of time
+   trying to solve a particular problem that some of you have complained
+   about and others might be familiar with: If you use C-Kermit to make a
+   secure Telnet connection to another host (e.g. with Telnet SSL/TLS,
+   Kerberos, or SRP) and then attempt to transfer a file using an external
+   protocol such as Zmodem, it doesn't work.
+
+   That's because as coded (through 8.0.211), C-Kermit simply starts the
+   external protocol in a fork with its standard i/o redirected to the
+   connection. This completely bypasses the encryption and decryption that
+   is done by C-Kermit itself, and of course it doesn't work. The same
+   thing occurs if you use the REDIRECT command. The routine that handles
+   this is ttruncmd() in ckutio.c.
+
+   In order to allow (say) Zmodem transfers on secure connections, it is
+   necessary for C-Kermit to interpose itself between the external Zmodem
+   program and the connection, decrypting the incoming stream before
+   feeding it to Zmodem and encrypting Zmodem's output before sending out
+   the connection.
+
+   In principal, this is simple enough. We open a pseudoterminal pair
+   ("master" and "slave") for Zmodem's i/o and we create a fork and start
+   Zmodem in it; we read from the fork pty's standard output, encrypt, and
+   send to the net; we read from the net, decrypt, and write to the fork
+   pty's standard input.
+
+   In practice, it's not so simple. First of all, pseudoterminals (ptys)
+   don't seem to interface correctly with certain crucial APIs, at least
+   not in the OS's I have tried (Mac OS X, Linux, NetBSD, etc), such as
+   select(). And i/o with the pty often - perhaps always - fails to
+   indicate errors when they occur; for example, when the fork has exited.
+
+   But, even after coding around the apparent uselessness of select() for
+   multiplexing pty and net, and using various tricks to detect when the
+   external protocol exits and what its exit status is, I'm still left
+   with a show-stopping problem: I just simply can not download (receive)
+   a file with Zmodem, which is the main thing that people would probably
+   want to do. I can send files just fine, but not receive. The incoming
+   stream is delivered to Zmodem (to the pty slave) but upon arrival at
+   the Zmodem process itself, pieces are always missing and/or corrupt.
+   Yet I can receive files just fine if I use Kermit itself (C-Kermit or
+   G-Kermit) as the external protocol, rather than Zmodem.
+
+   I can think of two reasons why this might be the case:
+
+    1. Zmodem sends all 8-bit bytes and control codes in the clear, and
+       maybe the pty is choking on them because it thinks it is a real
+       terminal.
+
+   But Zmodem puts its controlling terminal into raw mode. And C-Kermit
+   puts the pty into raw mode too, just for good measure. If any 0xFF
+   codes are in the Zmodem data stream, and it's a Telnet session, Kermit
+   does any needed byte stuffing/unstuffing automatically. Anyway, if I
+   tell Zmodem to prefix everything, it makes no difference.
+
+    2. Zmodem is a streaming protocol and perhaps the pty driver can't
+       keep up with a sustained stream of input at network speeds. What
+       would be the method of flow control?
+
+   I can vary the size of the i/o buffers used for writing to the pty, and
+   get different effects, but I am not able to get a clean download, no
+   matter what buffer size I use. write()'ing to the pty does not return
+   an error, and I can't see the errors because they happen on the master
+   side. It's as if the path between the pty slave and master lacks flow
+   control; I deliver a valid data stream to the pty slave and the master
+   gets bits and pieces. This impression is bolstered somewhat by the
+   "[93]man 7 pty" page in HP-UX, which talks about some special modes for
+   ptys that turn off all termio processing and guarantee a
+   flow-controlled reliable stream of bytes in both directions - a feature
+   that seems to be specific to HP-UX, and exactly the one we need
+   everywhere.
+
+   Well, in Pass One I used C-Kermit's existing pty routines from
+   ckupty.[ch], which are well-proven in terms of portability and of
+   actually working. They are currently used by SET HOST /PTY for making
+   terminal connections to external processes. But these routines are
+   written on the assumption that the pty is to be accessed interactively,
+   and maybe they are setting the fork/pty arrangement up in such a way
+   that that's not suitable for file transfer. The Pass One routine is
+   called xttptycmd() in ckutio.c.
+
+   So in Pass Two I made a second copy of the routine, yttptycmd(), that
+   manages the pty and fork itself, so all the code is in one place and
+   it's simple and understandable. But it still doesn't work for Zmodem
+   downloads. In this routine, I use openpty() to get the pty pair, which
+   is not portable, so I can have access to both the master and slave pty
+   file descriptors. This version can be used only a platforms that have
+   openpty(): Linux, Mac OS X, NetBSD, etc.
+
+   In Pass Three, zttptycmd(), I tried using pipes instead of ptys, in
+   case ptys are simply not up to this task (but that can't be true
+   because if I make a Telnet or SSH connection into a host, I can send
+   files to it with Zmodem, and the remote Zmodem receiver is, indeed,
+   running on a pty). But pipes didn't work either.
+
+   In Pass Four, I extracted the relevant routines into a standalone
+   program based on yttptycmd() (the openpty() version, for simplicity),
+   which I tested on Mac OS X, the idea being to rule out any
+   "environmental" effects of running inside the C-Kermit process. There
+   was no difference -- Kermit transfers (with C-Kermit itself as the
+   external protocol) worked; Zmodem transfers (neither sz or lsz) did
+   not.
+
+   Well, it's a much longer story. As the external protocol, I've tried
+   rzsz, crzsz, and lrzsz. We know that some of these have quirks
+   regarding standard i/o, etc, which is one of the reasons for using ptys
+   in the first place, and i/o does work - just not reliably. Anyway, the
+   1100 lines or so of [94]ckc299.txt, starting just below where it says
+   "--- Dev.27 ---" tell the full story. At this point I have to give up
+   and move on; it might be more productive to let somebody else who has
+   more experience with ptys take a look at it - if indeed anyone still
+   cares about being able to do Zmodem transfers over secure Telnet
+   connections.
+
+   C-Kermit 9.0 contains the three new routines (and some auxiliary ones),
+   but they are not compiled or called unless you build it specially:
+
+     make targetname KFLAGS=-DXTTPTYCMD (builds with xttptycmd())
+     make targetname KFLAGS=-DYTTPTYCMD (builds with yttptycmd())
+     make targetname KFLAGS=-DZTTPTYCMD (builds with zttptycmd())
+
+   These are all in [95]ckutio.c. As noted, the second one works only for
+   Linux, FreeBSD, NetBSD, and Mac OS X, because it uses non-POSIX,
+   non-portable openpty(). If you want to try it on some other platform
+   that has openpty(), you can build it like this:
+
+     make targetname "KFLAGS=-DYTTPTYCMD -DHAVE_OPENPTY"
+
+   (and let me know, so I can have HAVE_OPENPTY predefined for that
+   platform too). The best strategy to get this working, I think, would be
+   to concentrate on yttptycmd(), which is the simpler of the two
+   pty-based routines. If it can be made to work, then we'll see if we can
+   retrofit it to use the ckupty.c routines so it will be portable to
+   non-BSD platforms.
+
+   By the way, if you build with any of [XYZ]TTPTYCMD defined, then the
+   selected routine will always be used in place of ttruncmd(). This is to
+   allow testing on all kinds of connections, not just secure ones, in
+   both local and remote mode. Once the thing works, if it ever does, I'll
+   add the appropriate tests and/or commands.
+
+   By default, in the initial test release, C-Kermit 9.0 uses ttruncmd()
+   on serial connections and ttyptycmd() on network connections. Even when
+   a network connection is not encrypted, Kermit still needs to handle the
+   network protocol, e.g. the quoting of 0xff bytes on Telnet connections.
+
+Demonstration: Fetch Mail from POP Server Secured by SSL
+
+   [96]pop.ksc is a fully elaborated production script for fetching one's
+   mail from a POP3 server over a connection secured by SSL. For
+   explanation and documentation, [97]CLICK HERE. [98]mailcheck is a
+   wrapper for the pop.ksc script, which collects your password one time,
+   and then checks for new mail every 5 minutes (or other selected
+   interval) and calls pop.ksc to fetch it if there is any.
+
+Demonstration: HP Switch Configuration Backup
+
+   A common use for Kermit software is to make automated backups of the
+   configuration of network switches and routers, such as those made by
+   Cisco or Hewlett-Packard (although [99]tftp can be used for this, it is
+   not available in all such devices; Kermit, however, works with those
+   that have tftp as well as those that don't).
+
+   Typically a backup can be done by making a Telnet, SSH, or serial
+   connection to the device with Kermit and giving a command such as "show
+   config" at the command-line prompt of the device with Kermit's session
+   log activated. The result is a list of the commands that were used to
+   establish the current configuration, suitable for feeding back to the
+   device's console (e.g. with C-Kermit's TRANSMIT command) to reestablish
+   the same configuration or to duplicate it on another device.
+
+   At an HP installation it was noted, however, that while the HP switches
+   (various ProCurve models) produced the desired list of commands, they
+   were interspersed with escape sequences for special effects, thus
+   rendering the recorded sessions unsuitable for feeding back into the
+   switches.
+
+   C-Kermit 9.0 introduces a new feature to strip the offending sequences
+   out of a session log, leaving just the text. The command SET
+   SESSION-LOG TEXT activates this feature. In C-Kermit 9.0 Alpha.02 and
+   earlier, escape sequence stripping occurred only while logging
+   interactive (CONNECT) sessions; beginning with Alpha.03 it is done also
+   for data that is read by INPUT commands and therefore works for scripts
+   too.
+
+   A sample HP Switch Configuration Backup script is [100]HERE, and its
+   data file is [101]HERE. This script also illustrates some other new
+   features of Alpha.03:
+
+   MESSAGE text
+          This lets you put debugging messages in your script that can be
+          displayed or not, according to SET DEBUG MESSAGE (below). This
+          way you don't have to change your script for debugging.  Hint:
+          In Unix, invoke the script like this:
+
+     $ DEBUG=1 scriptname arg1 arg2...
+
+          and then include the following command in your script:
+
+     if defined \$(DEBUG) set debug message on
+
+   XMESSAGE text
+          Like MESSAGE but prints the text with no line terminator, so it
+          can be continued by subsequent messages.
+
+   SET DEBUG MESSAGE { ON, OFF, STDERR }
+          ON means MESSAGE commands should print to standard output; OFF
+          means they shouldn't print anything; STDERR means the messages
+          should be printed to [102]stderr. DEBUG MESSAGE is OFF by
+          default, i.e. unless you SET it to ON or STDERR.
+
+   IF DEBUG command
+          Executes the command if SET DEBUG MESSAGE is not OFF.
+
+   The \v(lastcommand) variable
+          This variable contains the previous command. You can use it in
+          debugging and error message to show (for example) exactly what
+          the command was that just failed, without having to make a copy
+          of the command:
+
+set host somehost.somecompany.com
+if fail exit 1 "FATAL - \v(lastcommand)"
+
+          which, if the SET HOST command fails, prints "FATAL - set host
+          somehost.somecompany.com" and then exits with status 1 (which
+          normally indicates failure).
+
+Demonstration: HP iLO Blade Configuration
+
+   [103]THIS DOCUMENT describes a script in production use at Columbia
+   University for configuring and deploying racks full of HP blade servers
+   through their "integrated Lights Out" (iLO) management interface,
+   bypassing the tedious and error-prone process of configuring the
+   servers one by one through the vendor-provided point-and-click Web
+   interface, which is ill-suited to configuring large numbers of blades.
+   The script illustrates some of C-Kermit 9.0's new features; source code
+   is available through the link. The code is apt to change from time to
+   time as new requirements surface.
+
+Demonstration: IBM/Rolm/Siemens CBX Management
+
+   [104]THIS DOCUMENT describes a suite of scripts (some in production,
+   some in development) used to manage the Columbia campus 20,000-line
+   main telephone switch, along with about 10 satellite switches at
+   off-campus locations. These switches are 1980s technology*, their
+   management consoles are serial ports. Access is via Telnet to reverse
+   terminal servers. The scripts allow for interactive sessions as well as
+   automatic production (and in some cases formatting) of different
+   reports required by different groups at different intervals. These
+   scripts replace a whole assortment of ad-hoc ProComm ASPECT scripts
+   that were scattered all over the place, with passwords embedded. The
+   new scripts are intended to be run from a centralized server where
+   there is a single well-secured configuration file, and where they can
+   be used on demand, or in cron jobs. They are modular so code
+   duplication is minimal.
+   __________________________
+   *  Of course the University is deploying new technology but the but the
+   old system will be used in parallel for some time to come.
+
+Demonstration: CSV and TSV Files
+
+   Contents
+
+     * [105]Reading a CSV or TSV Record and Converting it to an Array
+     * [106]Using \fjoin() to create a Comma- or Tab-Separated Value List
+       from an Array
+     * [107]Using CSV or TSV Files
+
+   Comma-Separated Value (CSV) format is commonly output by spreadsheets
+   and databases when exporting data into plain-text files for import into
+   other applications. Here are the details:
+
+   Comma-Separated List Syntax
+
+    1. Each record is a series of fields.
+    2. Records are in whatever format is used by the underlying file
+       system for lines of text.
+    3. Fields within records are separated by commas, with zero or more
+       whitespace characters (space or tab) before and/or after the comma;
+       such whitespace is considered part of the separator.
+    4. Fields with embedded commas must be enclosed in ASCII doublequote
+       characters.
+    5. Fields with leading or trailing spaces must be enclosed in ASCII
+       doublequotes.
+    6. Any field may be enclosed in ASCII doublequotes.
+    7. Fields with embedded doublequotes must be enclosed in doublequotes
+       and each interior doublequote is doubled.
+
+   Here is an example:
+
+aaa, bbb, has spaces,,"ddd,eee,fff", " has spaces ","Muhammad ""The Greatest"" A
+li"
+
+   The first two are regular fields. The second is a field that has an
+   embedded space but in which any leading or trailing spaces are to be
+   ignored. The fourth is an empty field, but still a field. The fifth is
+   a field that contains embedded commas. The sixth has leading and
+   trailing spaces. The last field has embedded quotation marks.
+
+   Prior to C-Kermit 9.0 Alpha.06, C-Kermit did not handle CSV files
+   according to the specification above. Most seriously, there was no
+   provision for a separator to be surrounded by whitespace that was to be
+   considered part of the separator. Also there was no provision for
+   quoting doublequotes inside of a quoted string.
+
+Reading a CSV record
+
+   Now the \fsplit() function can handle any CSV-format string if you
+   include the symbolic include set "CSV" as the 4th parameter. To
+   illustrate, this program:
+
+def xx {
+   echo [\fcontents(\%1)]
+   .\%9 := \fsplit(\fcontents(\%1), &a, \44, CSV)
+   for \%i 1 \%9 1 { echo "\flpad(\%i,3). [\&a[\%i]]" }
+   echo "-----------"
+}
+xx {a,b,c}
+xx { a , b , c }
+xx { aaa,,ccc," with spaces ",zzz }
+xx { "1","2","3","","5" }
+xx { this is a single field }
+xx { this is one field, " and this is another  " }
+xx { name,"Mohammad ""The Greatest"" Ali", age, 67 }
+xx { """field enclosed in doublequotes""" }
+exit
+
+   gives the following results:
+
+[a,b,c]
+  1. [a]
+  2. [b]
+  3. [c]
+-----------
+[ a , b , c ]
+  1. [a]
+  2. [b]
+  3. [c]
+-----------
+[ aaa,,ccc," with spaces ",zzz ]
+  1. [aaa]
+  2. []
+  3. [ccc]
+  4. [ with spaces ]
+  5. [zzz]
+-----------
+[ "1","2","3","","5" ]
+  1. [1]
+  2. [2]
+  3. [3]
+  4. []
+  5. [5]
+-----------
+[ this is a single field ]
+  1. [this is a single field]
+-----------
+[ this is one field, " and this is another  " ]
+  1. [this is one field]
+  2. [ and this is another  ]
+-----------
+[ name,"Mohammad ""The Greatest"" Ali", age, 67 ]
+  1. [name]
+  2. [Mohammad "The Greatest" Ali]
+  3. [age]
+  4. [67]
+-----------
+[ """field enclosed in doublequotes""" ]
+  1. ["field enclosed in doublequotes"]
+-----------
+
+   The separator \44 (comma) must still be specified as the break set (3rd
+   \fsplit() parameter). When "CSV" is specified as the include set:
+     * The Grouping Mask is automatically set to 1 (which specifies that
+       the ASCII doublequote character (") is used for grouping;
+     * The Separator Flag is automatically set to 1 so that adjacent field
+       separators will not be collapsed;
+     * All bytes (values 0 through 255) other than the break character are
+       added to the include set;
+     * Any leading whitespace is stripped from the first element unless it
+       is enclosed in doublequotes;
+     * Any trailing whitespace is trimmed from the end of the last element
+       unless it is enclosed in doublequotes;
+     * If the separator character has any spaces or tabs preceding it or
+       following it, they are ignored and discarded;
+     * The separator character is treated as an ordinary data character if
+       it appears in a quoted field;
+     * A sequence of two doublequote characters ("") within a quoted field
+       is converted to a single doublequote.
+
+   There is also a new TSV symbolic include set, which is like CSV except
+   without the quoting rules or the stripping of whitespace around the
+   separator because, by definition, TSV fields do not contain tabs.
+
+   Of course you can specify any separator(s) you want with either the
+   CSV, TSV, or ALL symbolic include sets. For example, if you have a TSV
+   file in which you want the spaces around each Tab to be discarded, you
+   can use:
+
+\fsplit(variable, &a, \9, CSV)
+
+   \9 is Tab.
+
+   The new symbolic include sets can also be used with \fword(), which is
+   just like \fsplit() except that it retrieves the nth word from the
+   argument string, rather than an array of all the words. In C-Kermit you
+   can get information about these or any other functions with the HELP
+   FUNCTION command, e.g.:
+
+C-Kermit> help func word
+
+Function \fword(s1,n1,s2,s3,n2,n3) - Extracts a word from a string.
+    s1 = source string.
+    n1 = word number (1-based) counting from left; if negative, from right.
+    s2 = optional break set.
+    s3 = optional include set (or ALL, CSV, or TSV).
+    n2 = optional grouping mask.
+    n3 = optional separator flag:
+       0 = collapse adjacent separators;
+       1 = don't collapse adjacent separators.
+
+  \fword() returns the n1th "word" of the string s1, according to the
+  criteria specified by the other parameters.
+
+  The BREAK SET is the set of all characters that separate words. The
+  default break set is all characters except ASCII letters and digits.
+  ASCII (C0) control characters are treated as break characters by default,
+  as are spacing and punctuation characters, brackets, and so on, and
+  all 8-bit characters.
+
+  The INCLUDE SET is the set of characters that are to be treated as
+  parts of words even though they normally would be separators.  The
+  default include set is empty.  Three special symbolic include sets are
+  also allowed:
+
+    ALL (meaning include all bytes that are not in the break set)
+    CSV (special treatment for Comma-Separated-Value records)
+    TSV (special treatment for Tab-Separated-Value records)
+
+  For operating on 8-bit character sets, the include set should be ALL.
+
+  If the GROUPING MASK is given and is nonzero, words can be grouped by
+  quotes or brackets selected by the sum of the following:
+
+     1 = doublequotes:    "a b c"
+     2 = braces:          {a b c}
+     4 = apostrophes:     'a b c'
+     8 = parentheses:     (a b c)
+    16 = square brackets: [a b c]
+    32 = angle brackets:  <a b c>
+
+  Nesting is possible with {}()[]<> but not with quotes or apostrophes.
+
+Returns string:
+  Word number n1, if there is one, otherwise an empty string.
+
+Also see:
+  HELP FUNCTION SPLIT
+
+C-Kermit>
+
+Using \fjoin() to create Comma- or Tab-Separated Value Lists from Arrays
+
+   In C-Kermit 9.0, \fsplit()'s inverse function, [108]\fjoin() received
+   the capability of converting an array into a comma-separated or a
+   tab-separated value list. Thus, given a CSV, if you split it into an
+   array with \fsplit() and then join the array with \fjoin(), giving each
+   function the new CSV parameter in the appropriate argument position,
+   the result will be will be equivalent to the original, according to the
+   CSV definition. It might not be identical, because if the result had
+   extraneous spaces before or after the separating commas, these are
+   discarded, but that does not affect the elements themselves. The new
+   syntax for \fjoin() is:
+
+   \fjoin(&a,CSV)
+          Given the array \&a[] or any other valid array designator, joins
+          its elements into a comma-separated list according to the
+          [109]rules listed above.
+
+   \fjoin(&a,TSV)
+          Joins the elements of the given array into a tab-separated list,
+          also described above.
+
+   [110]Previous calling conventions for \fjoin() are undisturbed,
+   including the ability to specify a portion of an array, rather than the
+   whole array:
+
+declare \&a[] = 1 2 3 4 5 6 7 8 9
+echo \fjoin(&a[3:7],CSV)
+3,4,5,6,7
+
+   Using \fsplit() and \fjoin() it is now possible to convert a
+   comma-separated value list into a tab-separated value list, and vice
+   versa (which is not a simple matter of changing commas to tabs or vice
+   versa).
+
+Applications for CSV Files
+
+   Databases such as MS Access or MySQL can export tables or reports in
+   CSV format, and then Kermit can read the resulting CSV file and do
+   whatever you like with it; typically something that could not be done
+   with the database query language itself (or that you didn't know how to
+   do that way): create reports or datasets based on complex criteria or
+   procedures, edit or modify some fields, etc, and then use \fjoin() to
+   put each record back in CSV form so it can be reimported into a
+   spreadsheet or database.
+
+   Here is a simple example in which we purge all records of customers who
+   have two or more unpaid bills. The file is sorted so that each license
+   purchase record is followed by its annual maintenance payment records
+   in chronological order.
+
+#!/usr/local/bin/kermit
+.filename = somefile.csv        # Input file in CSV format
+fopen /read \%c \m(filename)    # Open it
+if fail exit                    # Don't go on if open failed
+copy \m(filename) ./new         # Make a copy of the file
+
+.oldserial = 00000000000        # Multiple records for each serial number
+.zeros = 0                      # Unpaid bill counter
+
+while true {                    # Loop
+    fread /line \%c line        # Get a record
+    if fail exit                # End of file
+    .n := \fsplit(\m(line),&a,\44,CSV)    # Split the fields into an array
+    if not equ "\m(oldserial)" "\&a[6]" { # Have new serial number?
+        # Remove all records for previous serial number
+        # if two or more bills were not paid...
+        if > \m(zeros) 1 {
+            grep /nomatch \m(oldserial) /output:./new2 ./new
+            rename ./new2 ./new
+        }
+        .oldserial := \&a[6]    # To detect next time serial number changes
+        .zeros = 0              # Reset unpaid bill counter
+    }
+    if equ "\&a[5]" "$0.00" {   # Element 5 is amount paid
+        increment zeros         # If it's zero, count it.
+    }
+}
+fclose \%c
+
+   Rewriting the file multiple times is inelegant, but this is a quick and
+   dirty use-once-and-discard script, so elegance doesn't count. The
+   example is interesting in that it purges certain records based on the
+   contents of other records. Maybe there is a way to do this directly
+   with SQL, but why use SQL when you can use Kermit?
+
+   Here is the same task but this time no shelling out, and this time we
+   do change and add some fields and then join the result back into a CSV
+   record and write it out to a new file. The object is to create a record
+   for each license that shows not only the date and purchase price of the
+   license but also the date and amount of the last maintenance payment,
+   and to add new fields for sorting by anniversary (month and day):
+
+#!usr/local/bin/kermit +
+cd ~/somedirectory                      # CD to appropriate directory
+if fail exit 1                          # Make sure we did
+.filename := \%1                        # Filename from command line
+if not def filename {                   # If none give usage message
+    exit 1 "Usage: \%0: infile [ outfile ]"
+}
+fopen /read \%c \m(filename)            # Open the input CSV file
+if fail exit                            # Make sure we did
+
+.output := \%2                          # Output filename from command line
+if not def output {                     # Supply one if not given
+    .output := New_\m(filename)
+}
+fopen /write \%o \m(output)             # Open output file
+if fail exit                            # Check that we did
+
+.serial = 00000000000                   # Initialize serial number
+.licenses = 0                           # and license counter
+
+fread /line \%c line                        # First line is column labels
+if fail exit                                # Check
+fwrite /line \%o "\m(line),AMM_DD,AYYYY"    # Write new labels line
+
+# Remaining lines are license purchases (K95B) followed by zero or more
+# maintenance invoices (K95BM) for each license.
+
+.datepaid = 00/00/0000                  # Initialize last maint payment date
+.amtpaid = $0.00                        # Initialize last maint payment amount
+set flag off                            # For remembering we're at end of file
+while not flag {                        # Loop to read all records
+    fread /line \%c line                # Read a record
+    if fail set flag on                 # If EOF set flag for later
+    .n := \fsplit(\m(line),&a,\44,CSV)  # Break record into array
+    if ( flag || equ "\&a[3]" "K95B" ) { # License or EOF
+        if fail exit 1 "FAILED: \v(lastcommand)"
+        if licenses {                   # If this is not the first license
+            .\&x[5] := \m(amtpaid)      # Substitute most recent amount paid
+            .\&x[21] := \m(datepaid)    # Substitute most recent date paid
+            void \fsplit(\&x[18],&d,/)  # Break up original (anniversary) date
+            # and put mm_dd and yyyy in separate fields for sorting...
+            fwrite /line \%o "\fjoin(&x,CSV),\flpad(\&d[1],2,0)_\flpad(\&d[2],2,
+0),\&d[3]"
+            if fail exit 1 WRITE        # Check for error
+            xecho .                     # Show progress as one dot per record
+        }
+        if flag break                   # We're at EOF so we're finished
+        increment licenses              # New license - count it
+        array copy &a &x                # Keep this record while reading next
+        .serial := \&a[6]               # Remember serial number
+        .datepaid = 00/00/0000          # Initial maintenance payment date
+        .amtpaid = $0.00                # and amount
+        continue                        # and go back to read next record
+    }
+    if not eq "\m(serial)" "\&a[6]" {   # Catch out-of-sequence record
+        echo
+        echo "SEQUENCE: \m(serial)..\&a[6]: \&a[7] [\&a[1]]"
+        continue
+    }
+    if equ "\&a[5]" "" .\&a[5] = $0.00  # If amount is empty make it $0.00
+    if not equ "\&a[5]" "$0.00" {       # If amount is not $0.00
+        .datepaid := \&a[21]            # remember date paid
+        .amtpaid := \&a[5]              # and amount paid
+    }
+}
+fclose ALL                              # Done - close all files and exit
+exit 0 Done.
+
+
+   The result imports back into Excel, where it can be sorted, formatted,
+   or otherwise manipulated as desired.
+
+Using CSV Files: Extending Kermit's Data Structures
+
+   Now that we can parse a CSV record, what would we do with a CSV file -
+   that is, a sequence of records? If we needed all the data available at
+   once, we would want to load it into a matrix of (row,column) values.
+   But Kermit doesn't have matrices. Or does it?
+
+   Kermit has several built-in data types, but you can invent your own
+   data types as needed using Kermit's macro feature:
+
+define variablename value
+
+   For example:
+
+define alphabet abcdefghijklmnopqrstuvwxyz
+
+   This defines a macro named alphabet and gives it the value
+   abcdefghijklmnopqrstuvwxyz. A more convenient notation (added in
+   C-Kermit 7.0, see [111]Table 2) for this is:
+
+.alphabet = abcdefghijklmnopqrstuvwxyz
+
+   The two are exactly equivalent: they make a literal copy the "right
+   hand side" as the value of the macro. Then you can refer to the macro
+   anywhere in a Kermit command as "\m(macroname)":
+
+echo "Alphabet = \m(alphabet)"
+
+   There is a second way to define a macro, which is like the first except
+   that the right-hand side is evaluated first; that is, any variable
+   references or function calls in the right-hand side are replaced by
+   their values before the result is assigned to the macro. The command
+   for this is ASSIGN rather than DEFINE:
+
+define alphabet abcdefghijklmnopqrstuvwxyz
+assign backwards \freverse(\m(alphabet))
+echo "Alphabet backwards = \m(backwards)"
+
+   which prints:
+
+Alphabet backwards = zyxwvutsrqponmlkjihgfedcba
+
+   This kind of assignment can also be done like this:
+
+.alphabet = abcdefghijklmnopqrstuvwxyz
+.backwards := \freverse(\m(alphabet))
+
+   [112]Any command starting with a period is an assignment, and the
+   operator (= or :=) tells what to do with the right-hand side before
+   making the assignment.
+
+   In both the DEFINE and ASSIGN commands, the variable name itself is
+   taken literally. It is also possible, however, to have Kermit compute
+   the variable name. This is done (as described in [113]Using C-Kermit,
+   2nd Ed., p.457), using parallel commands that start with underscore:
+   _DEFINE and _ASSIGN (alias _DEF and _ASG). These are just like DEFINE
+   and ASSIGN except they evaluate the variable name before making the
+   assignment. For example:
+
+define \%a one
+_define \%a\%a\%a 111
+
+   would create a macro named ONEONEONE with a value of 111, and:
+
+define \%a one
+define number 111
+_assign \%a\%a\%a \m(number)
+
+   would create the same macro with the same value, but:
+
+define \%a one
+define number 111
+_define \%a\%a\%a \m(number)
+
+   would give the macro a value of "\m(number)".
+
+   You can use the _ASSIGN command to create any kind of data structure
+   you want; you can find some examples in the [114]Object-Oriented
+   Programming section of the [115]Kermit Script Library. In the following
+   program we use this capability to create a two-dimensional array, or
+   matrix, to hold the all the elements of the CSV file, and then to
+   display the matrix:
+
+fopen /read \%c data.csv                # Open CSV file
+if fail exit 1
+
+.\%r = 0                                # Row
+.\%m = 0                                # Maximum columns
+while true {
+    fread /line \%c line                # Read a record
+    if fail break                       # End of file
+    .\%n := \fsplit(\m(line),&a,\44,CSV) # Split record into items
+    incr \%r                            # Count this row
+    for \%i 1 \%n 1 {                   # Assign items to this row of matrix
+        _asg a[\%r][\%i] \&a[\%i]
+    }
+    if > \%i \%m { .\%m := \%i }        # Remember width of widest row
+}
+fclose \%c                              # Close CSV file
+decrement \%m                           # (because of how FOR loop works)
+echo MATRIX A ROWS: \%r COLUMNS: \%m    # Show the matrix
+
+for \%i 1 \%r 1 {                       # Loop through rows
+    for \%j 1 \%m 1 {                   # Loop through columns of each row
+        xecho "\flpad(\m(a[\%i][\%j]),6)"
+    }
+    echo
+}
+exit 0
+
+   The matrix is called a and its elements are a[1][1], a[1][2], a[1][3],
+   ... a[2][1], etc, and you can treat this data structure exactly like a
+   two-dimensional array, in which you can refer to any element by its "X
+   and Y coordinates". For example, if the CSV file contained numeric data
+   you could compute row and column sums using simple FOR loops and
+   Kermit's built-in one-dimensional array data type:
+
+declare \&r[\%r]                        # Make an array for the row sums
+declare \&c[\%m]                        # Make an array for the column sums
+for \%i 1 \%r 1 {                       # Loop through rows
+    for \%j 1 \%m 1 {                   # Loop through columns of each row
+        increment \&r[\%i] \m(a[\%i][\%j]) # Accumulate row sum
+        increment \&c[\%j] \m(a[\%i][\%j]) # Accumulate column sum
+    }
+}
+
+   Note that the sum arrays don't have to be initialized to zero because
+   Kermit's INCREMENT command treats empty definitions as zero.
+
+Demonstration Scripts for Webmasters
+
+   These scripts all use new features of C-Kermit 9.0.
+
+   [116]ksitemap
+          A C-Kermit 9.0 script to build sitemap.xml for a website,
+          complete with Google image extensions (this is the file used by
+          webmasters to get their sites crawled and indexed optimally).
+
+   [117]The Weblog Script
+          Reads a web log, extracts the Google searches, normalizes the
+          search strings, and prints the top 20 searches, along with their
+          counts.
+
+   [118]The Amazon Script
+          Reads an Amazon Associate orders report and lists the products
+          according to the number of orders for each, or the number of
+          clicks on each.
+
+   [119]Photoalbum
+          Makes a website from a collection of JPG images.
+
+            [120]Home [121]Kermit 95 [122]C-Kermit [123]Scripts [124]Current
+   [125]New [126]FAQ  [127]Support
+
+
+    C-Kermit 9.0 / [128]The Kermit Project / [129]Columbia University /
+    [130]kermit@columbia.edu / [131]validate
+
+References
+
+   1. http://www.columbia.edu/
+   2. mailto:kermit@columbia.edu
+   3. http://www.columbia.edu/kermit/index.html
+   4. http://www.columbia.edu/kermit/k95.html
+   5. http://www.columbia.edu/kermit/ckermit.html
+   6. http://www.columbia.edu/kermit/ckscripts.html
+   7. http://www.columbia.edu/kermit/current.html
+   8. http://www.columbia.edu/kermit/whatsnew.html
+   9. http://www.columbia.edu/kermit/faq.html
+  10. http://www.columbia.edu/kermit/support.html
+  11. http://www.columbia.edu/cu/computinghistory/books/#menagerie
+  12. http://www.columbia.edu/kermit/ck90tables.html
+  13. http://www.amazon.com/gp/product/1555581641?ie=UTF8&tag=aleidmoreldom-20&linkCode=as2&camp=1789&creative=9325&creativeASIN=1555581641
+  14. http://www.columbia.edu/kermit/ckermit.html#download
+  15. http://www.columbia.edu/kermit/ckermit90.html#LargeFiles
+  16. http://www.columbia.edu/kermit/ckermit90.html#TestLargeFiles
+  17. http://www.columbia.edu/kermit/ckermit90.html#Bignums
+  18. http://www.columbia.edu/kermit/ckermit90.html#force3
+  19. http://www.columbia.edu/kermit/ckermit90.html#Vareval
+  20. http://www.columbia.edu/kermit/ckermit90.html#rename
+  21. http://www.columbia.edu/kermit/ckermit90.html#Other
+  22. http://www.columbia.edu/kermit/ckermit90.html#Incompatibilities
+  23. http://www.columbia.edu/kermit/ckermit90.html#NotIn9.0
+  24. http://www.columbia.edu/kermit/ckermit90.html#LooseEnd
+  25. http://www.columbia.edu/kermit/ckermit90.html#pop
+  26. http://www.columbia.edu/kermit/ckermit90.html#HPswitch
+  27. http://www.columbia.edu/kermit/ckermit90.html#iLO
+  28. http://www.columbia.edu/kermit/ckermit90.html#Rolm
+  29. http://www.columbia.edu/kermit/ckermit90.html#CSV
+  30. http://www.columbia.edu/kermit/ckermit90.html#Otherdemos
+  31. http://www.columbia.edu/kermit/ck60manual.html
+  32. http://www.amazon.com/gp/product/B002ACPF9M?ie=UTF8&tag=aleidmoreldom-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=B002ACPF9M
+  33. http://www.columbia.edu/kermit/ckermit70.html
+  34. http://www.columbia.edu/kermit/ckermit80.html
+  35. http://www.columbia.edu/kermit/ckscripts.html
+  36. http://www.columbia.edu/cu/computinghistory/dec20.html
+  37. mailto:fdc@columbia.edu
+  38. http://www.columbia.edu/kermit/k95.html
+  39. http://www.columbia.edu/kermit/cu-bsd-license.html
+  40. http://www.columbia.edu/kermit/ckermit90.html#LargeFiles
+  41. http://www.columbia.edu/kermit/ck90tables.html
+  42. http://www.columbia.edu/kermit/ck90tables.html
+  43. http://www.columbia.edu/kermit/ckermit90.html#force3
+  44. http://www.columbia.edu/kermit/ckermit90.html#Vareval
+  45. http://www.columbia.edu/kermit/ckrename.html
+  46. http://www.columbia.edu/kermit/csv.html
+  47. http://www.columbia.edu/kermit/csetnames.html
+  48. http://www.columbia.edu/kermit/ckermit90.html#HPswitch
+  49. http://www.columbia.edu/kermit/ckdaily.html
+  50. http://www.columbia.edu/kermit/cu-bsd-license.html
+  51. http://www.opensource.org/
+  52. http://kermit.columbia.edu/ck90tables.html#LF
+  53. ftp://kermit.columbia.edu/kermit/utils/bigfile.c
+  54. http://www.columbia.edu/kermit/ckermit80.html#x9
+  55. http://www.columbia.edu/kermit/ck90tables.html#LF
+  56. ftp://kermit.columbia.edu/kermit/scripts/ckermit/easter2
+  57. http://www.columbia.edu/kermit/em-apex.html
+  58. http://www.iridium.com/
+  59. http://science1.nasa.gov/science-news/science-at-nasa/2006/09jan_electrichurricanes/
+  60. http://www.columbia.edu/kermit/ek.html
+  61. ftp://kermit.columbia.edu/kermit/ek/simirid/
+  62. http://www.columbia.edu/kermit/ek.html
+  63. http://www.columbia.edu/kermit/ckermit70.html#x7.10.10
+  64. http://www.columbia.edu/kermit/csv.html
+  65. http://www.columbia.edu/kermit/ckermit70.html#x1.11
+  66. http://www.columbia.edu/kermit/ckermit70.html
+  67. http://www.columbia.edu/kermit/ckermit80.html#x9
+  68. http://www.columbia.edu/kermit/csetnames.html
+  69. http://www.columbia.edu/kermit/ckdaily.html
+  70. http://www.columbia.edu/kermit/ftpclient.html
+  71. http://www.columbia.edu/kermit/ckdaily.html
+  72. http://www.columbia.edu/kermit/csetnames.html
+  73. http://www.columbia.edu/kermit/ckermit90.html#Otherdemos
+  74. http://www.columbia.edu/kermit/input_nowrap.html
+  75. http://www.columbia.edu/~fdc/mm/index.html
+  76. http://www.columbia.edu/kermit/photoalbum.html
+  77. http://www.columbia.edu/~fdc/kermit/logserial.html
+  78. http://www.columbia.edu/kermit/ckermit90.html#message
+  79. http://www.columbia.edu/kermit/ckermit90.html#NotIn9.0
+  80. http://www.columbia.edu/kermit/csv.html#join
+  81. http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-3767
+  82. http://www.columbia.edu/kermit/ftp/test/tar/x.zip
+  83. http://www.mseclab.com/?p=180
+  84. http://www.theregister.co.uk/2009/07/30/universal_ssl_certificate/
+  85. http://www.columbia.edu/kermit/ckermit90.html#HPswitch
+  86. http://www.columbia.edu/kermit/em-apex.html
+  87. http://www.freebsd.org/releases/8.0R/announce.html
+  88. http://www.columbia.edu/kermit/security81.html#x4.2.3
+  89. http://www.columbia.edu/kermit/ckermit80.html#x9
+  90. http://www.columbia.edu/kermit/ckermit80.html#x8.7.2
+  91. http://www.columbia.edu/kermit/ckermit80.html#x9
+  92. http://www.columbia.edu/kermit/ckpackages.html
+  93. http://docs.hp.com/en/B9106-90013/pty.7.html
+  94. http://www.columbia.edu/kermit/test/text/ckc299.txt
+  95. http://www.columbia.edu/kermit/test/text/ckutio.c
+  96. http://www.columbia.edu/~fdc/mm/pop
+  97. http://www.columbia.edu/~fdc/mm/
+  98. http://www.columbia.edu/~fdc/mm/mailcheck
+  99. http://en.wikipedia.org/wiki/Trivial_File_Transfer_Protocol
+ 100. http://www.columbia.edu/kermit/ftp/scripts/ckermit/gethpconfig
+ 101. http://www.columbia.edu/kermit/ftp/scripts/ckermit/TestSwitches.txt
+ 102. http://en.wikipedia.org/wiki/Standard_streams
+ 103. http://kermit.columbia.edu/cudocs/ilosetup.html
+ 104. http://www.columbia.edu/kermit/cudocs/cbx.html
+ 105. http://www.columbia.edu/kermit/ckermit90.html#record
+ 106. http://www.columbia.edu/kermit/ckermit90.html#join
+ 107. http://www.columbia.edu/kermit/ckermit90.html#file
+ 108. http://www.columbia.edu/kermit/ckermit80.html#fjoin
+ 109. http://www.columbia.edu/kermit/ckermit90.html#rules
+ 110. http://www.columbia.edu/kermit/ckermit80.html#fjoin
+ 111. http://www.columbia.edu/kermit/ckermit90.html#varasg
+ 112. http://www.columbia.edu/kermit/ckermit70.html#x7.9
+ 113. http://www.amazon.com/gp/product/1555581641?ie=UTF8&tag=aleidmoreldom-20&linkCode=as2&camp=1789&creative=9325&creativeASIN=1555581641
+ 114. http://www.columbia.edu/kermit/ckscripts.html#oops
+ 115. http://www.columbia.edu/kermit/ckscripts.html
+ 116. http://www.columbia.edu/kermit/ksitemap.html
+ 117. http://www.columbia.edu/kermit/weblog.html
+ 118. http://kermit.columbia.edu/ftp/scripts/ckermit/amazon
+ 119. http://www.columbia.edu/kermit/photoalbum.html
+ 120. http://www.columbia.edu/kermit/index.html
+ 121. http://www.columbia.edu/kermit/k95.html
+ 122. http://www.columbia.edu/kermit/ckermit.html
+ 123. http://www.columbia.edu/kermit/ckscripts.html
+ 124. http://www.columbia.edu/kermit/current.html
+ 125. http://www.columbia.edu/kermit/whatsnew.html
+ 126. http://www.columbia.edu/kermit/faq.html
+ 127. http://www.columbia.edu/kermit/support.html
+ 128. http://www.columbia.edu/kermit/index.html
+ 129. http://www.columbia.edu/
+ 130. mailto:kermit@columbia.edu
+ 131. http://validator.w3.org/check?uri=http%3A%2F%2Fkermit.columbia.edu%2Fckermit90.html