The device name of the install medium that will be read from will
vary from machine to machine, so it may not be /dev/rdiskette
on your machine. The cpio should take less than one minute and
will report the names of the files it is copying along with a
block count indicating how many blocks (usually around 420) it
copied from the diskette to the hard disk. Any other message(s)
will most likely indicate an error. In such a situation, please
contact your System Administrator for assistance.
A list of the files CCsh uses are listed in the `man' page for
CCsh. This can be found in Appendix A. In some rare circumstances, your needs may require that you remove CCsh from your
system. This can be accomplished by logging in as root and running /usr/bin/rmccsh at the '#' prompt. rmccsh will end by emitting the message Remove of CCsh complete. If not, contact your
Systems Administrator.
Finally, in some cases, a port of CCsh may need to be done via
modem using your actual machine. In these situations, installation will be accomplished by Comeau Computing. From time to
time, a new or existing customer will require a port of CCsh to
another machine. There will probably be a good chance that such
a port already exists. In the case where it doesn't, Comeau Computing will determine if the port is possible. If the port
presents no problems, we will discuss our porting method with the
customer. This will usually require that the customer have a
modem and a C compiler.
Also recently, we are now distributing CCsh electronically in most cases, normally through ftp. Follow the instructions provided with the email you received.
III. Requirement for the use of CCsh
The only prerequisite for using CCsh is that the machine support
the software development system (the cc command in particular).
Executable programs generated from CCsh will typically be around
50K, so there are no memory requirements. Disk space for CCsh
(the compiler, library, and header file) is 200K bytes.
In addition, there are no requirements such as setting up special
"environment variables", files, or directories since CCsh does
not need any "external" information to run.
IV. The ARGVSIZE, ENVPSIZE and WAITSIZE variables
Normally, upon start-up, the shell must set up its environment
list and consolidate the argument list that's been passed to it.
CCsh is no different in this respect. More explicitly, when a
shell script is compiled by CCsh, the C code expects that the
environment variable list will have a finite length. Also, a
CCshd program will build an argument list of finite length for
the commands it invokes. In addition, the invocation of background commands also requires that information on background
processes be stored. The sizes of the variables CCsh uses for
these lists (Argv, Lenviron, and Backgrounds) are controlled by
the pre-processor definitions ARGVSIZE, ENVPSIZE, and WAITSIZE.
CCshd programs will terminate with an error message informing
you that you must increase the size of one of these defines if
any list has overflowed. This can be accomplished easily by
editing the generated C code output from CCsh and changing the
appropriate lines where ARGVSIZE, ENVPSIZE, and WAITSIZE are
defined.
For instance, the shell script
for i in $*
do
echo i=$i
done
would generate the C code shown in Appendix B. If you were to
find that this simple shell script were being passed many arguments, you would increase the size of ARGVSIZE shown in line 10
of Appendix B to something more appropriate.
Unfortunately, this requires you to be aware of what's going on
and that you remember to edit the generated C file. It's also
hard to generate systems automatically with commands like make
if you're required to do some hand-editing. CCsh makes this task
a bit easier by allowing you to specify the size of ARGVSIZE,
ENVPSIZE, and WAITSIZE as command line parameters when it is
invoked. See the man page presented in the appendix for details
on using these options.
V. Shell scripts that don't use argv and envp
There are a few subroutine calls at the beginning of the main
procedure of C code that is generated by CCsh. The first one,
setupargs, sets up the CCshd program's argument list. The
second subroutine, setupenv, sets up the CCshd program's
environment list. Since there are many shell scripts that do not
use or care about either of these "external" variables (the argument list or the environment), the programmer can remove either
or both of these calls if they are not needed, thus reducing
startup overhead for the C code when it executes, as well as
obtaining a smaller object code size. Removing these lines can
be as simple as editing the .c file or using the -E and -A
options explained in the `man' page found in Appendix A.
NOTE: Do not remove the calls to setupargs or setupenv if the
program uses argv or envp.
NOTE: Do not remove the call to setupenv if any of the
program's children will use envp.
VI. The Dot Command
The Dot command (`.') is now supported in CCsh V1.4+. While its
syntax and functionality is the same as the shells, its implementation it different. The difference in the implementation is
brought about because of the differences between an interpreted
environment and a compiled environment. When the shell is running a shell script, it doesn't care or know that the next line
might be a `dot' command. In other words, the dot'ing normally
doesn't happen until a dot command is encountered and executed.
With CCsh the dot'ing must occur during compilation of the shell
script, not during execution time. This requires that
- the file being dot'ed needs to exist during compilation,
- the file being dot'ed cannot be expected to change after the compilation,
and
- dot commands using variable substitution for the file
name cannot wait until runtime for the file name to be determined.
In the latter case, CCsh will pick up the last assignment
of the variable that occurred in the shell script, regardless of
conditional statements enclosing the assignment. Alternately, if
this presents a problem, or if the variable is not explicitly set
in the shell script, it may be specified and assigned on the command line during compilation. Please see Appendix A, the man
page, for further instructions.
VII. The Eval Command
The eval command is now supported in CCsh V1.4+. Like the Dot
command its syntax and functionality is the same as the shell,
but its implementation is different. Again, the difference in
the implementation is brought about because of the differences
between an interpreted environment and a compiled environment.
The problem with eval is that it supports self-modifying code.
This is no big problem except in one situation. For example, in
the following command lines:
PIPEIT='| od -bc'
...
eval cat file $PIPEIT
the use of the pipe operation is not known until execution time
since there may be conditional statements between the assignment
of PIPEIT and the eval command. If CCsh is to determine this at
execution time, then it needs to have a completely functional
shell interpreter inside every executable file it produces. This
certainly defeats the point of CCsh altogether. The use of eval
in all other situations is allowed and supported.
VIII. Additions
Versions of CCsh previous to V1.4 did not support the use of
shell functions, (command-list), {command-list}, the IFS variable, digit redirection (i.e. 2>&1), and ${parameter??word} initializations whatsoever. All these constructs are now fully supported making CCsh completely compatible with the System V
Release 2 shell.
IX. Built-in Commands
Various UNIX commands have been built into CCsh. This avoids the
overhead of an exec() and/or fork() altogether. In addition,
many of CCshs built-in commands are faster than their UNIX
equivalents. The commands currently built-in include basename,
cat, cp, dirname, dsort, echo, expr, false, getopt, head, od,
page, pr, pwd, split, tail, tee, test, touch, true, and wc.
Future releases of CCsh will have even more built-in commands.
Also, with the introduction of CCsh V1.4 users now have the ability to use site-specific built-in commands of their own choosing.
This ability to have custom built-in commands will also make
non-UNIX ports of CCsh as well as ports of CCsh generated C code
easier. Appendix C provides sample code and explanations for
creating user built-ins.
X. Error Messages
Compile Time Errors
Usage: ccsh [ ccsh options ] shell_file
When you have specified an incorrect argument to CCsh this
message will print informing you of the correct usage.
Please refer to the man page for more information.
ccsh: -OPT option in argument 'ARG' invalid
The option character OPT within the argument ARG is not a
valid option character to specify on the command line.
ccsh: no input file specified.
CCsh could not find the name of the shell_file to compile
while parsing the command line.
ccsh: warning: filename 'FILE' > than X characters.
An executable file created by CCsh will have the characters
".exe" appended to it. If the name of the input shell file
is larger than X characters (typically 10), the file name
will be truncated.
ccsh: Shell script 'FILE' does not exist.
The input shell file could not be found.
ccsh: Shell script 'FILE' is not readable.
CCsh could not read the input shell file.
ccsh: Cannot stat 'FILE'.
Contact Comeau Computing if you receive this error.
ccsh: 'FILE' is not a regular file.
You are trying to compile a shell file that is a directory or
device, and not a regular file.
ccsh: Cannot open shell script 'FILE'.
The input shell file cannot be opened for reading. Check the
path name for accessibility and/or existence.
ccsh: Cannot open C output file 'FILE' for writing.
The output shell file cannot be opened for writing. Check
the path name for accessibility and/or existence.
CCsh ends with NUMBER errors and NUMBER warnings.
CCsh always prints this message when it ends.
syntax error: `KEYWORD' was expected on line LINE
Your shell script has a syntax error that was created by a
missing keyword, such as a missing then in an if statement.
warning: `KEYWORD' found on line LINE is not supported
Your shell script is trying to use a feature of the shell
that is not yet supported by CCsh. This should no longer
occur in versions after 1.3l. Please contact Comeau Computing if it does.
warning: `break' is not enclosed in a `for' or `while' on line LINE
A `break' statement must be within a for or while statement
for it to have any effect. It is a syntax error otherwise.
warning: `continue' is not enclosed in a `for' or `while' on line LINE
A `continue' statement must be within a for or while statement for it to have any effect. It is a syntax error otherwise.
warning: `[' command on line LINE does not have a matching `]'
A bracketed `test' command requires a closing `]' character.
warning: `trap' command on line LINE should be single quoted
The `trap' command in a compiled environment must operate
slightly different than when used in an interpretive environment. This is because `sh' scans a command and then executes
it. With a `trap', a second scan is performed if the `sh'
process receives a signal that is to be trapped. In this
scenario, the shell will attempt to rescan the line for variable substitutions, etc. Now, since CCsh is not an interpreter, there is no way to do the first scan that the shell
normally does. That is, CCsh will not scan the commands in
the trap string until the appropriate signal has been
received. This in effect results in the trap string being
single quoted, since the shell would not do any substitutions
on a single quoted trap string until the trap has been
"sprung". Therefore, any double quoted trap string(s) will
result in a warning message from CCsh and it's up to the programmer to ensure that the trap string is acceptable.
syntax error: unexpected `KEYWORD' found on line LINE
A misplaced keyword was encountered.
Compiler error in 'screener'
This should never occur. If it does, contract Comeau Computing.
Program will not continue.
A error has occurred and CCsh is aborting itself.
XX: malloc space used up
This message should never occur. If it does, contract Comeau
Computing.
Line LINE too long.
The length of a shell input line may not typically be greater
than 512 characters.
warning: Var table filled up.
CCsh records all variable assignments it passes so that the
dot command can perform reliably in a compiled environment.
If this message comes up, please contact Comeau Computing.
ccsh: Compile interrupted
CCsh received a signal (typically from the keyboard) causing
it to abort.
ccsh: info: Buffer size of BUFFERSIZE being used
You have specified a -b option of BUFFERSIZE bytes on the
command line. This is strictly informative.
ccsh: Buffer size must be >= 512 bytes.
You have specified a -b option on the command line, but the
buffer needs to be at least 512 bytes long.
warning: `;;' was expected on line LINE
The shell does not require a closing `;;' before an `esac'.
CCsh does not either, but it would prefer that you would.
Warning: Command line define of 'VARIABLE' set to NULL
You have chosen to define a shell variable on the command
line (perhaps for use with the `.' command?), yet the variable was given no specific value.
Warning: Builtin table filled up.
CCsh only allows up to 50 user builtins at a time. Contact
Comeau Computing if this presents a problem.
warning: C compiler will generate a "warning: statement not
reached" message
Because CCsh runs in a variety of environments, it generates
very portable C code. One anomaly of this code generation
occurs during if/then/else processing in which CCsh generates
a break statement followed by a goto statement. This causes
most C compilers to give a non-fatal warning message.
warning: unreachable code on line LINE
CCsh encountered code after a non-nested `exit' statement.
Error: line LINE: Trying to create more than NUM functions: use
-F flag.
CCsh usually only allows 50 functions to be defined in a
shell script at any one time. Use of the -F option can be
used to bypass this default.
warning: substitution of 'VARIABLE' on line LINE yields null.
or
Error: $VARIABLE on line LINE doesn't expand to anything.
CCsh was processing a `.' command involving variable substitution and discovered that the variable being interrogated
had no value or was never defined.
Warning: Usage of 'VARIABLE' on line LINE is unpredictable.
During parsing, CCsh records variable assignments so that the
`.' command can function correctly. This message is emitted
when CCsh discovers that a variable has been assigned to more
than once. In such situations CCsh discards previous assignments to the variable and will only "remember" the last
assignment value.
error: bad file number 'FILE_NUMBER' on line LINE
or
error: bad number 'FILE_NUMBER' on line LINE
A file number used in digit redirection (say 2>&1) can only
consist of the digits 1 through 9, or '-'. Any other value
is incorrect.
warning: EOD in here document on line LINE may be premature
Under certain circumstances, the shell allows the end-of-data
marker in a `here document' (`<<' redirection) to occur after
a tab character rather than as the first character on a line.
CCsh will also accept this syntax but issues a warning in
case that is not what you wanted to do.
warning: case on line LINE has no statements
Better safe than sorry type of message...
warning: `.' (dot) command on line LINE not fully supported.
See Section VI for a discussion of this.
Warning: nothing's being `.'ed on line LINE
CCsh encountered a `.' command yet there was no file name
specified to dot.
Dotting ORIGFILE==>DOTFILE
CCsh prints this out to inform you that it is now processing
a dotfile. The syntax specified in the shell script for the
file is ORIGFILE. The actual file being used is DOTFILE.
Note that ORIGFILE and DOTFILE need not be the same (because
of variable substitutions).
Error: line LINE: 'DOTFILE' not found.
The DOTFILE specified on line LINE is invalid.
End of dotfile 'DOTFILE'
CCsh prints this out to inform you that it has finished processing the dotfile named in the message.
warning: Your use of `eval' on line LINE may not be supported.
Check the manual.
Please see Section VII of this manual for further discussion.
Warning: nothing's being `eval'ed on line LINE
CCsh encountered a "null" `eval' statement.
`return' on line LINE does not occur in a function
A `return' statement must occur within a shell function.
warning: `return' on line LINE1 and LINE2
CCsh would like you to double check your `return' statements.
error: Single quoted string beginning on line LINE1 till line
LINE2 is too long.
or
error: Double quoted string beginning on line LINE1 till line
LINE2 is too long.
The output buffer for strings is usually 512 bytes long.
This can be changed with the -b option to CCsh.
XI. Error Messages
Runtime Errors
com.exe: DIRECTORY: bad directory
Your executable shell script has attempted to `cd' to a non-existent or unsearchable directory.
Cannot pipe
Your executable shell script is implementing a pipeline but
has opened too many file descriptors, hence cannot set up the
pipe.
IDENTIFIER: is not an identifier
You have attempted to `export', `readonly', or `read' a shell
variable but the variable does not have the correct form of
an identifier.
Invalid type: NN
This should never occur. Contact Comeau Computing if you
receive this message.
Cannot times
An error occurred while processing a `times' command.
pwd: Can't open 'DIRECTORY'
The `pwd' command attempted to print the current directory
but failed.
Cannot fork 'COMMAND'
Your executable shell script could not run a command. Make
sure the command exists and is executable. Otherwise, check
with your Systems Administrator for system problems.
Discarding output from `command`
Your executable shell script only has a 2K buffer for `command` constructs. Any data over this limit is thrown away.
com.exe: Cannot get ulimit??
Your executable shell script could not obtain the current
ulimit setting.
com.exe: Bad ulimit
Your executable shell script could not change the current
ulimit setting.
Cannot get umask??
Your executable shell script could not obtain the current
umask setting.
Bad umask
Your executable shell script could not change the current
umask setting.
ccsh.com: setupenv: no more room for variables
Your executable shell script could not create a list of the
current variables. The environment variable list can be
increased as explained in the manual and in the man page if
you get this message.
com.exe: VARIABLE: is read only
Your executable shell script has attempted to assign to or
`unset' a shell variable that has the `readonly' attribute.
com.exe: cannot shift
Your executable shell script has attempted to do a `shift'
command but there were not enough positional parameters left
to fulfill the request.
com.exe: 'FILE': cannot open
Your executable shell script has attempted to perform
redirection, but the file to be used for the redirection
could not be opened.
com.exe: Error duping for 'FILE'
Your executable shell script has too many file descriptors
open while attempting to redirect the standard output.
com.exe: 'FILE': cannot create
Your executable shell script could not create an output file
while attempting to redirect the standard output. You may
have too many file descriptors open. Also, check permissions
on the directory that FILE would have been created in.
com.exe: 'FILE': cannot dup
Your executable shell script has too many file descriptors
open while attempting to redirect the standard input.
com.exe: test: unknown operator 'OPERATOR'
The operator in a `test' expression is not a valid one.
com.exe: test: argument expected
Your executable shell script is running the `test' command
and has encountered an invalid or incomplete expression for
evaluation.
com.exe: bad trap number 'NUMBER' on line LINE
The signal number you have specified on the `trap' command is
not numeric.
com.exe: bad trap on line LINE: cannot trap 11
The shell prohibits receiving signal #11 (a memory fault), so
do we.
com.exe: TRAP_NUMBER: bad trap on line LINE
The signal number you have specified on the `trap' command is
not a valid signal number.
com.exe: unset: bad argument count
Your executable shell script has executed the `unset' command
but no shell variable(s) was specified for unsetting.
com.exe: malloc space used up
This message should rarely occur. If it does, contract
Comeau Computing.
XII. Problems
Because CCsh must perform complicated logic as a compiler and
since the shell is an interpreter with an "incomplete" grammar
specification, situations will arise that will not compile and in
rare circumstances the a.out file will not function properly.
Therefore, it is suggested that you compile shell scripts AFTER
they have been tested under the actual shell. If you still have
a problem please notify Comeau Computing and save a copy of the
shell script, C code, and object code before contacting us.
Do not send any files, instead just send the line of code that's problematic.
XIII. Future Directions
CCsh is under continuous development and will be going through
various phases of development. Some of this development depends
upon your input.
If you have any questions or suggestions we can be reached
here
Appendix A: CCsh MAN Page
CCsh(1) CCsh(1)
Name
CCsh - Bourne Shell Compiler
Synopsis
ccsh [-cvVuAE] [-asize] [-esize] [-wsize] [-bbufsize] [-Bbuiltin]
[-Ddefine] shell_file
Description
CCsh is a Bourne Shell Compiler which translates a shell
file (better known as a shell script) into C language source
or into the object code of your native machine to produce an
executable equivalent of your shell script.
Normally, execution of ccsh will create both a .c and a
.exe file. If the -c option is specified, only C code
(.c) is generated. By default, the C file and/or object
code are placed into the same directory as the shell script.
The -v option causes the shell source to be inserted into
the generated C code as comments. If the -V option is used
instead, the line numbers of the shell script are also
printed along with comments.
C code generated by CCsh is normally sent to the .c file
using buffered I/O. If this is not desired, the -u option
will cause CCsh to write to the file without buffering.
Since this degrades performance, this option should only be
used for debugging purposes.
The -A and -E options allow you to control whether or not
CCshd shell scripts will use their environment or argument
list. If you use the -A and -E options, CCsh will not
include the routines to handle the arguments and environment, respectively.
The -a, -e, and -w options allow you to override the default
values for the ARGVSIZE, ENVPSIZE, and WAITSIZE
variables within the .c file. These variables normally
have values of 256, 256, and 9 respectively. The purpose of
these variables is to control the sizes and storage area
used by the argument list and environment variables.
Because of the limitations of some C compilers, CCsh will
use an output line of 512 characters by default. If this
default becomes too small (say you're printing out a
screen-long string using echo), you can increase the limit
by using the -b option. A buffer size must be used with
this option.
When using user defined built-ins with CCsh you must use the
-B option. The name of the built-in being used is specified
along with the -B option. Please refer to Appendix C for
more information. This option may be specified repeatedly.
The -D option is useful for defining shell variables so that
the dot command (`.') can resolve names of files, at compile
time, needing substitution. The name of the variable is
placed along with this option. This option may be specified
repeatedly.
Files
/usr/bin/ccsh Shell script which runs CCsh
/usr/bin/ccshcomp The compiler
/usr/lib/libccshrun*.a Runtime library(ies)
/usr/include/ccsh.h Header file used in CCsh'd programs
See Also
sh(1)
UNIX Shell Programming by Kochan and Wood
Example
To compile a shell script located in a file named example,
type:
ccsh example
This will create two files: example.c and example.exe.
Appendix B: Sample C file output
1 /*
2 *
3 * Generated by CCsh V2.1 (tm), "The Bourne Shell Compiler"
4 * CCsh is manufactured by Comeau Computing: comeaucomputing@gmail.com
5 *
6 * Derived from '/tmp/argdump'
7 * Created: Tue Jan 26 14:31:00 1997
8 */
9
10 #define ARGVSIZE (256)
11 #define ENVPSIZE (256)
12 #define WAITSIZE (9)
13
14 #include <ccsh.h>
15
16 main(argc, argv, envp)
17 int argc;
18 char *argv[];
19 char *envp[];
20 {
21 CCshinit(ARGVSIZE);
22 setupargs(argc, argv); /* delete if arguments are not used */
23 setupenv(ENVPSIZE); /* delete if environment is not used */
24 setupsigs();
25
26 while (1) {
27 Bufp = inarg(&Nest1,
28 TEXT, NCAT, "$",
29 TEXT, CAT, "*",
30 ENDOFLIST, FORK, (char *)0
31 );
32 if (Bufp == (char *)0)
33 break;
34 setvar("i", Bufp);
35
36 rc = echo(
37 TEXT, NCAT, "i",
38 TEXT, CAT, "=",
39 TEXT, CAT, "$i",
40 ENDOFLIST, FORK, (char *)0
41 );
42 }
43 Nest1 = (char **)0;
44
45 CCendup();
46 exit(rc);
47 }
48 char *(*Subcom[])() = {
49 (char *(*)())0,
50 };
Appendix C: Adding Builtin Commands
Adding your own built-in commands to CCsh can be very simple
depending upon your needs. For instance, lets take a typical C
program like example.c:
$ cat example.c
main()
{
printf("Hello, world\n");
exit (0);
}
$
One would typically run this through the C compiler and place it
into a shell script, say ex, by entering the text example,
saving it, and running it. The ex script may then also be
passed through CCsh. A sample session follows:
$ cc -o example example.c
$ cat ex
example
$ chmod 755 ex
$ ex
Hello, world
$ ccsh ex # first case: example is fork()'ed
CCsh(tm) Version 2.1, "The Bourne Shell Compiler"
(c) Copyright 1987, 1997 Comeau Computing. All rights reserved.
CCsh ends with 0 errors and 0 warnings.
Compiling C code ...
Creation of ex.exe finished.
$ ex.exe
Hello, world
$ cat ex.c
/*
*
* Generated by CCsh V2.1 (tm), "The Bourne Shell Compiler"
* CCsh is manufactured by Comeau Computing: comeaucomputing@gmail.com
*
* Derived from '/tmp/ex'
* Created: Tue Jan 26 17:57:47 1997
*/
#define ARGVSIZE (256)
#define ENVPSIZE (256)
#define WAITSIZE (9)
#include <ccsh.h>
main(argc, argv, envp)
int argc;
char *argv[];
char *envp[];
{
CCshinit(ARGVSIZE);
setupargs(argc, argv); /* delete if arguments are not used */
setupenv(ENVPSIZE); /* delete if environment is not used */
setupsigs();
rc = simpcommand(
TEXT, NCAT, "example",
ENDOFLIST, FORK, (char *)0
);
CCendup();
exit(rc);
}
char *(*Subcom[])() = {
(char *(*)())0,
};
If instead, we change main to a function definition that
CCsh would understand in addition to changing the exit call
into a return statement, then the CCshd code can now call
example as a subroutine as seen below.
$ cat example2.c
int
example()
{
printf("Hello, world\n");
return (0);
}
$ cc -c example2.c
$ ar cq mylib.a example2.o
$ CCLIB=mylib.a # CCLIB is used by ccsh to find your builtin library
$ export CCLIB
$ # second case: example is now builtin via the -B option.
$ # It runs as a subroutine!
$ ccsh -Bexample ex # second case: example is now builtin
CCsh(tm) Version 2.1, "The Bourne Shell Compiler"
(c) Copyright 1987, 1997 Comeau Computing. All rights reserved.
CCsh ends with 0 errors and 0 warnings.
Compiling C code ...
Creation of ex.exe finished.
$ cat ex.c
/*
*
* Generated by CCsh V2.1 (tm), "The Bourne Shell Compiler"
* CCsh is manufactured by Comeau Computing: comeacomputing@gmail.com
*
* Derived from '/tmp/ex'
* Created: Tue Jan 26 18:03:19 1997
*/
#define ARGVSIZE (256)
#define ENVPSIZE (256)
#define WAITSIZE (9)
#include <ccsh.h>
main(argc, argv, envp)
int argc;
char *argv[];
char *envp[];
{
CCshinit(ARGVSIZE);
setupargs(argc, argv); /* delete if arguments are not used */
setupenv(ENVPSIZE); /* delete if environment is not used */
setupsigs();
rc = example( /* NOTE: no more fork()ing of `example' */
ENDOFLIST, FORK, (char *)0
);
CCendup();
exit(rc);
}
char *(*Subcom[])() = {
(char *(*)())0,
};
$
Note that in the first case, there is not a large speed benefit
in running the script through CCsh since example still needs to
be fork()'ed and then exec()'ed. The second case is different
though since the -B options has informed CCsh to make example a
built-in command. Now, the executable file ex.exe literally has
a copy of example linked into it as a subroutine producing the
effect we wanted. In general, this technique works fine so long
as the shell script being enhanced in this way does not use any
redirection, pipes, command substitution, or command arguments.
If this is the case, and one should assume that it always is
since programs change through their lifetime, then you need to
put some header and trailer code into any commands that are to
become built-in. Therefore, a proper setup for our example
subroutine should be:
$ cat example3.c
#include <ccsh.h>
int
example(ccshc, ccsht, ccshs)
int ccshc;
int ccsht;
char *ccshs;
{
register char **argv = Argv;
FILE *stream = stdout;
makeargv(&ccshc);
dobuiltio(&stream);
argv = Argv;
/* Your code goes from here to........... */
fprintf(stream, "Hello, world\n");
/* ................................. here */
outahere:
fflush(stream);
endbuiltio(&stream);
fixstandio();
return (0); /* The return value from your program. */
/* Note you *must* pass through outahere to "exit" */
/* BUT, don't call exit() unless you really want to */
}
$ cc -c example3.c
$ rm mylib.a
$ ar cq mylib.a example3.o
$ cat ex
example
var=`example`
echo var=$var
$ ccsh -Bexample ex # third case: previous example using I/O
CCsh(tm) Version 2.1, "The Bourne Shell Compiler"
(c) Copyright 1987, 1997 Comeau Computing. All rights reserved.
CCsh ends with 0 errors and 0 warnings.
Compiling C code ...
Creation of ex.exe finished.
$ ex.exe
Hello, world
var=Hello, world
$
Note that this must be setup this way because the subroutine
(example in our case) is now part of the generated code instead
of an independent command. In such cases, it needs to handle I/O
and arguments all by itself since the .exe file is to run as a
single process. Also, note the use of the variable stream.
All output that had previously been going through stdout must now
go through stream. If this presents a problem to a large program you will need run it through an editor or sed to replace
all standard I/O routines to use their "file" versions, i.e
changing printf( to fprintf(stream, or putchar(char) to putc(char, stream).
Comeau Computing.
Copyright © Comeau Computing. All rights reserved.
Revised: July, 2013.