1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-02-13 19:52:20 +00:00

Merge pull request #1471 from lkoutsofios/master

added documentation pages from Dave Korn's old web site
This commit is contained in:
Lefteris Koutsofios 2020-02-14 13:08:33 -05:00 committed by GitHub
commit 27e72175bd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 2777 additions and 0 deletions

6
docs/index.html Normal file
View file

@ -0,0 +1,6 @@
<html>
<head><title>AST Software</title></head>
<body>
<a href='ksh/index.html'>The KornShell</a><br>
</body>
</html>

710
docs/ksh/builtins.html Normal file
View file

@ -0,0 +1,710 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<HTML>
<HEAD>
<META name="generator" content="mm2html (AT&amp;T Research) 2012-01-11">
<TITLE> www/ksh/builtins.mm mm document </TITLE>
<META name="author" content="gsf+dgk+kpv">
<STYLE type="text/css">
div.FI { padding-left:2em; text-indent:0em; }
div.HI { padding-left:4em; text-indent:-2em; }
dt { float:left; clear:both; }
dd { margin-left:3em; }
</STYLE>
</HEAD>
<BODY bgcolor=white link=slateblue vlink=teal >
<TABLE border=0 align=center width=96%>
<TBODY><TR><TD valign=top align=left>
<!--INDEX--><!--/INDEX-->
<P>
<CENTER>
<H3><CENTER><FONT color=red><FONT face=courier>Guidelines for writing <TT>ksh-93</TT> built-in commands</FONT></FONT></CENTER></H3>
<BR>David G. Korn
<P><I></I>
</CENTER>
<P>
<CENTER><FONT color=red><FONT face=courier><H3 align=center><A name="Abstract">Abstract</A></H3></FONT></FONT></CENTER>
One of the features of <TT>ksh93</TT>, the latest version of <TT>ksh</TT>,
is the ability to add built-in commands at run time.
This feature only works on operating systems that have the ability
to load and link code into the current process at run time.
Some examples of the systems that have this feature
are Linux, System V Release 4, Solaris, Sun OS, HP-UX Release 8 and above,
AIX 3.2 and above, and Microsoft Windows systems.
<P>
This memo describes how to write and compile programs
that can be loaded into <TT>ksh</TT> at run time as built-in
commands.
<P>
<P><HR><CENTER><FONT color=red><FONT face=courier><H3><A name="INTRODUCTION">INTRODUCTION</A></H3></FONT></FONT></CENTER>
A built-in command is executed without creating a separate process.
Instead, the command is invoked as a C function by <TT>ksh</TT>.
If this function has no side effects in the shell process,
then the behavior of this built-in is identical to that of
the equivalent stand-alone command. The primary difference
in this case is performance. The overhead of process creation
is eliminated. For commands of short duration, the effect
can be dramatic. For example, on SUN OS 4.1, the time to
run <TT>wc</TT> on a small file of about 1000 bytes, runs
about 50 times faster as a built-in command.
<P>
In addition, built-in commands may have side effects on the
shell environment.
This is usually done to extend the application domain for
shell programming. For example, there is a group of X-windows extension
built-ins that make heavy use of the shell variable namespace.
These built-ins are added at run time and
result in a windowing shell that can be used to write
X-windows applications.
<P>
While there are definite advantages to adding built-in
commands, there are some disadvantages as well.
Since the built-in command and <TT>ksh</TT> share the same
address space, a coding error in the built-in program
may affect the behavior of <TT>ksh</TT>; perhaps causing
it to core dump or hang.
Debugging is also more complex since your code is now
a part of a larger entity.
The isolation provided by a separate process
guarantees that all resources used by the command
will be freed when the command completes.
Resources used by a built-in must be meticulously maintained and freed.
Also, since the address space of <TT>ksh</TT> will be larger when built-in are loaded,
it may increase the time it takes <TT>ksh</TT> to fork() and
exec() non-built-in commands.
It makes no sense to add a built-in command that takes
a long time to run or that is run only once, since the performance
benefits will be negligible.
Built-ins that have side effects in the current shell
environment have the disadvantage of increasing the
coupling between the built-in and <TT>ksh</TT>, making
the overall system less modular and more monolithic.
<P>
Despite these drawbacks, in many cases extending
<TT>ksh</TT> by adding built-in
commands makes sense and allows reuse of the shell
scripting ability in an application specific domain.
This memo describes how to write <TT>ksh</TT> extensions.
<P>
<P><HR><CENTER><FONT color=red><FONT face=courier><H3><A name="WRITING BUILT-IN COMMANDS">WRITING BUILT-IN COMMANDS</A></H3></FONT></FONT></CENTER>
There is a development kit available for writing <TT>ksh</TT>
built-ins as part of the AST (AT&amp;T Software Technology) Toolkit.
The development kit has three directories,
<TT>include</TT>, <TT>lib</TT>, and <TT>bin</TT>.
It is best to set the value of the environment variable
<TT>PACKAGE_ast</TT> to the pathname of the directory
containing the development kit.
The <TT>include</TT> directory contains a sub-directory
named <TT>ast</TT> that contains interface prototypes
for functions that you can call from built-ins. The <TT>lib</TT>
directory contains the <TT>ast</TT> library
and a library named <TT>cmd</TT> that contains a version
of several of the standard POSIX<FONT SIZE=-6>[1]</FONT>
utilities that can be made run time built-ins.
The <TT>lib/ksh</TT> directory contains shared libraries
that implement other <TT>ksh</TT> built-ins.
The <TT>bin</TT> directory contains build tools such as <TT>nmake</TT><FONT SIZE=-6>[2]</FONT>.
To add built-ins at runtime, it is necessary to build a shared library
containing one or more built-ins that you wish to add.
The built-ins are then added by running <TT>builtin &#45;f</TT> <EM>shared_lib</EM>.
Since the procedure for building share libraries is system dependent,
it is best to use
<TT>nmake</TT>
using the sample nmake makefile below as a prototype.
The AST Toolkit also contains some examples of built-in libraries under
the <TT>src/cmd/kshlib</TT> directory.
<P>
There are two ways to code adding built-ins. One method is to replace
the function <TT>main</TT> with a function
<TT>b_</TT><EM>name</EM>, where <EM>name</EM> is the name
of the built-in you wish to define.
A built-in command has a calling convention similar to
the <TT>main</TT> function of a program,
<TT>int main(int argc, char *argv&#0091;&#0093;)</TT>.
except that it takes a third argument of type <TT>Shbltin_t*</TT> which can
be passed as <TT><FONT SIZE=-1>NULL</FONT></TT> if it is not used. The definition for
<TT>Shbltin_t*</TT> is in <TT>&lt;ast/shcmd.h&gt;</TT>.
Instead of <TT>exit</TT>, you need to use <TT>return</TT>
to terminate your command.
The return value will become the exit status of the command.
The <TT>open</TT> built-in, installed in <TT>lib/ksh</TT> in the AST Toolkit, uses this method.
The <TT>Shbltin_t</TT> structure contains a field named <TT>shp</TT> which is
a pointer the the shell data that is needed for <TT>shell</TT> library callbacks.
It also contains the fields, <TT>shrun</TT>, <TT>shtrap</TT>, <TT>shexit</TT>,
and <TT>shbltin</TT>
that are function pointers to the <TT>shell</TT> library functions <TT>sh_run</TT>, <TT>sh_trap</TT>
<TT>sh_exit</TT>, and <TT>sh_addbuiltin</TT>, respectively. These functions
can be invoked without the need for runtime symbol lookup when the
shell is statically linked with <TT>libshell</TT>.
<P>
The alternative method is to create a function <TT>lib_init</TT> and
use the <TT>Shbltin_t.shbltin()</TT> function to add one or more built-ins.
The <TT>lib_init</TT> function will be called with two arguments. The
first argument will be 0 when the library is loaded and the second
argument will be of type <TT>Shbltin_t*</TT>.
The <TT>dbm_t</TT> and <TT>dss</TT> shell built-ins use this method.
<P>
No matter which way you add built-ins you should add the line
<TT>SHLIB(</TT><EM>identifier</EM><TT>)</TT> as the last line of one
of the built-in source file, where <EM>identifier</EM> is any C identifier.
This line provides version information to the shell <TT>builtin</TT> command
that it uses to verify compatibility between the built-in and <TT>ksh</TT>
implementation versions. <TT>builtin</TT> fails with a diagnostic on version
mismatch. The diagnostic helps determine whether <TT>ksh</TT> is out of
date and requires an upgrade or the built-in is out of date and requires
recompilation.
<P>
The steps necessary to create and add a run time built-in are
illustrated in the following simple example.
Suppose you wish to add a built-in command named <TT>hello</TT>
which requires one argument and prints the word hello followed
by its argument. First, write the following program in the file
<TT>hello.c</TT>:
<DIV class=FI>
<PRE>
#include &lt;stdio.h&gt;
int b_hello(int argc, char *argv&#0091;&#0093;, void *context)
{
if(argc != 2)
{
fprintf(stderr,"Usage: hello arg&#0092;n");
return(2);
}
printf("hello %s&#0092;n",argv&#0091;1&#0093;);
return(0);
}
SHLIB(hello)
</DIV>
</PRE>
<P>
Next, the program needs to be compiled.
If you are building with AT&amp;T <TT>nmake</TT> use the following <TT>Makefile</TT>:
<DIV class=FI>
<PRE>
:PACKAGE: --shared ast
hello plugin=ksh :LIBRARY: hello.c
</DIV>
</PRE>
and run <TT>nmake install</TT> to compile, link, and install the built-in shared library
in <TT>lib/ksh/</TT> under <TT>PACKAGE_ast</TT>.
If the built-in extension uses several <TT>.c</TT> files, list all of these on
the <TT>:LIBRARY:</TT> line.
<P>
Otherwise you will have to compile <TT>hello.c</TT> with an option
to pick up the AST include directory
(since the AST <TT>&lt;stdio.h&gt;</TT> is required for <TT>ksh</TT> compatibility)
and options required for generating shared libraries.
For example, on Linux use this to compile:
<DIV class=FI>
<PRE>
cc -fpic -I$PACKAGE_ast/include/ast -c hello.c
</DIV>
</PRE>
and use the appropriate link line.
It really is best to use <TT>nmake</TT> because the 2 line Makefile above
will work on all systems that have <TT>ksh</TT> installed.
<P>
If you have several built-ins, it is desirable
to build a shared library that contains them all.
<P>
The final step is using the built-in.
This can be done with the <TT>ksh</TT> command <TT>builtin</TT>.
To load the shared library <TT>libhello.so</TT> from the current directory
and add the built-in <TT>hello</TT>, invoke the command,
<DIV class=FI>
<PRE>
builtin -f ./libhello.so hello
</DIV>
</PRE>
The shared library prefix (<TT>lib</TT> here) and suffix (<TT>.so</TT> here) be omitted;
the shell will add an appropriate suffix
for the system that it is loading from.
If you install the shared library in <TT>lib/ksh/</TT>, where <TT>../lib/ksh/</TT> is
a directory on <STRONG>$PATH</STRONG>, the command
<DIV class=FI>
<PRE>
builtin -f hello hello
</DIV>
</PRE>
will automatically find, load and install the built-in on any system.
Once this command has been invoked, you can invoke <TT>hello</TT>
as you do any other command.
If you are using <TT>lib_init</TT> method to add built-ins then no arguments
follow the <TT>&#45;f</TT> option.
<P>
It is often desirable to make a command <EM>built-in</EM>
the first time that it is referenced. The first
time <TT>hello</TT> is invoked, <TT>ksh</TT> should load and execute it,
whereas for subsequent invocations <TT>ksh</TT> should just execute the built-in.
This can be done by creating a file named <TT>hello</TT>
with the following contents:
<DIV class=FI>
<PRE>
function hello
{
unset -f hello
builtin -f hello hello
hello "$@"
}
</DIV>
</PRE>
This file <TT>hello</TT> needs to be placed in a directory that is
in your <STRONG><FONT SIZE=-1>FPATH</FONT></STRONG> variable, and the built-in shared library
should be installed in <TT>lib/ksh/</TT>, as described above.
<P>
<P><HR><CENTER><FONT color=red><FONT face=courier><H3><A name="CODING REQUIREMENTS AND CONVENTIONS">CODING REQUIREMENTS AND CONVENTIONS</A></H3></FONT></FONT></CENTER>
As mentioned above, the entry point for built-ins must either be of
the form <TT>b_</TT><EM>name</EM> or else be loaded from a function named
<TT>lib_init</TT>.
Your built-ins can call functions from the standard C library,
the <TT>ast</TT> library, interface functions provided by <TT>ksh</TT>,
and your own functions.
You should avoid using any global symbols beginning with
<STRONG>sh_</STRONG>,
<STRONG>nv_</STRONG>,
and
<STRONG>ed_</STRONG>
since these are used by <TT>ksh</TT> itself.
<TT>#define</TT> constants in <TT>ksh</TT> interface
files use symbols beginning with <TT>SH_</TT> and <TT>NV_</TT>,
so avoid using names beginning with these too.
<P>
<H4><A name="Header Files">Header Files</A></H4>
The development kit provides a portable interface
to the C library and to libast.
The header files in the development kit are compatible with
K&amp;R C<FONT SIZE=-6>[3]</FONT>,
ANSI-C<FONT SIZE=-6>[4]</FONT>,
and C++<FONT SIZE=-6>[5]</FONT>.
<P>
The best thing to do is to include the header file <TT>&lt;shell.h&gt;</TT>.
This header file causes the <TT>&lt;ast.h&gt;</TT> header, the
<TT>&lt;error.h&gt;</TT> header and the <TT>&lt;stak.h&gt;</TT>
header to be included as well as defining prototypes
for functions that you can call to get shell
services for your builtins.
The header file <TT>&lt;ast.h&gt;</TT>
provides prototypes for many <STRONG>libast</STRONG> functions
and all the symbol and function definitions from the
ANSI-C headers, <TT>&lt;stddef.h&gt;</TT>,
<TT>&lt;stdlib.h&gt;</TT>, <TT>&lt;stdarg.h&gt;</TT>, <TT>&lt;limits.h&gt;</TT>,
and <TT>&lt;string.h&gt;</TT>.
It also provides all the symbols and definitions for the
POSIX<FONT SIZE=-6>[6]</FONT>
headers <TT>&lt;sys/types.h&gt;</TT>, <TT>&lt;fcntl.h&gt;</TT>, and
<TT>&lt;unistd.h&gt;</TT>.
You should include <TT>&lt;ast.h&gt;</TT> instead of one or more of
these headers.
The <TT>&lt;error.h&gt;</TT> header provides the interface to the error
and option parsing routines defined below.
The <TT>&lt;stak.h&gt;</TT> header provides the interface to the memory
allocation routines described below.
<P>
Programs that want to use the information in <TT>&lt;sys/stat.h&gt;</TT>
should include the file <TT>&lt;ls.h&gt;</TT> instead.
This provides the complete POSIX interface to <TT>stat()</TT>
related functions even on non-POSIX systems.
<P>
<P>
<H4><A name="Input/Output">Input/Output</A></H4>
<TT>ksh</TT> uses <STRONG>sfio</STRONG>,
the Safe/Fast I/O library<FONT SIZE=-6>[7]</FONT>,
to perform all I/O operations.
The <STRONG>sfio</STRONG> library, which is part of <STRONG>libast</STRONG>,
provides a superset of the functionality provided by the standard
I/O library defined in ANSI-C.
If none of the additional functionality is required,
and if you are not familiar with <STRONG>sfio</STRONG> and
you do not want to spend the time learning it,
then you can use <TT>sfio</TT> via the <TT>stdio</TT> library
interface. The development kit contains the header <TT>&lt;stdio.h&gt;</TT>
which maps <TT>stdio</TT> calls to <TT>sfio</TT> calls.
In most instances the mapping is done
by macros or inline functions so that there is no overhead.
The man page for the <TT>sfio</TT> library is in an Appendix.
<P>
However, there are some very nice extensions and
performance improvements in <TT>sfio</TT>
and if you plan any major extensions I recommend
that you use it natively.
<P>
<H4><A name="Error Handling">Error Handling</A></H4>
For error messages it is best to use the <TT>ast</TT> library
function <TT>errormsg()</TT> rather that sending output to
<TT>stderr</TT> or the equivalent <TT>sfstderr</TT> directly.
Using <TT>errormsg()</TT> will make error message appear
more uniform to the user.
Furthermore, using <TT>errormsg()</TT> should make it easier
to do error message translation for other locales
in future versions of <TT>ksh</TT>.
<P>
The first argument to
<TT>errormsg()</TT> specifies the dictionary in which the string
will be searched for translation.
The second argument to <TT>errormsg()</TT> contains that error type
and value. The third argument is a <EM>printf</EM> style format
and the remaining arguments are arguments to be printed
as part of the message. A new-line is inserted at the
end of each message and therefore, should not appear as
part of the format string.
The second argument should be one of the following:
<DIV class=SH>
<DL>
<DT><TT>ERROR_exit(</TT><EM>n</EM><TT>)</TT>:<DD><BR>
If <EM>n</EM> is not-zero, the builtin will exit value <EM>n</EM> after
printing the message.
<DT><TT>ERROR_system(</TT><EM>n</EM><TT>)</TT>:<DD><BR>
Exit builtin with exit value <EM>n</EM> after printing the message.
The message will display the message corresponding to <TT>errno</TT>
enclosed within <TT>&#0091;&nbsp;&#0093;</TT> at the end of the message.
<DT><TT>ERROR_usage(</TT><EM>n</EM><TT>)</TT>:<DD><BR>
Will generate a usage message and exit. If <EM>n</EM> is non-zero,
the exit value will be 2. Otherwise the exit value will be 0.
<DT><TT>ERROR_debug(</TT><EM>n</EM><TT>)</TT>:<DD><BR>
Will print a level <EM>n</EM> debugging message and will then continue.
<DT><TT>ERROR_warn(</TT><EM>n</EM><TT>)</TT>:<DD><BR>
Prints a warning message. <EM>n</EM> is ignored.
</DL><P>
<H4><A name="Option Parsing">Option Parsing</A></H4>
The first thing that a built-in should do is to check
the arguments for correctness and to print any usage
messages on standard error.
For consistency with the rest of <TT>ksh</TT>, it is best
to use the <TT>libast</TT> functions <TT>optget()</TT> and
<TT>optusage()</TT>for this
purpose.
The header <TT>&lt;error.h&gt;</TT> includes prototypes for
these functions.
The <TT>optget()</TT> function is similar to the
System V C library function <TT>getopt()</TT>,
but provides some additional capabilities.
Built-ins that use <TT>optget()</TT> provide a more
consistent user interface.
<P>
The <TT>optget()</TT> function is invoked as
<DIV class=FI>
<PRE>
int optget(char *<EM>argv</EM>&#0091;&#0093;, const char *<EM>optstring</EM>)
</DIV>
</PRE>
where <TT>argv</TT> is the argument list and <TT>optstring</TT>
is a string that specifies the allowable arguments and
additional information that is used to format <EM>usage</EM>
messages.
In fact a complete man page in <TT>troff</TT> or <TT>html</TT>
can be generated by passing a usage string as described
by the <TT>getopts</TT> command.
Like <TT>getopt()</TT>,
single letter options are represented by the letter itself,
and options that take a string argument are followed by the <TT>:</TT>
character.
Option strings have the following special characters:
<DIV class=SH>
<DL>
<DT><TT>:</TT><DD>
Used after a letter option to indicate that the option
takes an option argument.
The variable <TT>opt_info.arg</TT> will point to this
value after the given argument is encountered.
<DT><TT>#</TT><DD>
Used after a letter option to indicate that the option
can only take a numerical value.
The variable <TT>opt_info.num</TT> will contain this
value after the given argument is encountered.
<DT><TT>?</TT><DD>
Used after a <TT>:</TT> or <TT>#</TT> (and after the optional <TT>?</TT>)
to indicate the the
preceding option argument is not required.
<DT><TT>&#0091;</TT>...<TT>&#0093;</TT><DD><BR>
After a <TT>:</TT> or <TT>#</TT>, the characters contained
inside the brackets are used to identify the option
argument when generating a <EM>usage</EM> message.
<DT><EM>space</EM><DD><BR>
The remainder of the string will only be used when generating
usage messages.
</DL>
</DIV>
<P>
The <TT>optget()</TT> function returns the matching option letter if
one of the legal option is matched.
Otherwise, <TT>optget()</TT> returns
<DIV class=SH>
<DL>
<DT><TT>':'</TT><DD>
If there is an error. In this case the variable <TT>opt_info.arg</TT>
contains the error string.
<DT><TT>0</TT><DD>
Indicates the end of options.
The variable <TT>opt_info.index</TT> contains the number of arguments
processed.
<DT><TT>'?'</TT><DD>
A usage message has been required.
You normally call <TT>optusage()</TT> to generate and display
the usage message.
</DL>
</DIV>
<P>
The following is an example of the option parsing portion
of the <TT>wc</TT> utility.
<DIV class=FI>
<PRE>
#include &lt;shell.h&gt;
while(1) switch(n=optget(argv,"xf:&#0091;file&#0093;"))
{
case 'f':
file = opt_info.arg;
break;
case ':':
error(ERROR_exit(0), opt_info.arg);
break;
case '?':
error(ERROR_usage(2), opt_info.arg);
break;
}
</DIV>
</PRE>
<P>
<H4><A name="Storage Management">Storage Management</A></H4>
It is important that any memory used by your built-in
be returned. Otherwise, if your built-in is called frequently,
<TT>ksh</TT> will eventually run out of memory.
You should avoid using <TT>malloc()</TT> for memory that must
be freed before returning from you built-in, because by default,
<TT>ksh</TT> will terminate you built-in in the event of an
interrupt and the memory will not be freed.
<P>
The best way to to allocate variable sized storage is
through calls to the <STRONG>stak</STRONG> library
which is included in <STRONG>libast</STRONG>
and which is used extensively by <TT>ksh</TT> itself.
Objects allocated with the <TT>stakalloc()</TT>
function are freed when you function completes
or aborts.
The <STRONG>stak</STRONG> library provides a convenient way to
build variable length strings and other objects dynamically.
The man page for the <STRONG>stak</STRONG> library is contained
in the Appendix.
<P>
Before <TT>ksh</TT> calls each built-in command, it saves
the current stack location and restores it after
it returns.
It is not necessary to save and restore the stack
location in the <TT>b_</TT> entry function,
but you may want to write functions that use this stack
are restore it when leaving the function.
The following coding convention will do this in
an efficient manner:
<DIV class=FI>
<PRE>
<EM>yourfunction</EM>()
{
char *savebase;
int saveoffset;
if(saveoffset=staktell())
savebase = stakfreeze(0);
...
if(saveoffset)
stakset(savebase,saveoffset);
else
stakseek(0);
}
</DIV>
</PRE>
<P>
<P><HR><CENTER><FONT color=red><FONT face=courier><H3><A name="CALLING <TT>ksh</TT> SERVICES">CALLING <TT>ksh</TT> SERVICES</A></H3></FONT></FONT></CENTER>
Some of the more interesting applications are those that extend
the functionality of <TT>ksh</TT> in application specific directions.
A prime example of this is the X-windows extension which adds
builtins to create and delete widgets.
The <STRONG>nval</STRONG> library is used to interface with the shell
name space.
The <STRONG>shell</STRONG> library is used to access other shell services.
<P>
<H4><A name="The nval library">The nval library</A></H4>
A great deal of power is derived from the ability to use
portions of the hierarchal variable namespace provided by <TT>ksh-93</TT>
and turn these names into active objects.
<P>
The <STRONG>nval</STRONG> library is used to interface with shell
variables.
A man page for this file is provided in an Appendix.
You need to include the header <TT>&lt;nval.h&gt;</TT>
to access the functions defined in the <STRONG>nval</STRONG> library.
All the functions provided by the <STRONG>nval</STRONG> library begin
with the prefix <TT>nv_</TT>.
Each shell variable is an object in an associative table
that is referenced by name.
The type <TT>Namval_t*</TT> is pointer to a shell variable.
To operate on a shell variable, you first get a handle
to the variable with the <TT>nv_open()</TT> function
and then supply the handle returned as the first
argument of the function that provides an operation
on the variable.
You must call <TT>nv_close()</TT> when you are finished
using this handle so that the space can be freed once
the value is unset.
The two most frequent operations are to get the value of
the variable, and to assign value to the variable.
The <TT>nv_getval()</TT> returns a pointer the the
value of the variable.
In some cases the pointer returned is to a region that
will be overwritten by the next <TT>nv_getval()</TT> call
so that if the value isn't used immediately, it should
be copied.
Many variables can also generate a numeric value.
The <TT>nv_getnum()</TT> function returns a numeric
value for the given variable pointer, calling the
arithmetic evaluator if necessary.
<P>
The <TT>nv_putval()</TT> function is used to assign a new
value to a given variable.
The second argument to <TT>putval()</TT> is the value
to be assigned
and the third argument is a <EM>flag</EM> which
is used in interpreting the second argument.
<P>
Each shell variable can have one or more attributes.
The <TT>nv_isattr()</TT> is used to test for the existence
of one or more attributes.
See the appendix for a complete list of attributes.
<P>
By default, each shell variable passively stores the string you
give with with <TT>nv_putval()</TT>, and returns the value
with <TT>getval()</TT>. However, it is possible to turn
any node into an active entity by assigning functions
to it that will be called whenever <TT>nv_putval()</TT>
and/or <TT>nv_getval()</TT> is called.
In fact there are up to five functions that can
associated with each variable to override the
default actions.
The type <TT>Namfun_t</TT> is used to define these functions.
Only those that are non-<TT>NULL</TT> override the
default actions.
To override the default actions, you must allocate an
instance of <TT>Namfun_t</TT>, and then assign
the functions that you wish to override.
The <TT>putval()</TT>
function is called by the <TT>nv_putval()</TT> function.
A <TT>NULL</TT> for the <EM>value</EM> argument
indicates a request to unset the variable.
The <EM>type</EM> argument might contain the <TT>NV_INTEGER</TT>
bit so you should be prepared to do a conversion if
necessary.
The <TT>getval()</TT>
function is called by <TT>nv_getval()</TT>
value and must return a string.
The <TT>getnum()</TT>
function is called by by the arithmetic evaluator
and must return double.
If omitted, then it will call <TT>nv_getval()</TT> and
convert the result to a number.
<P>
The functionality of a variable can further be increased
by adding discipline functions that
can be associated with the variable.
A discipline function allows a script that uses your
variable to define functions whose name is
<EM>varname</EM><TT>.</TT><EM>discname</EM>
where <EM>varname</EM> is the name of the variable, and <EM>discname</EM>
is the name of the discipline.
When the user defines such a function, the <TT>settrap()</TT>
function will be called with the name of the discipline and
a pointer to the parse tree corresponding to the discipline
function.
The application determines when these functions are actually
executed.
By default, <TT>ksh</TT> defines <TT>get</TT>,
<TT>set</TT>, and <TT>unset</TT> as discipline functions.
<P>
In addition, it is possible to provide a data area that
will be passed as an argument to
each of these functions whenever any of these functions are called.
To have private data, you need to define and allocate a structure
that looks like
<DIV class=FI>
<PRE>
struct <EM>yours</EM>
{
Namfun_t fun;
<EM>your_data_fields</EM>;
};
</DIV>
</PRE>
<P>
<H4><A name="The shell library">The shell library</A></H4>
There are several functions that are used by <TT>ksh</TT> itself
that can also be called from built-in commands.
The man page for these routines are in the Appendix.
<P>
The <TT>sh_addbuiltin()</TT> function can be used to add or delete
builtin commands. It takes the name of the built-in, the
address of the function that implements the built-in, and
a <TT>void*</TT> pointer that will be passed to this function
as the third agument whenever it is invoked.
If the function address is <TT>NULL</TT>, the specified built-in
will be deleted. However, special built-in functions cannot
be deleted or modified.
<P>
The <TT>sh_fmtq()</TT> function takes a string and returns
a string that is quoted as necessary so that it can
be used as shell input.
This function is used to implement the <TT>%q</TT> option
of the shell built-in <TT>printf</TT> command.
<P>
The <TT>sh_parse()</TT> function returns a parse tree corresponding
to a give file stream. The tree can be executed by supplying
it as the first argument to
the <TT>sh_trap()</TT> function and giving a value of <TT>1</TT> as the
second argument.
Alternatively, the <TT>sh_trap()</TT> function can parse and execute
a string by passing the string as the first argument and giving <TT>0</TT>
as the second argument.
<P>
The <TT>sh_isoption()</TT> function can be used to set to see whether one
or more of the option settings is enabled.
</DIV>
<P><HR><CENTER><FONT color=red><FONT face=courier><H3><A name="References">References</A></H3></FONT></FONT></CENTER>
<P>
<DL compact>
<DT>[1]<DD>
<EM>POSIX &#45; Part 2: Shell and Utilities,</EM>
IEEE Std 1003.2-1992, ISO/IEC 9945-2:1993.
<DT>[2]<DD>
Glenn Fowler,
<EM>A Case for make</EM>,
Software - Practice and Experience, Vol. 20 No. S1, pp. 30-46, June 1990.
<DT>[3]<DD>
Brian W. Kernighan and Dennis M. Ritchie,
<EM>The C Programming Language</EM>,
Prentice Hall, 1978.
<DT>[4]<DD>
American National Standard for Information Systems &#45; Programming
Language &#45; C, ANSI X3.159-1989.
<DT>[5]<DD>
Bjarne Stroustroup,
<EM>C++</EM>,
Addison Wesley, xxxx
<DT>[6]<DD>
<EM>POSIX &#45; Part 1: System Application Program Interface,</EM>
IEEE Std 1003.1-1990, ISO/IEC 9945-1:1990.
<DT>[7]<DD>
David Korn and Kiem-Phong Vo,
<EM>SFIO - A Safe/Fast Input/Output library,</EM>
Proceedings of the Summer Usenix,
pp. , 1991.
</DL>
<P>
<HR>
<TABLE border=0 align=center width=96%>
<TR>
<TD align=left></TD>
<TD align=center></TD>
<TD align=right>March 13, 2012</TD>
</TR>
</TABLE>
<P>
</TD></TR></TBODY></TABLE>
</BODY>
</HTML>

55
docs/ksh/examples.html Normal file
View file

@ -0,0 +1,55 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<HTML>
<HEAD>
<META name="generator" content="mm2html (AT&amp;T Research) 2012-01-11">
<TITLE> www/ksh/examples.mm mm document </TITLE>
<META name="author" content="gsf+dgk+kpv">
<STYLE type="text/css">
div.FI { padding-left:2em; text-indent:0em; }
div.HI { padding-left:4em; text-indent:-2em; }
dt { float:left; clear:both; }
dd { margin-left:3em; }
</STYLE>
</HEAD>
<BODY bgcolor=white link=slateblue vlink=teal >
<TABLE border=0 align=center width=96%>
<TBODY><TR><TD valign=top align=left>
<!--INDEX--><!--/INDEX-->
<P>
<P><CENTER><FONT color=red><FONT face=courier><H3><A name="Sample Functions">Sample Functions</A></H3></FONT></FONT></CENTER>
<P></P><TABLE border=0 frame=void rules=none width=100%><TBODY><TR><TD>
<TABLE align=center bgcolor=papayawhip border=0 bordercolor=white cellpadding=2 cellspacing=2 frame=void rules=none >
<TBODY>
<TR><TD align=left>
<A href="functions/dirs.txt">dirs</A>&nbsp;&nbsp;</TD><TD align=left>&nbsp;&nbsp;<A href="functions/getopt.txt">getopt</A>&nbsp;&nbsp;</TD><TD align=left>&nbsp;&nbsp;<A href="functions/popd.txt">popd</A>&nbsp;&nbsp;</TD><TD align=left>&nbsp;&nbsp;<A href="functions/title.txt">title</A></TD></TR>
<TR><TD align=left>
<A href="functions/emacs_keybind.txt">emacs_keybind</A>&nbsp;&nbsp;</TD><TD align=left>&nbsp;&nbsp;<A href="functions/keybind.txt">keybind</A>&nbsp;&nbsp;</TD><TD align=left>&nbsp;&nbsp;<A href="functions/pushd.txt">pushd</A>&nbsp;&nbsp;</TD><TD align=left>&nbsp;&nbsp;<A href="functions/vi_keybind.txt">vi_keybind</A></TD></TR>
</TBODY></TABLE></TD></TR></TBODY></TABLE>
<P>
<P><HR><CENTER><FONT color=red><FONT face=courier><H3><A name="Sample Scripts">Sample Scripts</A></H3></FONT></FONT></CENTER>
<P></P><TABLE border=0 frame=void rules=none width=100%><TBODY><TR><TD>
<TABLE align=center bgcolor=papayawhip border=0 bordercolor=white cellpadding=2 cellspacing=2 frame=void rules=none >
<TBODY>
<TR><TD align=left>
<A href="scripts/cgi-lib.ksh.txt">cgi-lib.ksh</A>&nbsp;&nbsp;</TD><TD align=left>&nbsp;&nbsp;<A href="scripts/env.txt">env</A>&nbsp;&nbsp;</TD><TD align=left>&nbsp;&nbsp;<A href="scripts/which.txt">which</A>&nbsp;&nbsp;</TD><TD align=left>&nbsp;&nbsp;&nbsp;</TD></TR>
<TR><TD align=left>
<A href="scripts/dump-cgi.ksh.txt">dump-cgi.ksh</A>&nbsp;&nbsp;</TD><TD align=left>&nbsp;&nbsp;<A href="scripts/line.txt">line</A>&nbsp;&nbsp;</TD><TD align=left>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD><TD align=left>&nbsp;&nbsp;&nbsp;</TD></TR>
</TBODY></TABLE></TD></TR></TBODY></TABLE>
<P>
<HR>
<TABLE border=0 align=center width=96%>
<TR>
<TD align=left></TD>
<TD align=center></TD>
<TD align=right>March 13, 2012</TD>
</TR>
</TABLE>
<P>
</TD></TR></TBODY></TABLE>
</BODY>
</HTML>

1004
docs/ksh/faq.html Normal file

File diff suppressed because it is too large Load diff

207
docs/ksh/features.html Normal file
View file

@ -0,0 +1,207 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<HTML>
<HEAD>
<META name="generator" content="mm2html (AT&amp;T Research) 2012-01-11">
<TITLE> www/ksh/features.mm mm document </TITLE>
<META name="author" content="gsf+dgk+kpv">
<STYLE type="text/css">
div.FI { padding-left:2em; text-indent:0em; }
div.HI { padding-left:4em; text-indent:-2em; }
dt { float:left; clear:both; }
dd { margin-left:3em; }
</STYLE>
</HEAD>
<BODY bgcolor=white link=slateblue vlink=teal >
<TABLE border=0 align=center width=96%>
<TBODY><TR><TD valign=top align=left>
<!--INDEX--><!--/INDEX-->
<P>
<P><CENTER><FONT color=red><FONT face=courier><H3><A name="ksh features">ksh features</A></H3></FONT></FONT></CENTER>
KSH-93 is the most recent version of the KornShell Language described in
<EM>The KornShell Command and Programming Language</EM>,
by Morris Bolsky and David Korn of AT&amp;T Research (nee Bell Laboratories).
The KornShell is a shell programming language,
which is upward compatible with
<EM>sh</EM>
(the Bourne Shell),
and is intended to conform to the IEEE P1003.2/ISO 9945.2 Shell and
Utilities standard.
KSH-93 provides an enhanced programming environment in
addition to the major command-entry features of the BSD
shell
<EM>csh</EM>.
With KSH-93, medium-sized programming tasks can be
performed at shell-level without a significant loss in performance.
In addition,
<EM>sh</EM>
scripts can be run on KSH-93 without modification.
<P>
The code should conform to the IEEE POSIX 1003.1 standard and to the
proposed ANSI-C standard so that it should be portable to all
such systems.
Like the previous version, KSH-88,
it is designed to accept eight bit character sets
transparently, thereby making it internationally compatible.
It can support multi-byte characters sets with some characteristics
of the character set given at run time.
<P>
KSH-93 provides the following features, many of which were also inherent
in KSH-88:
<P>
<H4><A name="Enhanced Command Re-entry Capability">Enhanced Command Re-entry Capability</A></H4>
The KSH-93 history
function records commands entered at any shell level and stores
them, up to a user-specified limit, even after you log off.
This allows you to re-enter long commands with a few keystrokes
- even those commands you entered yesterday.
The history file allows for eight bit characters in
commands and supports essentially unlimited size histories.
<P>
<H4><A name="In-line Editing">In-line Editing</A></H4>
In
<EM>sh</EM>
the only way to fix mistyped
commands is to backspace or retype the line.
KSH-93 allows you
to edit a command line using a choice of EMACS-TC or
<EM>vi</EM>
functions.
You can use the in-line editors to complete filenames as
you type them.
You may also use this editing feature when entering
command lines from your history file.
A user can capture keystrokes and rebind keys to customize the
editing interface.
<P>
<H4><A name="Extended I/O Capabilities">Extended I/O Capabilities</A></H4>
KSH-93 provides several I/O
capabilities not available in
<EM>sh</EM>,
including the ability to:
<UL type=square>
<LI>
specify a file descriptor for input and output
<LI>
start up and run co-processes
<LI>
produce a prompt at the terminal before a read
<LI>
easily format and interpret responses to a menu
<LI>
echo lines exactly as output without escape processing
<LI>
format output using printf formats.
<LI>
read and echo lines ending in "&#0092;e".
</UL>
<P>
<H4><A name="Improved performance">Improved performance</A></H4>
KSH-93 executes many scripts faster
than the System V Bourne shell.
A major reason for this is
that many of the standard utilities are built-in.
To reduce the time to initiate a command, KSH-93 allows
commands to be added as built-ins at run time
on systems that support dynamic loading such as System V Release 4.
<P>
<H4><A name="Arithmetic">Arithmetic</A></H4>
KSH-93 allows you to do integer arithmetic in any
base from two to sixty-four.
You can also do double
precision floating point arithmetic.
Almost the complete set of C language operators are available
with the same syntax and precedence.
Arithmetic expressions can be used to as an argument expansion
or as a separate command.
In addition there is an arithmetic for command that works
like the for statement in C.
<P>
<H4><A name="Arrays">Arrays</A></H4>
KSH-93 supports both indexed and associative arrays.
The subscript for an indexed array is an arithmetic expression,
whereas, the subscript for an associative array is a string.
<P>
<H4><A name="Functions and Aliases">Functions and Aliases</A></H4>
Two mechanisms - functions and
aliases - can be used to assign a user-selected identifier to
an existing command or shell script.
Functions allow local variables and provide scoping
for exception handling.
Functions can be searched for and loaded on first reference the
way scripts are.
<P>
<H4><A name="Substring Capabilities">Substring Capabilities</A></H4>
KSH-93 allows you to create a
substring of any given string either by specifying the starting
offset and length, or by stripping off leading
or trailing substrings during parameter substitution.
You can also specify attributes, such as upper and lower case,
field width, and justification to shell variables.
<P>
<H4><A name="Enhanced pattern matching capabilities">Enhanced pattern matching capabilities</A></H4>
KSH-93 allows you to specify
regular expressions for file and string matches.
<P>
<H4><A name="Improved debugging">Improved debugging</A></H4>
KSH-93 can generate line numbers on execution traces.
Also, I/O redirections are now traced.
There is a DEBUG trap that gets evaluated after each command
so that errors can be localized.
<P>
<H4><A name="Job Control">Job Control</A></H4>
On systems that support job control, including
System V Release 4, KSH-93
provides a job-control mechanism almost identical to that of
the BSD "csh", version 4.1.
This feature allows you
to stop and restart programs, and to move programs between the
foreground and the background.
<P>
<H4><A name="Added security">Added security</A></H4>
KSH-93 can execute scripts which do not have read permission
and scripts which have the setuid and/or setgid set when
invoked by name, rather than as an argument to the shell.
It is possible to log or control the execution of setuid and/or
setgid scripts.
The noclobber option prevents you from accidentally erasing
a file by redirecting to an existing file.
<P>
<H4><A name="Documentation">Documentation</A></H4>
Documentation for KSH-93 consists of an
<EM>Introduction to KSH-93,</EM>
<EM>Compatibility with the Bourne Shell</EM>,
a manual page and a
README file.
In addition, the
<EM>New KornShell Command and Programming Language</EM>
book is available from Prentice Hall.
<P>
<HR>
<TABLE border=0 align=center width=96%>
<TR>
<TD align=left></TD>
<TD align=center></TD>
<TD align=right>March 13, 2012</TD>
</TR>
</TABLE>
<P>
</TD></TR></TBODY></TABLE>
</BODY>
</HTML>

111
docs/ksh/functions/dirs.txt Normal file
View file

@ -0,0 +1,111 @@
#
# DIRECTORY MANIPULATION FUNCTIONS PUSHD, POPD AND DIRS
#
# Uses global parameters _push_max _push_top _push_stack
integer _push_max=100 _push_top=100
# Display directory stack -- $HOME displayed as ~
function dirs
{
typeset dir="${PWD#$HOME/}"
case $dir in
$HOME)
dir=\~
;;
/*) ;;
*) dir=\~/$dir
esac
print -r - "$dir ${_push_stack[@]}"
}
# Change directory and put directory on front of stack
function pushd
{
typeset dir= type=0
integer i
case $1 in
"") # pushd
if ((_push_top >= _push_max))
then print pushd: No other directory.
return 1
fi
type=1 dir=${_push_stack[_push_top]}
;;
+[1-9]|+[1-9][0-9]) # pushd +n
integer i=_push_top$1-1
if ((i >= _push_max))
then print pushd: Directory stack not that deep.
return 1
fi
type=2 dir=${_push_stack[i]}
;;
*) if ((_push_top <= 0))
then print pushd: Directory stack overflow.
return 1
fi
esac
case $dir in
\~*) dir=$HOME${dir#\~}
esac
cd "${dir:-$1}" > /dev/null || return 1
dir=${OLDPWD#$HOME/}
case $dir in
$HOME)
dir=\~
;;
/*) ;;
*) dir=\~/$dir
esac
case $type in
0) # pushd name
_push_stack[_push_top=_push_top-1]=$dir
;;
1) # pushd
_push_stack[_push_top]=$dir
;;
2) # push +n
type=${1#+} i=_push_top-1
set -- "${_push_stack[@]}" "$dir" "${_push_stack[@]}"
shift $type
for dir
do (((i=i+1) < _push_max)) || break
_push_stack[i]=$dir
done
esac
dirs
}
# Pops the top directory
function popd
{
typeset dir
if ((_push_top >= _push_max))
then print popd: Nothing to pop.
return 1
fi
case $1 in
"")
dir=${_push_stack[_push_top]}
case $dir in
\~*) dir=$HOME${dir#\~}
esac
cd "$dir" || return 1
;;
+[1-9]|+[1-9][0-9])
typeset savedir
integer i=_push_top$1-1
if ((i >= _push_max))
then print pushd: Directory stack not that deep.
return 1
fi
while ((i > _push_top))
do _push_stack[i]=${_push_stack[i-1]}
i=i-1
done
;;
*) print pushd: Bad directory.
return 1
esac
unset '_push_stack[_push_top]'
_push_top=_push_top+1
dirs
}

View file

@ -0,0 +1,12 @@
typeset -A Keytable
trap 'eval "${Keytable[${.sh.edchar}]}"' KEYBD
function emacs_keybind
{
keybind $'\E[A' $'\020' # Up key
keybind $'\E[B' $'\016' # Down key
keybind $'\E[C' $'\06' # Right key
keybind $'\E[D' $'\02' # Left key
keybind $'\E[H' $'\01' # Home key
keybind $'\E[Y' $'\05' # End key
keybind $'\t' $'\E\E' # Tab for command-line completion
}

View file

@ -0,0 +1,28 @@
function getopt
{
typeset c optstring=$1 options= sep=
shift
while getopts $optstring c
do case $c in
[:?])
exit 2
;;
*)
options="$options$sep-$c"
sep=' '
if [[ $optstring == *$c:* ]]
then options=" $options $OPTARG"
fi
#then print -rn -- " -$c" "$OPTARG"
#else print -rn -- " -$c"
;;
esac
done
print -rn -- "$options"
if [[ ${@:$OPTIND-1} != -- ]]
then print -rn -- " --"
fi
if [[ -n ${@:$OPTIND} ]]
then print -r -- " ${@:$OPTIND}"
fi
}

View file

@ -0,0 +1,14 @@
typeset -A Keytable
trap 'eval "${Keytable[${.sh.edchar}]}"' KEYBD
function keybind # key action
{
typeset key=$(print -f "%q" "$2")
case $# in
2) Keytable[$1]='.sh.edchar=${.sh.edmode}'"$key"
;;
1) unset Keytable[$1]
;;
*) print -u2 "Usage: $0 key [action]"
;;
esac
}

111
docs/ksh/functions/popd.txt Normal file
View file

@ -0,0 +1,111 @@
#
# DIRECTORY MANIPULATION FUNCTIONS PUSHD, POPD AND DIRS
#
# Uses global parameters _push_max _push_top _push_stack
integer _push_max=100 _push_top=100
# Display directory stack -- $HOME displayed as ~
function dirs
{
typeset dir="${PWD#$HOME/}"
case $dir in
$HOME)
dir=\~
;;
/*) ;;
*) dir=\~/$dir
esac
print -r - "$dir ${_push_stack[@]}"
}
# Change directory and put directory on front of stack
function pushd
{
typeset dir= type=0
integer i
case $1 in
"") # pushd
if ((_push_top >= _push_max))
then print pushd: No other directory.
return 1
fi
type=1 dir=${_push_stack[_push_top]}
;;
+[1-9]|+[1-9][0-9]) # pushd +n
integer i=_push_top$1-1
if ((i >= _push_max))
then print pushd: Directory stack not that deep.
return 1
fi
type=2 dir=${_push_stack[i]}
;;
*) if ((_push_top <= 0))
then print pushd: Directory stack overflow.
return 1
fi
esac
case $dir in
\~*) dir=$HOME${dir#~}
esac
cd "${dir:-$1}" > /dev/null || return 1
dir=${OLDPWD#$HOME/}
case $dir in
$HOME)
dir=\~
;;
/*) ;;
*) dir=\~/$dir
esac
case $type in
0) # pushd name
_push_stack[_push_top=_push_top-1]=$dir
;;
1) # pushd
_push_stack[_push_top]=$dir
;;
2) # push +n
type=${1#+} i=_push_top-1
set -- "${_push_stack[@]}" "$dir" "${_push_stack[@]}"
shift $type
for dir
do (((i=i+1) < _push_max)) || break
_push_stack[i]=$dir
done
esac
dirs
}
# Pops the top directory
function popd
{
typeset dir
if ((_push_top >= _push_max))
then print popd: Nothing to pop.
return 1
fi
case $1 in
"")
dir=${_push_stack[_push_top]}
case $dir in
\~*) dir=$HOME${dir#~}
esac
cd "$dir" || return 1
;;
+[1-9]|+[1-9][0-9])
typeset savedir
integer i=_push_top$1-1
if ((i >= _push_max))
then print pushd: Directory stack not that deep.
return 1
fi
while ((i > _push_top))
do _push_stack[i]=${_push_stack[i-1]}
i=i-1
done
;;
*) print pushd: Bad directory.
return 1
esac
unset '_push_stack[_push_top]'
_push_top=_push_top+1
dirs
}

View file

@ -0,0 +1,111 @@
#
# DIRECTORY MANIPULATION FUNCTIONS PUSHD, POPD AND DIRS
#
# Uses global parameters _push_max _push_top _push_stack
integer _push_max=100 _push_top=100
# Display directory stack -- $HOME displayed as ~
function dirs
{
typeset dir="${PWD#$HOME/}"
case $dir in
$HOME)
dir=\~
;;
/*) ;;
*) dir=\~/$dir
esac
print -r - "$dir ${_push_stack[@]}"
}
# Change directory and put directory on front of stack
function pushd
{
typeset dir= type=0
integer i
case $1 in
"") # pushd
if ((_push_top >= _push_max))
then print pushd: No other directory.
return 1
fi
type=1 dir=${_push_stack[_push_top]}
;;
+[1-9]|+[1-9][0-9]) # pushd +n
integer i=_push_top$1-1
if ((i >= _push_max))
then print pushd: Directory stack not that deep.
return 1
fi
type=2 dir=${_push_stack[i]}
;;
*) if ((_push_top <= 0))
then print pushd: Directory stack overflow.
return 1
fi
esac
case $dir in
\~*) dir=$HOME${dir#\~}
esac
cd "${dir:-$1}" > /dev/null || return 1
dir=${OLDPWD#$HOME/}
case $dir in
$HOME)
dir=\~
;;
/*) ;;
*) dir=\~/$dir
esac
case $type in
0) # pushd name
_push_stack[_push_top=_push_top-1]=$dir
;;
1) # pushd
_push_stack[_push_top]=$dir
;;
2) # push +n
type=${1#+} i=_push_top-1
set -- "${_push_stack[@]}" "$dir" "${_push_stack[@]}"
shift $type
for dir
do (((i=i+1) < _push_max)) || break
_push_stack[i]=$dir
done
esac
dirs
}
# Pops the top directory
function popd
{
typeset dir
if ((_push_top >= _push_max))
then print popd: Nothing to pop.
return 1
fi
case $1 in
"")
dir=${_push_stack[_push_top]}
case $dir in
\~*) dir=$HOME${dir#\~}
esac
cd "$dir" || return 1
;;
+[1-9]|+[1-9][0-9])
typeset savedir
integer i=_push_top$1-1
if ((i >= _push_max))
then print pushd: Directory stack not that deep.
return 1
fi
while ((i > _push_top))
do _push_stack[i]=${_push_stack[i-1]}
i=i-1
done
;;
*) print pushd: Bad directory.
return 1
esac
unset '_push_stack[_push_top]'
_push_top=_push_top+1
dirs
}

View file

@ -0,0 +1,54 @@
# add to (+), delete from (-), print (.), or set ([=]) window title
# arguments are eval'd before printing
# title text string exported in TITLE_TEXT
function title # [+ | - | =] title ...
{
typeset x t="$TITLE_TEXT"
case $1 in
+) shift
case $# in
0) ;;
*) for x
do case " $t " in
*" $x "*) ;;
" ") t=$x ;;
*) t="$t $x" ;;
esac
done
case $t in
$TITLE_TEXT) return 1 ;;
esac
;;
esac
;;
-) shift
case $# in
0) ;;
*) for x
do case " $t " in
*" $x "*) t="${t%?( )$x*}${t##*$x?( )}" ;;
esac
done
case $t in
$TITLE_TEXT) return 1 ;;
esac
;;
esac
;;
.) print -r -- "$TITLE_TEXT"
return 0
;;
*) t="$*"
;;
esac
export TITLE_TEXT="$t"
eval x=\"$t\"
case $TERM in
630*) print -nr -- "[?${#x};0v$x" ;;
vt100|xterm*) print -nr -- "]0;$x" ;;
*) return 1 ;;
esac
return 0
}

View file

@ -0,0 +1,10 @@
typeset -A Keytable
trap 'eval "${Keytable[${.sh.edchar}]}"' KEYBD
function vi_keybind
{
keybind $'\E[A' k # Up key
keybind $'\E[B' j # Down key
keybind $'\E[C' l # Right key
keybind $'\E[D' h # Left key
keybind $'\t' '\' # Tab for command-line completion
}

10
docs/ksh/index.html Normal file
View file

@ -0,0 +1,10 @@
<html>
<head><title>KSH93</title></head>
<body>
<a href='ksh.html'>Overview</a><br>
<a href='faq.html'>FAQ</a><br>
<a href='features.html'>Features</a><br>
<a href='builtins.html'>Builtins</a><br>
<a href='examples.html'>Examples</a>
</body>
</html>

118
docs/ksh/ksh.html Normal file
View file

@ -0,0 +1,118 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<HTML>
<HEAD>
<META name="generator" content="mm2html (AT&amp;T Research) 2012-01-11">
<TITLE> www/ksh/ksh.mm mm document </TITLE>
<META name="author" content="gsf+dgk+kpv">
<STYLE type="text/css">
div.FI { padding-left:2em; text-indent:0em; }
div.HI { padding-left:4em; text-indent:-2em; }
dt { float:left; clear:both; }
dd { margin-left:3em; }
</STYLE>
</HEAD>
<BODY bgcolor=white link=slateblue vlink=teal >
<TABLE border=0 align=center width=96%>
<TBODY><TR><TD valign=top align=left>
<!--INDEX--><!--/INDEX-->
<P>
<P><CENTER><FONT color=red><FONT face=courier><H3><A name="ksh overview">ksh overview</A></H3></FONT></FONT></CENTER>
The
<STRONG>KornShell</STRONG>
language was designed and developed by David G. Korn at AT&amp;T Bell Laboratories and AT&amp;T Research.
It is an interactive command language that provides access to the UNIX system and to many other systems,
on the many different computers and workstations on which it is implemented.
The
<STRONG>KornShell</STRONG>
language is also a complete, powerful, high-level programming language for writing applications,
often more easily and quickly than with other high-level languages.
This makes it especially suitable for prototyping.
There are two other widely used shells, the Bourne shell developed by Steven Bourne at AT&amp;T Bell Laboratories,
and the C shell developed by Bill Joy at the University of California.
<STRONG>ksh</STRONG>
has the best features of both, plus many new features of its own.
Thus
<STRONG>ksh</STRONG>
can do much to enhance your productivity and the quality of your work,
both in interacting with the system, and in programming.
<STRONG>ksh</STRONG>
programs are easier to write, and are more concise and readable than programs written in a lower level language such as C.
<P>
The new version of
<STRONG>ksh</STRONG>
has the functionality of other scripting languages such as awk, icon, perl, rexx, and tcl.
For this and many other reasons,
<STRONG>ksh</STRONG>
is a much better scripting language than any of the other popular shells.
The code size for
<STRONG>ksh</STRONG>
is larger than the Bourne shell or C shell programs.
The revised version is even larger.
<P>
In spite of its increased size,
<STRONG>ksh</STRONG>
provides better performance.
You can write programs to run faster with
<STRONG>ksh</STRONG>
than with either the Bourne shell or the C shell, sometimes an order of magnitude faster.
<STRONG>ksh</STRONG>
has evolved and matured with extensive user feedback.
It has been used by many thousands of people at AT&amp;T since 1982, and at many other companies and universities.
A survey conducted at one of the largest AT&amp;T Bell Laboratories computer centers showed that 80% of their customers, both programmers and non-programmers, use
<STRONG>ksh.</STRONG>
<STRONG>ksh</STRONG>
is compatible with the Bourne shell.
Virtually all programs written for the Bourne shell run with
<STRONG>ksh.</STRONG>
If you are familiar with the Bourne shell, you can use
<STRONG>ksh</STRONG>
immediately, without retraining.
The new version of
<STRONG>ksh</STRONG>
is compatible with earlier versions of
<STRONG>ksh.</STRONG>
<STRONG>ksh</STRONG>
is readily available.
It is sold (source and binary) by AT&amp;T and Novell, and by other companies under license from AT&amp;T both in the USA and abroad.
It has been purchased by dozens of major corporations, and by many individuals for use on home computers.
<STRONG>ksh</STRONG>
is extensible.
<P>
The
<STRONG>KornShell</STRONG>
language uses the same syntax for built-in commands as for non built-in commands.
Therefore, system developers can add new commands "transparently" to the
<STRONG>KornShell</STRONG>
language; that is, with minimum effort and with no differences visible to users other than faster execution.
On systems with dynamic linking, it is possible to add new built-in commands at run time.
Novell has extended the new version of
<STRONG>ksh</STRONG>
to enable X-windows programming for their desktop
<STRONG>ksh</STRONG>
product,
<STRONG>dtksh</STRONG>.
<STRONG>dtksh</STRONG>
is a standard part of CDE, the Common Desktop Environment defined by COSE (Common Operating System Environment), supported by most major UNIX system hardware vendors.
An extended version of
<STRONG>ksh</STRONG>
that enables Tk programming, called tksh, is available as well.
<P>
<STRONG>ksh</STRONG>
is intended to conform to the Shell Language Standard developed by the IEEE POSIX 1003.2 Shell and Utilities Language Committee.
<P>
<HR>
<TABLE border=0 align=center width=96%>
<TR>
<TD align=left></TD>
<TD align=center></TD>
<TD align=right>March 13, 2012</TD>
</TR>
</TABLE>
<P>
</TD></TR></TBODY></TABLE>
</BODY>
</HTML>

View file

@ -0,0 +1,129 @@
typeset -A COOKIE HEADER
typeset Cgi _CGI_c _CGI_multipart
function cgi_header
{
typeset h
for h in "${!HEADER[@]}"
do printf '%s: %s\n' "$h" "${HEADER[$h]}"
done
print
}
function cgi_url
{
if [[ $SERVER_PORT != 80 ]]
then print "http://$SERVER_NAME:$SERVER_PORT$SCRIPT_NAME"
else print "http://$SERVER_NAME$SCRIPT_NAME"
fi
}
function cgi_parse
{
if [[ $REQUEST_METHOD == POST ]]
then if [[ $CONTENT_TYPE == multipart/form-data* ]]
then _CGI_multipart=${TMPDIR-/tmp}/cgi-form-$$
trap 'rm -rf "$_CGI_multipart"' EXIT
mkdir $_CGI_multipart
unset -f Cgi.set
typeset -A Cgi.file
typeset i b v
pax --nosummary --read --edit ",.*/,," --edit ",^,$_CGI_multipart/,"
for i in $_CGI_multipart/*
do b=${i##*/}
if [[ $b == +([a-z]) ]]
then v=$(<$i)
eval Cgi.$b='$v'
else Cgi.file[$b]=$i
fi
done
else Cgi=$(<&0) # Read from stdin
fi
else Cgi="$QUERY_STRING"
fi
cgi_cookie "$HTTP_COOKIE"
HEADER["Content-type"]="text/html"
}
function cgi_cookie
{
typeset cookie=$1 name val c IFS=';'
set -- $cookie
for c
do
IFS='='
set -- $c
name=${1##' '} val=${2##' '} # trim white space
name=${name%%' '} val=${val%%' '}
COOKIE[$name]=$val
done
}
function cgi_setcookie # name value
{
HEADER["Set-Cookie"]="$1=$2; path=$SCRIPT_NAME"
}
## Cgi variable disciplines
function Cgi.set
{
set -f
typeset i j n val IFS='&'
set -- ${.sh.value}
for i
do n=${i%%=*}
[[ $n == [[:alpha:]_]*([[:alnum:]_]) ]] || continue
val=${i#$n=}
val=${val//+/ }
val=${val//@([\'\\])/'\'\1}
eval j=\${#${.sh.name}.${n}[@]} \
"${.sh.name}.${n}[j]=\$'${val//'%'@(??)/'\x'\1"'\$'"}'"
done
}
function cgi_C_init
{
integer i
for ((i=1; i < 256; i++))
do if (( i!=16#22 && i!=16#27 && i!=16#5C && i!=16#5B && i!=16#5D ))
then printf $'_CGI_c[$\'\\\\x%.2X\']=%%%.2X\n' $i $i
fi
done
print
}
function cgi_encode
{
typeset v=$1
var=${v//' '/+}
cbrace='}'
eval var=${var//@([!a-zA-Z0-9_+])/\${_CGI_c[\\\1]$cbrace}
print -r -- "$var"
}
function Cgi.get
{
typeset i val name vname
if [[ ! ${_CGI_c[\\]} ]]
then val='"'
_CGI_c[""]=%00
_CGI_c[$var]=%22
_CGI_c[\']=%27
_CGI_c[\]]=%5B
_CGI_c[\[]=%5D
_CGI_c[\\]=%5C
eval $(cgi_C_init)
unset -f cgi_C_init
fi
vname=${.sh.name} # .sh.name contains variable name
.sh.value= # .sh.value stores value
for i in ${!Cgi.@}
do
name=${i#$vname.}
nameref v=${i}
val=$(cgi_encode "$v")
.sh.value="${.sh.value}${.sh.value:+&}$name=$val"
done
}

View file

@ -0,0 +1,17 @@
#!/bin/ksh
. ./cgi-lib.ksh
cgi_parse
cgi_header
print "<html>"
print "<pre>"
print -r "Url: $(cgi_url)"
for i in ${!Cgi.*}
do
nameref val=$i
print -r "$i = $val"
done
print "</pre>"
print "</html>"

66
docs/ksh/scripts/env.txt Normal file
View file

@ -0,0 +1,66 @@
#! /usr/bin/ksh
# shell version of env command
case $(getopts '[-]' opt '--???man' 2>&1) in
version=[0-9]*)
usage=$'[-?@(#)env (AT&T Labs Research) 1999-05-20\n]
[-author?David Korn <dgkorn@gmail.com>]
[-license?http://www.research.att.com/sw/tools/reuse]
[+NAME?env - set environment for command invocation]
[+DESCRIPTION?\benv\b modifies the current environment according
to the \aname\a\b=\b\avalue\a arguments, and then
invokes \acommand\a with the modified environment.]
[+?If \acommand\a is not specified, the resulting environment
is written to standard output quoted as required for
reading by the \bsh\b.]
[i:ignore-environment?Invoke \acommand\a with the exact environment
specified by the \aname\a\b=\b\avalue\a arguments; inherited
environment variables are ignored. As an obsolete feature,
\b-\b by itself can be specified instead of \b-i\b.]
[u:unset]:[name?Unset the environment variable \aname\a if it was
in the environment. This option can be repeated to unset
additional variables.]
[name=value]... [command ...]
[+EXIT STATUS?If \acommand\a is invoked, the exit status of \benv\b
will be that of \acommand\a. Otherwise, it will be one of
the following:]{
[+0?\benv\b completed successfully.]
[+126?\acommand\a was found but could not be invoked.]
[+127?\acommand\a could not be found.]
}
[+SEE ALSO?\bsh\b(1), \bexport\b(1)]
'
;;
*)
usage='iu:[name] [name=value]... [command ...]'
;;
esac
clear=
while getopts "$usage" var
do case $var in
i) clear=1;;
u) command unset $OPTARG 2> /dev/null;;
esac
done
#[[ $var == "" ]] || exit 1
shift $((OPTIND-1))
if [[ $1 == - ]] # obsolete form
then clear=1
shift
fi
if [[ $clear == 1 ]]
then typeset +x $(typeset +x)
fi
while true
do case $1 in
*=*) export "$1";;
*) break;;
esac
shift
done
if (( $# >0 ))
then exec "$@"
else export
exit 0
fi

View file

@ -0,0 +1,2 @@
#! /bin/ksh
read -r && print -r -- "$REPLY"

View file

@ -0,0 +1,2 @@
#! /bin/ksh
whence -p "$@"