chain - chain to a BASIC program


#include <basic/string.h>

extern Bcomon;
extern Bcomal[];

struct string *prog;



These functions implement the chaining facility.  They are forbidden when basic(1) is invoked with the -K switch. 

Besides starting the new program, the major task performed by the chaining facility is the transmission of data required by the new program.  Data declared as ďcommonĒ with the COMMON statement must be available to the new program.  In addition, the information concerning open files must be available because files must remain open across a chain.  A pipe (see pipe(2)) is used for transmitting this data. 

The chaining program creates a pipe and an environment variable BASCHAIN.  The first ten characters of this variableís value are an ASCII representation of the programís process id (see getpid(2)), left-padded with zeroes.  The eleventh and final character is a capital letter representing the read file descriptor number of the pipe: capital A represents file descriptor zero, B represents one, etc.  The chaining program then creates a new process for the new program (see fork(2)).  When the new program begins execution, it must determine if it was executed by a chaining program.  If the environment variable BASCHAIN is found and contains its process id, the new program reads the data from the pipe using the file descriptor encoded in the environment variable. 

The transmission over the pipe proceeds as follows: first, a magic number is transmitted to allow the new program protection against erroneously receiving data from a process other than a chaining program.  All common data and information concerning open files are transmitted.  The arrays Bcomon and Bcomal contain the necessary information for the transmission.  The new program stores only as much common data as it has space allocated for this purpose.  Any additional data is discarded.  It is assumed that the ordering of the types of the variables declared as common in the COMMON statements of both programs is the same.  The new program may have a shorter list of common variables.  It may have a longer list provided it does not expect these extra variables to be non-zero.  Finally, the process id of the old program and a checksum of the entire transmission (save the checksum itself) is sent and verified against the new programís checksum. 

Chain, as a precaution, uses access(2) to check that prog refers to a file that is executable.  If this test is successful, this function then creates the pipe, creates the environment variable, sets all signals to be ignored using ignsigs (see initio(io)) and forks.  The parent process closes the write file descriptor of the pipe and executes the file given by the string pointed to by prog (see exec(2)).  The child process closes the read file descriptor of the pipe, sends the data on the write file descriptor and then closes it.  The process then terminates with status zero, avoiding cleanup (see exit(2)). 

Chainy tests the environment variable.  If it does not contain the process id, this function merely initializes I/O using initio(io).  Otherwise it reads and checks the magic number from the file descriptor encoded in the environment variable.  It then receives the data, closes the pipe and verifies the checksum.  The new program then waits for the old program to terminate using dezomb and then all signals are set to be trapped normally using trapsigs (see initio(io)).  Finally, the environment variable is reset to prevent any future process from assuming it is the subject of a chain.  To be effective, this function must be called when the process begins. 

These variables and functions implement the CHAIN statement and its behavior due to the COMMON statement. 


chain(stmt), common(stmt)
basic(1) in the Supplemental Documentation section
access(2), exec(2), exit(2), fork(2), getpid(2), pipe(2) in the UNIX Programmerís Manual


Chain generates error 51 (Internal error) if pipe, fork or exec fail.  If this error is trapped, steps are taken to recover gracefully leaving the process essentially intact. 

In case of trouble thereafter (sending the data or closing the pipe), chain exits with status one, avoiding cleanup (see exit(2)).  Presumably this will cause a read error in the new program which is responsible for reporting any errors. 

Chainy writes to the standard error output the message, ďGarbled data transfer during CHAIN,Ē and exits with status one in case of trouble receiving the data or closing the pipe.  Since the information concerning open files is lost, these files will be left in disarray.  In particular, the userís terminal will probably be left in a disturbed state. 


Signals are ignored during chaining.  This is necessary to avoid leaving the userís terminal in a disturbed state while insuring that no data is lost from the terminal during the chain.  Unfortunately, the user may be disconcerted by the inability to interrupt the process during this period.  Also, the terminal state will not be restored should the transmission of data fail. 

The description above may make life with the chaining facility somewhat more tolerable if one must invoke a BASIC program in an unusual way.  However, the author recommends that the use of the facility in a manner not prescribed be avoided; all else is proscribed. 

from The Basmark QuickBASIC Programmerís Manual by Lawrence Leinweber