home *** CD-ROM | disk | FTP | other *** search
- /**
- *
- * Name pcexec -- Load and execute a program
- *
- * Synopsis ercode = pcexec(pfile,pcmd,fcb_flag);
- *
- * int ercode 0 if successful;
- * 300 if calloc() failed;
- * if another positive value, this is
- * the error from MMSETBLK which
- * prevented releasing memory for the
- * child;
- * if negative, this is the OPPOSITE of
- * the DOS error encountered while
- * loading the child program.
- * char *pfile Name of file to load and execute
- * char *pcmd Commmand line to pass to the program
- * int fcb_flag If nonzero, offset 5C and 6C of the
- * child process program segment prefix
- * are filled with file control blocks
- * formatted as the first two command
- * line parameters. If it is zero, the
- * file control blocks are inherited
- * from the parent process.
- *
- * Description This function loads and executes the program whose file
- * name is specified by *pfile. The program is loaded and
- * executed as if invoked from DOS with the command line
- * specified in *pcmd. The child program returns control
- * when either execution ends or Ctrl/Break is pressed.
- *
- * Many of the DOS external commands (e.g., FORMAT,
- * DISKCOPY, etc.) expect the command line parameters to be
- * formatted in the file control blocks at offsets 0x5C and
- * 0x6C in their program segment prefix. (In fact, when
- * COMMAND.COM loads a program it always does just that.)
- * If fcb_flag is nonzero, the first two parameters of the
- * command line are placed in the formatted FCBs; if
- * fcb_flag is zero, the parent FCBs are inherited by the
- * child.
- *
- * The command line is truncated to 126 bytes if necessary.
- * It should be terminated by a NUL byte ('\0') as usual.
- * It should not contain any carriage returns ('\15') or
- * line feeds ('\12').
- *
- * The original idea for this revision of PCEXEC is due to
- * Lloyd Zusman of Master Byte Software (August 1984).
- *
- * Returns ercode 0 if successful;
- * 300 if calloc() failed;
- * if another positive value, this is
- * the error from MMSETBLK which
- * prevented releasing memory for the
- * child;
- * if negative, this is the OPPOSITE of
- * the DOS error encountered while
- * loading the child program.
- *
- * Version 3.0 (C)Copyright Blaise Computing Inc. 1983, 1984, 1986
- *
- * Version 3.01 August 20, 1986 PLD
- * Corrected declaration of "environ" for Lattice compiler.
- *
- * Version 3.02 March 24, 1987
- * Prevented copying of null environment strings ("") into
- * child's copy of environment table (because DOS
- * function 0x4b considers a null string to be the
- * end of the table.
- *
- **/
-
- #include <stdlib.h>
- #include <string.h>
-
- #include <bmemory.h>
- #include <bprogctl.h>
- #include <butility.h>
-
- #if MSC300
- #include <malloc.h>
- #endif
-
- static char *envpak(char **); /* Internal (see below). */
-
- #define OUT_OF_MEMORY 300
-
- int pcexec(pfile,pcmd,fcb_flag)
- char *pfile,*pcmd;
- int fcb_flag;
- {
-
- struct fc_block /* DOS File Control Block (FCB) */
- { /* structure. It is needed if */
- char drive; /* fcb_flag is nonzero. */
- char f_name[8];
- char f_ext[3];
- int cur_block;
- int rec_size;
- long file_size;
- int cr_date;
- char reserved[10];
- char rec_num;
- long rel_rec;
- } *pfcb1, *pfcb2;
-
- struct parm_block /* Parameter block used by EXEC */
- { /* function (DOS 0x4b call) */
- unsigned envseg; /* Segment of environment */
- ADS cmd_ads; /* ADS of command line */
- ADS fb1_ads; /* ADS of first and second file */
- ADS fb2_ads; /* control blocks (FCBs) */
- } block_val;
-
- DOSREG dos_reg;
- ADS env_ads,loc_ads;
- int ercode,cmd_len;
- unsigned size;
- char *pcmd_line;
- char *penv_table,*penv_space;
-
- if ((ercode = mmshrink(&size)) != 0)
- return(ercode); /* Error releasing memory. */
-
- /* Pack the current environment table and store it on a segment */
- /* boundary. Compute its physical segment and store it as */
- /* block_val.envseg. */
-
- if (NIL == (penv_table = envpak(&penv_space)))
- return OUT_OF_MEMORY;
-
- utabsptr(penv_table,&env_ads);
- block_val.envseg = env_ads.s + (env_ads.r >> 4);
-
- /* The command line must have a leading length byte followed by */
- /* actual characters making up the string. Then move the address */
- /* of the command line to the parameter block. */
-
- cmd_len = (int) strlen(pcmd);
- utuplim(cmd_len,126);
- pcmd_line = calloc((unsigned int) (cmd_len + 3),1);
-
- if (pcmd_line == NIL)
- {
- free(penv_space);
- return OUT_OF_MEMORY;
- }
-
- *pcmd_line = (char) cmd_len;
- strncpy(pcmd_line+1,pcmd,(unsigned int) cmd_len);
- *(pcmd_line + cmd_len + 1) = '\15'; /* Trailing carriage return */
- utabsptr(pcmd_line,&block_val.cmd_ads);
-
- /* If fcb_flag is nonzero, build the FCBs out of the command */
- /* line. The DOS function call 0x29 is used to scan the command */
- /* line and create the FCBs. */
-
- if (fcb_flag)
- {
- pfcb1 = utalloc(struct fc_block);
- pfcb2 = utalloc(struct fc_block);
-
- if (pfcb1 == NIL || pfcb2 == NIL)
- {
- free(pcmd_line);
- free(penv_space);
- return OUT_OF_MEMORY;
- }
-
- utabsptr(pcmd,&loc_ads);
- dos_reg.ds = loc_ads.s; /* Location of the command line */
- dos_reg.si = loc_ads.r; /* to be parsed. */
-
- /* Address of formatted FCB area*/
- utabsptr((char *) pfcb1,&block_val.fb1_ads);
- dos_reg.es = block_val.fb1_ads.s;
- dos_reg.di = block_val.fb1_ads.r;
- dos_reg.ax = 0x2901;
- dos(&dos_reg); /* DS,SI now point to next item */
- /* in the command line. */
- utabsptr((char *) pfcb2,&block_val.fb2_ads);
- dos_reg.es = block_val.fb2_ads.s;
- dos_reg.di = block_val.fb2_ads.r;
- dos_reg.ax = 0x2901;
- dos(&dos_reg);
- }
- else /* Use parent's FCBs */
- {
- block_val.fb1_ads.r = 0x5c;
- block_val.fb2_ads.r = 0x6c;
- block_val.fb1_ads.s =
- block_val.fb2_ads.s = utpspseg;
- }
-
- dos_reg.ax = 0x4b00;
- utabsptr((char *) &block_val,&loc_ads);
- dos_reg.es = loc_ads.s;
- dos_reg.bx = loc_ads.r;
- utabsptr(pfile,&loc_ads);
- dos_reg.ds = loc_ads.s;
- dos_reg.dx = loc_ads.r;
-
- ercode = -dos(&dos_reg); /* Return negative error code */
- if (fcb_flag)
- {
- free((char *) pfcb1); /* If FCBs were constructed, we */
- free((char *) pfcb2); /* free the allocated memory. */
- }
- free(pcmd_line);
- free(penv_space);
-
- return(ercode);
- }
-
- /**
- *
- * Name envpak -- Pack environment table for PCEXEC
- *
- * Synopsis ptable = envpak(ppspace);
- *
- * char *ptable Address of packed table, or NIL if
- * failure.
- * char **ppspace Address of pointer to beginning of
- * space occupied by table, or NIL if
- * failure. (This is the space to be
- * freed when the table can be abandoned.)
- *
- * Description ENVPAK collects the environment strings pointed to by
- * the standard global variable environ and packs them into
- * the form demanded by the DOS Execute function (0x4b).
- * The address of the packed table is returned as the value
- * of the function.
- *
- * Space for the packed table is allocated by calloc(). A
- * pointer to the allocated space is returned in *ppspace.
- * THIS DOES NOT NECESSARILY COINCIDE WITH ptable
- * (typically it will be a few bytes in advance of ptable).
- * Use the value *ppspace to free the space when it is no
- * longer needed.
- *
- * The table is in the form of a sequence of consecutive
- * strings, each terminated by the usual NUL character
- * ('\0'). The last string is followed by a null string,
- * i.e., just a single NUL. The first string begins at a
- * 16-byte boundary.
- *
- * An error occurs if space cannot be allocated for the
- * packed table. If so, NIL is returned in *ppspace and as
- * the value of the function.
- *
- * Example The following example shows how to call ENVPAK, how to
- * declare its arguments, and how to free the allocated
- * space afterward.
- *
- * #include <bprogctl.h>
- * #include <butility.h> <-- for declaration of NIL
- *
- * #if MSC300
- * #include <malloc.h> <-- for declaration of free()
- * #else
- * #include <stdlib.h> <-- for declaration of free()
- * #endif
- *
- * char *ptable,*pspace;
- *
- * ptable = envpak(&pspace);
- * if (ptable != NIL)
- * {
- * . . . Use the table . . .
- *
- * free(pspace);
- * }
- *
- * Returns *ptable Packed table, or NIL if failure.
- * *ppspace Address of beginning of space occupied
- * by table, or NIL if failure. (This is
- * the space to be freed when the table
- * can be abandoned.)
- *
- **/
-
- #if LAT300
- extern char **environ;
- #endif
-
- static char *envpak(ppspace)
- char **ppspace;
- {
- register char **envtbl; /* Moving pointer into table of */
- /* pointers to environment strings. */
-
- register char *envstr; /* Pointer to one environment entry. */
- char *ptable;
- char *pentry; /* Moving pointer into packed table. */
- ADS space_ads;
- int total_len;
- int len;
-
- envtbl = environ;
- total_len = 0;
- while (envstr = *envtbl++) /* Step through the entries, */
- { /* counting total length */
- /* (including each trailing NUL)*/
- if (0 != (len = (int) strlen(envstr)))
- total_len += len + 1;
- }
-
- #define size (total_len + 1) /* Account for final trailing */
- /* NUL. */
-
- /* Allocate 15 extra bytes so */
- /* we can align on 16-byte */
- /* boundary. */
- if (NIL == (*ppspace = calloc((unsigned int) (size + 15),1)))
- return NIL; /* Insufficient memory for */
- /* table. */
-
- utabsptr(*ppspace,&space_ads); /* Point ptable at first 16- */
- /* byte boundary in the space. */
- ptable = *ppspace + ((16 - (space_ads.r & 0x000f)) % 16);
-
- envtbl = environ;
- pentry = ptable;
- while (envstr = *envtbl++) /* Copy each entry. */
- {
- if (0 != (len = (int) strlen(envstr)))
- {
- strcpy(pentry,envstr);
- pentry += len + 1;
- }
- }
- *pentry = '\0'; /* Extra NUL after all entries. */
-
- return ptable;
- }