diff options
Diffstat (limited to 'usr/src/lib/libshell/common/builtins.mm')
-rw-r--r-- | usr/src/lib/libshell/common/builtins.mm | 631 |
1 files changed, 0 insertions, 631 deletions
diff --git a/usr/src/lib/libshell/common/builtins.mm b/usr/src/lib/libshell/common/builtins.mm deleted file mode 100644 index 5713c48eab..0000000000 --- a/usr/src/lib/libshell/common/builtins.mm +++ /dev/null @@ -1,631 +0,0 @@ -.ds DT July 9, 1993 \" use troff -mm -.nr C 3 -.nr N 2 -.SA 1 \" right justified -.TL "311466-6713" "49059-6" \" charging case filing case -Guidelines for writing \f5ksh-93\fP built-in commands -.AU "David G. Korn" DGK FP 11267 8062 D-237 "(research!dgk)" -.AF -.TM 11267-930???-93 \" technical memo + TM numbers -.MT 4 -.AS 2 \" abstract start for TM -One of the features of \f5ksh93\fP, the latest version of \f5ksh\fP, -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 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 -to can be loaded into \f5ksh\fP at run time as built-in -commands. -.AE \" abstract end -.OK Shell "Command interpreter" Language UNIX \" keyword -.MT 1 \" memo type -.H 1 INTRODUCTION -A built-in command is executed without creating a separate process. -Instead, the command is invoked as a C function by \f5ksh\fP. -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 do -run \f5wc\fP on a small file of about 1000 bytes, runs -about 50 times faster as a built-in command. -.P -In addition, built-in commands that have side effects on the -shell environment can be written. -This is usually done to extend the application domain for -shell programming. For example, an X-windows extension -that makes heavy use of the shell variable namespace -was added as a group of built-ins commands that -are added at run time. -The result is 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 \f5ksh\fP share the same -address space, a coding error in the built-in program -may affect the behavior of \f5ksh\fP; 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. -Also, since the address space of \f5ksh\fP will be larger, -this may increase the time it takes \f5ksh\fP to fork() and -exec() a non-builtin command. -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 \f5ksh\fP making -the overall system less modular and more monolithic. -.P -Despite these drawbacks, in many cases extending -\f5ksh\fP 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 \f5ksh\fP extensions. -.H 1 "WRITING BUILT-IN COMMANDS" -There is a development kit available for writing \f5ksh\fP -built-ins. The development kit has three directories, -\f5include\fP, \f5lib\fP, and \f5bin\fP. -The \f5include\fP directory contains a sub-directory -named \f5ast\fP that contains interface prototypes -for functions that you can call from built-ins. The \f5lib\fP -directory contains the \fBast\fP library\*F -.FS -\fBast\fP stands for Advanced Software Technology -.FE -and a library named \fBlibcmd\fP that contains a version -of several of the standard POSIX\*(Rf -.RS -.I "POSIX \- Part 2: Shell and Utilities," -IEEE Std 1003.2-1992, ISO/IEC 9945-2:1993. -.RF -utilities that can be made run time built-ins. -It is best to set the value of the environment variable -\fB\s-1PACKAGE_\s+1ast\fP to the pathname of the directory -containing the development kit. -Users of \f5nmake\fP\*(Rf -.RS -Glenn Fowler, -Nmake reference needed -.RF -2.3 and above will then be able to -use the rule -.nf -.in .5i -\f5:PACKAGE: ast\fP -.in -.fi -in their makefiles and not have to specify any \f5-I\fP switches -to the compiler. -.P -A built-in command has a calling convention similar to -the \f5main\fP function of a program, -.nf -.in .5i -\f5int main(int argc, char *argv[])\fP. -.in -.fi -However, instead of \f5main\fP, you must use the function name -\f5b_\fP\fIname\fP, where \fIname\fP is the name -of the built-in you wish to define. -The built-in function takes a third -\f5void*\fP argument which you can define as \f5NULL\fP. -Instead of \f5exit\fP, you need to use \f5return\fP -to terminate your command. -The return value, will become the exit status of the command. -.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 \f5hello\fP -which requires one argument and prints the word hello followed -by its argument. First, write the following program in the file -\f5hello.c\fP: -.nf -.in .5i -\f5#include <stdio.h> -int b_hello(int argc, char *argv[], void *context) -{ - if(argc != 2) - { - fprintf(stderr,"Usage: hello arg\en"); - return(2); - } - printf("hello %s\en",argv[1]); - return(0); -}\fP -.in -.fi -.P -Next, the program needs to be compiled. -On some systems it is necessary to specify a compiler -option to produce position independent code -for dynamic linking. -If you do not compile with \f5nmake\fP -it is important to specify the a special include directory -when compiling built-ins. -.nf -.in .5i -\f5cc -pic -I$PACKAGE_ast/include -c hello.c\fP -.in -.fi -since the special version of \f5<stdio.h>\fP -in the development kit is required. -This command generates \f5hello.o\fP in the current -directory. -.P -On some systems, you cannot load \f5hello.o\fP directly, -you must build a shared library instead. -Unfortunately, the method for generating a shared library -differs with operating system. -However, if you are building with the AT\&T \f5nmake\fP -program you can use the \f5:LIBRARY:\fP rule to specify -this in a system independent fashion. -In addition, 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 \f5ksh\fP command \f5builtin\fP. -To load the shared library \f5hello.so\fP and to add -the built-in \f5hello\fP, invoke the command, -.nf -.in .5i -\f5builtin -f hello hello\fP -.in -.fi -The suffix for the shared library can be omitted in -which case the shell will add an appropriate suffix -for the system that it is loading from. -Once this command has been invoked, you can invoke \f5hello\fP -as you do any other command. -.P -It is often desirable to make a command \fIbuilt-in\fP -the first time that it is referenced. The first -time \f5hello\fP is invoked, \f5ksh\fP should load and execute it, -whereas for subsequent invocations \f5ksh\fP should just execute the built-in. -This can be done by creating a file named \f5hello\fP -with the following contents: -.nf -.in .5i -\f5function hello -{ - unset -f hello - builtin -f hello hello - hello "$@" -}\fP -.in -.fi -This file \f5hello\fP needs to be placed in a directory that is -in your \fB\s-1FPATH\s+1\fP variable. In addition, the full -pathname for \f5hello.so\fP should be used in this script -so that the run time loader will be able to find this shared library -no matter where the command \f5hello\fP is invoked. -.H 1 "CODING REQUIREMENTS AND CONVENTIONS" -As mentioned above, the entry point for built-ins must be of -the form \f5b_\fP\fIname\fP. -Your built-ins can call functions from the standard C library, -the \fBast\fP library, interface functions provided by \f5ksh\fP, -and your own functions. -You should avoid using any global symbols beginning with -.BR sh_ , -.BR nv_ , -and -.B ed_ -since these are used by \f5ksh\fP itself. -In addition, \f5#define\fP constants in \f5ksh\fP interface -files, use symbols beginning with \fBSH_\fP to that you should -avoid using names beginning with \fBSH_\fP. -.H 2 "Header Files" -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&R C\*(Rf, -.RS -Brian W. Kernighan and Dennis M. Ritchie, -.IR "The C Programming Language" , -Prentice Hall, 1978. -.RF -ANSI-C\*(Rf, -.RS -American National Standard for Information Systems \- Programming -Language \- C, ANSI X3.159-1989. -.RF -and C++\*(Rf. -.RS -Bjarne Stroustroup, -.IR "C++" , -Addison Wesley, xxxx -.RF -.P -The best thing to do is to include the header file \f5<shell.h>\fP. -This header file causes the \f5<ast.h>\fP header, the -\f5<error.h>\fP header and the \f5<stak.h>\fP -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 \f5<ast.h>\fP -provides prototypes for many \fBlibast\fP functions -and all the symbol and function definitions from the -ANSI-C headers, \f5<stddef.h>\fP, -\f5<stdlib.h>\fP, \f5<stdarg.h>\fP, \f5<limits.h>\fP, -and \f5<string.h>\fP. -It also provides all the symbols and definitions for the -POSIX\*(Rf -.RS -.I "POSIX \- Part 1: System Application Program Interface," -IEEE Std 1003.1-1990, ISO/IEC 9945-1:1990. -.RF -headers \f5<sys/types.h>\fP, \f5<fcntl.h>\fP, and -\f5<unistd.h>\fP. -You should include \f5<ast.h>\fP instead of one or more of -these headers. -The \f5<error.h>\fP header provides the interface to the error -and option parsing routines defined below. -The \f5<stak.h>\fP header provides the interface to the memory -allocation routines described below. -.P -Programs that want to use the information in \f5<sys/stat.h>\fP -should include the file \f5<ls.h>\fP instead. -This provides the complete POSIX interface to \f5stat()\fP -related functions even on non-POSIX systems. -.P -.H 2 "Input/Output" -\f5ksh\fP uses \fBsfio\fP, -the Safe/Fast I/O library\*(Rf, -.RS -David Korn and Kiem-Phong Vo, -.IR "SFIO - A Safe/Fast Input/Output library," -Proceedings of the Summer Usenix, -pp. , 1991. -.RF -to perform all I/O operations. -The \fBsfio\fP library, which is part of \fBlibast\fP, -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 \fBsfio\fP and -you do not want to spend the time learning it, -then you can use \fBsfio\fP via the \fBstdio\fP library -interface. The development kit contains the header \f5<stdio.h>\fP -which maps \fBstdio\fP calls to \fBsfio\fP calls. -In most instances the mapping is done -by macros or inline functions so that there is no overhead. -The man page for the \fBsfio\fP library is in an Appendix. -.P -However, there are some very nice extensions and -performance improvements in \fBsfio\fP -and if you plan any major extensions I recommend -that you use it natively. -.H 2 "Error Handling" -For error messages it is best to use the \fBast\fP library -function \f5errormsg()\fP rather that sending output to -\f5stderr\fP or the equivalent \f5sfstderr\fP directly. -Using \f5errormsg()\fP will make error message appear -more uniform to the user. -Furthermore, using \f5errormsg()\fP should make it easier -to do error message translation for other locales -in future versions of \f5ksh\fP. -.P -The first argument to -\f5errormsg()\fP specifies the dictionary in which the string -will be searched for translation. -The second argument to \f5errormsg()\fP contains that error type -and value. The third argument is a \fIprintf\fP 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: -.VL .5i -.LI \f5ERROR_exit(\fP\fIn\fP\f5)\fP: -If \fIn\fP is not-zero, the builtin will exit value \fIn\fP after -printing the message. -.LI \f5ERROR_system(\fP\fIn\fP\f5)\fP: -Exit builtin with exit value \fIn\fP after printing the message. -The message will display the message corresponding to \f5errno\fP -enclosed within \f5[\ ]\fP at the end of the message. -.LI \f5ERROR_usage(\fP\fIn\fP\f5)\fP: -Will generate a usage message and exit. If \fIn\fP is non-zero, -the exit value will be 2. Otherwise the exit value will be 0. -.LI \f5ERROR_debug(\fP\fIn\fP\f5)\fP: -Will print a level \fIn\fP debugging message and will then continue. -.LI \f5ERROR_warn(\fP\fIn\fP\f5)\fP: -Prints a warning message. \fIn\fP is ignored. -.H 2 "Option Parsing" -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 \f5ksh\fP, it is best -to use the \f5libast\fP functions \f5optget()\fP and -\f5optusage()\fPfor this -purpose. -The header \f5<error.h>\fP included prototypes for -these functions. -The \f5optget()\fP function is similar to the -System V C library function \f5getopt()\fP, -but provides some additional capabilities. -Built-ins that use \f5optget()\fP provide a more -consistent user interface. -.P -The \f5optget()\fP function is invoked as -.nf -.in .5i -\f5int optget(char *argv[], const char *optstring)\fP -.in -.fi -where \f5argv\fP is the argument list and \f5optstring\fP -is a string that specifies the allowable arguments and -additional information that is used to format \fIusage\fP -messages. -In fact a complete man page in \f5troff\fP or \f5html\fP -can be generated by passing a usage string as described -by the \f5getopts\fP command. -Like \f5getopt()\fP, -single letter options are represented by the letter itself, -and options that take a string argument are followed by the \f5:\fP -character. -Option strings have the following special characters: -.VL .5i -.LI \f5:\fP -Used after a letter option to indicate that the option -takes an option argument. -The variable \f5opt_info.arg\fP will point to this -value after the given argument is encountered. -.LI \f5#\fP -Used after a letter option to indicate that the option -can only take a numerical value. -The variable \f5opt_info.num\fP will contain this -value after the given argument is encountered. -.LI \f5?\fP -Used after a \f5:\fP or \f5#\fP (and after the optional \f5?\fP) -to indicate the the -preceding option argument is not required. -.LI \f5[\fP...\f5]\fP -After a \f5:\fP or \f5#\fP, the characters contained -inside the brackets are used to identify the option -argument when generating a \fIusage\fP message. -.LI \fIspace\fP -The remainder of the string will only be used when generating -usage messages. -.LE -.P -The \f5optget()\fP function returns the matching option letter if -one of the legal option is matched. -Otherwise, \f5optget()\fP returns -.VL .5i -.LI \f5':'\fP -If there is an error. In this case the variable \f5opt_info.arg\fP -contains the error string. -.LI \f50\fP -Indicates the end of options. -The variable \f5opt_info.index\fP contains the number of arguments -processed. -.LI \f5'?'\fP -A usage message has been required. -You normally call \f5optusage()\fP to generate and display -the usage message. -.LE -.P -The following is an example of the option parsing portion -of the \f5wc\fP utility. -.nf -.in +5 -\f5#include <shell.h> -while(1) switch(n=optget(argv,"xf:[file]")) -{ - 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; -}\fP -.in -.fi -.H 2 "Storage Management" -It is important that any memory used by your built-in -be returned. Otherwise, if your built-in is called frequently, -\f5ksh\fP will eventually run out of memory. -You should avoid using \f5malloc()\fP for memory that must -be freed before returning from you built-in, because by default, -\f5ksh\fP 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 \fBstak\fP library -which is included in \fBlibast\fP -and which is used extensively by \f5ksh\fP itself. -Objects allocated with the \f5stakalloc()\fP -function are freed when you function completes -or aborts. -The \fBstak\fP library provides a convenient way to -build variable length strings and other objects dynamically. -The man page for the \fBstak\fP library is contained -in the Appendix. -.P -Before \f5ksh\fP 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 \f5b_\fP 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: -.nf -.in .5i -\fIyourfunction\fP\f5() -{ - char *savebase; - int saveoffset; - if(saveoffset=staktell()) - savebase = stakfreeze(0); - \fP...\f5 - if(saveoffset) - stakset(savebase,saveoffset); - else - stakseek(0); -}\fP -.in -.fi -.H 1 "CALLING \f5ksh\fP SERVICES" -Some of the more interesting applications are those that extend -the functionality of \f5ksh\fP in application specific directions. -A prime example of this is the X-windows extension which adds -builtins to create and delete widgets. -The \fBnval\fP library is used to interface with the shell -name space. -The \fBshell\fP library is used to access other shell services. -.H 2 "The nval library" -A great deal of power is derived from the ability to use -portions of the hierarchal variable namespace provided by \f5ksh-93\fP -and turn these names into active objects. -.P -The \fBnval\fP 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 \f5<nval.h>\fP -to access the functions defined in the \fBnval\fP library. -All the functions provided by the \fBnval\fP library begin -with the prefix \f5nv_\fP. -Each shell variable is an object in an associative table -that is referenced by name. -The type \f5Namval_t*\fP is pointer to a shell variable. -To operate on a shell variable, you first get a handle -to the variable with the \f5nv_open()\fP function -and then supply the handle returned as the first -argument of the function that provides an operation -on the variable. -You must call \f5nv_close()\fP 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 \f5nv_getval()\fP 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 \f5nv_getval()\fP call -so that if the value isn't used immediately, it should -be copied. -Many variables can also generate a numeric value. -The \f5nv_getnum()\fP function returns a numeric -value for the given variable pointer, calling the -arithmetic evaluator if necessary. -.P -The \f5nv_putval()\fP function is used to assign a new -value to a given variable. -The second argument to \f5putval()\fP is the value -to be assigned -and the third argument is a \fIflag\fP which -is used in interpreting the second argument. -.P -Each shell variable can have one or more attributes. -The \f5nv_isattr()\fP 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 \f5nv_putval()\fP, and returns the value -with \f5getval()\fP. However, it is possible to turn -any node into an active entity by assigning functions -to it that will be called whenever \f5nv_putval()\fP -and/or \f5nv_getval()\fP is called. -In fact there are up to five functions that can -associated with each variable to override the -default actions. -The type \f5Namfun_t\fP is used to define these functions. -Only those that are non-\f5NULL\fP override the -default actions. -To override the default actions, you must allocate an -instance of \f5Namfun_t\fP, and then assign -the functions that you wish to override. -The \f5putval()\fP -function is called by the \f5nv_putval()\fP function. -A \f5NULL\fP for the \fIvalue\fP argument -indicates a request to unset the variable. -The \fItype\fP argument might contain the \f5NV_INTEGER\fP -bit so you should be prepared to do a conversion if -necessary. -The \f5getval()\fP -function is called by \f5nv_getval()\fP -value and must return a string. -The \f5getnum()\fP -function is called by by the arithmetic evaluator -and must return double. -If omitted, then it will call \f5nv_getval()\fP 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 -\fIvarname\fP\f5.\fP\fIdiscname\fP -where \fIvarname\fP is the name of the variable, and \fIdiscname\fP -is the name of the discipline. -When the user defines such a function, the \f5settrap()\fP -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, \f5ksh\fP defines \f5get\fP, -\f5set\fP, and \f5unset\fP 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 -.nf -.in .5i -\f5struct \fIyours\fP -{ - Namfun_t fun; - \fIyour_data_fields\fP; -};\fP -.in -.fi -.H 2 "The shell library" -There are several functions that are used by \f5ksh\fP itself -that can also be called from built-in commands. -The man page for these routines are in the Appendix. -.P -The \f5sh_addbuiltin()\fP 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 \f5void*\fP pointer that will be passed to this function -as the third agument whenever it is invoked. -If the function address is \f5NULL\fP, the specified built-in -will be deleted. However, special built-in functions cannot -be deleted or modified. -.P -The \f5sh_fmtq()\fP 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 \f5%q\fP option -of the shell built-in \f5printf\fP command. -.P -The \f5sh_parse()\fP 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 \f5sh_trap()\fP function and giving a value of \f51\fP as the -second argument. -Alternatively, the \f5sh_trap()\fP function can parse and execute -a string by passing the string as the first argument and giving \f50\fP -as the second argument. -.P -The \f5sh_isoption()\fP function can be used to set to see whether one -or more of the option settings is enabled. |