home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c005 / 4.ddi / C / PCEXEC.C < prev    next >
Encoding:
C/C++ Source or Header  |  1987-04-13  |  10.4 KB  |  336 lines

  1. /**
  2. *
  3. * Name        pcexec -- Load and execute a program
  4. *
  5. * Synopsis    ercode = pcexec(pfile,pcmd,fcb_flag);
  6. *
  7. *        int  ercode      0 if successful;
  8. *                  300 if calloc() failed;
  9. *                  if another positive value, this is
  10. *                   the error from MMSETBLK which
  11. *                   prevented releasing memory for the
  12. *                   child;
  13. *                  if negative, this is the OPPOSITE of
  14. *                   the DOS error encountered while
  15. *                   loading the child program.
  16. *        char *pfile      Name of file to load and execute
  17. *        char *pcmd      Commmand line to pass to the program
  18. *        int  fcb_flag      If nonzero, offset 5C and 6C of the
  19. *                  child process program segment prefix
  20. *                  are filled with file control blocks
  21. *                  formatted as the first two command
  22. *                  line parameters.  If it is zero, the
  23. *                  file control blocks are inherited
  24. *                  from the parent process.
  25. *
  26. * Description    This function loads and executes the program whose file
  27. *        name is specified by *pfile.  The program is loaded and
  28. *        executed as if invoked from DOS with the command line
  29. *        specified in *pcmd.  The child program returns control
  30. *        when either execution ends or Ctrl/Break is pressed.
  31. *
  32. *        Many of the DOS external commands (e.g., FORMAT,
  33. *        DISKCOPY, etc.) expect the command line parameters to be
  34. *        formatted in the file control blocks at offsets 0x5C and
  35. *        0x6C in their program segment prefix.  (In fact, when
  36. *        COMMAND.COM loads a program it always does just that.)
  37. *        If fcb_flag is nonzero, the first two parameters of the
  38. *        command line are placed in the formatted FCBs; if
  39. *        fcb_flag is zero, the parent FCBs are inherited by the
  40. *        child.
  41. *
  42. *        The command line is truncated to 126 bytes if necessary.
  43. *        It should be terminated by a NUL byte ('\0') as usual.
  44. *        It should not contain any carriage returns ('\15') or
  45. *        line feeds ('\12').
  46. *
  47. *        The original idea for this revision of PCEXEC is due to
  48. *        Lloyd Zusman of Master Byte Software (August 1984).
  49. *
  50. * Returns    ercode          0 if successful;
  51. *                  300 if calloc() failed;
  52. *                  if another positive value, this is
  53. *                   the error from MMSETBLK which
  54. *                   prevented releasing memory for the
  55. *                   child;
  56. *                  if negative, this is the OPPOSITE of
  57. *                   the DOS error encountered while
  58. *                   loading the child program.
  59. *
  60. * Version    3.0  (C)Copyright Blaise Computing Inc.  1983, 1984, 1986
  61. *
  62. * Version    3.01 August 20, 1986  PLD
  63. *        Corrected declaration of "environ" for Lattice compiler.
  64. *
  65. * Version    3.02 March 24, 1987
  66. *        Prevented copying of null environment strings ("") into
  67. *            child's copy of environment table (because DOS
  68. *            function 0x4b considers a null string to be the
  69. *            end of the table.
  70. *
  71. **/
  72.  
  73. #include <stdlib.h>
  74. #include <string.h>
  75.  
  76. #include <bmemory.h>
  77. #include <bprogctl.h>
  78. #include <butility.h>
  79.  
  80. #if MSC300
  81. #include <malloc.h>
  82. #endif
  83.  
  84. static char *envpak(char **);          /* Internal (see below).          */
  85.  
  86. #define OUT_OF_MEMORY    300
  87.  
  88. int pcexec(pfile,pcmd,fcb_flag)
  89. char *pfile,*pcmd;
  90. int  fcb_flag;
  91. {
  92.  
  93.     struct fc_block              /* DOS File Control Block (FCB) */
  94.     {                      /* structure.  It is needed if  */
  95.     char drive;              /* fcb_flag is nonzero.          */
  96.     char f_name[8];
  97.     char f_ext[3];
  98.     int  cur_block;
  99.     int  rec_size;
  100.     long file_size;
  101.     int  cr_date;
  102.     char reserved[10];
  103.     char rec_num;
  104.     long rel_rec;
  105.     } *pfcb1, *pfcb2;
  106.  
  107.     struct parm_block              /* Parameter block used by EXEC */
  108.     {                      /*   function (DOS 0x4b call)   */
  109.     unsigned envseg;          /* Segment of environment       */
  110.     ADS     cmd_ads;          /* ADS of command line          */
  111.     ADS     fb1_ads;          /* ADS of first and second file */
  112.     ADS     fb2_ads;          /*   control blocks (FCBs)      */
  113.     } block_val;
  114.  
  115.     DOSREG   dos_reg;
  116.     ADS      env_ads,loc_ads;
  117.     int      ercode,cmd_len;
  118.     unsigned size;
  119.     char     *pcmd_line;
  120.     char     *penv_table,*penv_space;
  121.  
  122.     if ((ercode = mmshrink(&size)) != 0)
  123.        return(ercode);              /* Error releasing memory.      */
  124.  
  125.     /* Pack the current environment table and store it on a segment   */
  126.     /* boundary.  Compute its physical segment and store it as          */
  127.     /* block_val.envseg.                          */
  128.  
  129.     if (NIL == (penv_table = envpak(&penv_space)))
  130.     return OUT_OF_MEMORY;
  131.  
  132.     utabsptr(penv_table,&env_ads);
  133.     block_val.envseg = env_ads.s + (env_ads.r >> 4);
  134.  
  135.     /* The command line must have a leading length byte followed by   */
  136.     /* actual characters making up the string.    Then move the address */
  137.     /* of the command line to the parameter block.              */
  138.  
  139.     cmd_len    = (int) strlen(pcmd);
  140.     utuplim(cmd_len,126);
  141.     pcmd_line  = calloc((unsigned int) (cmd_len + 3),1);
  142.  
  143.     if (pcmd_line == NIL)
  144.     {
  145.     free(penv_space);
  146.     return OUT_OF_MEMORY;
  147.     }
  148.  
  149.     *pcmd_line = (char) cmd_len;
  150.     strncpy(pcmd_line+1,pcmd,(unsigned int) cmd_len);
  151.     *(pcmd_line + cmd_len + 1) = '\15'; /* Trailing carriage return   */
  152.     utabsptr(pcmd_line,&block_val.cmd_ads);
  153.  
  154.     /* If fcb_flag is nonzero, build the FCBs out of the command      */
  155.     /* line.  The DOS function call 0x29 is used to scan the command  */
  156.     /* line and create the FCBs.                      */
  157.  
  158.     if (fcb_flag)
  159.     {
  160.     pfcb1 = utalloc(struct fc_block);
  161.     pfcb2 = utalloc(struct fc_block);
  162.  
  163.     if (pfcb1 == NIL || pfcb2 == NIL)
  164.     {
  165.         free(pcmd_line);
  166.         free(penv_space);
  167.         return OUT_OF_MEMORY;
  168.     }
  169.  
  170.     utabsptr(pcmd,&loc_ads);
  171.     dos_reg.ds = loc_ads.s;       /* Location of the command line */
  172.     dos_reg.si = loc_ads.r;       /* to be parsed.              */
  173.  
  174.                       /* Address of formatted FCB area*/
  175.     utabsptr((char *) pfcb1,&block_val.fb1_ads);
  176.     dos_reg.es = block_val.fb1_ads.s;
  177.     dos_reg.di = block_val.fb1_ads.r;
  178.     dos_reg.ax = 0x2901;
  179.     dos(&dos_reg);              /* DS,SI now point to next item */
  180.                       /* in the command line.          */
  181.     utabsptr((char *) pfcb2,&block_val.fb2_ads);
  182.     dos_reg.es = block_val.fb2_ads.s;
  183.     dos_reg.di = block_val.fb2_ads.r;
  184.     dos_reg.ax = 0x2901;
  185.     dos(&dos_reg);
  186.     }
  187.     else                  /* Use parent's FCBs            */
  188.     {
  189.     block_val.fb1_ads.r = 0x5c;
  190.     block_val.fb2_ads.r = 0x6c;
  191.     block_val.fb1_ads.s =
  192.     block_val.fb2_ads.s = utpspseg;
  193.     }
  194.  
  195.     dos_reg.ax = 0x4b00;
  196.     utabsptr((char *) &block_val,&loc_ads);
  197.     dos_reg.es = loc_ads.s;
  198.     dos_reg.bx = loc_ads.r;
  199.     utabsptr(pfile,&loc_ads);
  200.     dos_reg.ds = loc_ads.s;
  201.     dos_reg.dx = loc_ads.r;
  202.  
  203.     ercode = -dos(&dos_reg);           /* Return negative error code   */
  204.     if (fcb_flag)
  205.     {
  206.     free((char *) pfcb1);           /* If FCBs were constructed, we */
  207.     free((char *) pfcb2);           /* free the allocated memory.   */
  208.     }
  209.     free(pcmd_line);
  210.     free(penv_space);
  211.  
  212.     return(ercode);
  213. }
  214.  
  215. /**
  216. *
  217. * Name        envpak -- Pack environment table for PCEXEC
  218. *
  219. * Synopsis    ptable = envpak(ppspace);
  220. *
  221. *        char *ptable      Address of packed table, or NIL if
  222. *                  failure.
  223. *        char **ppspace      Address of pointer to beginning of
  224. *                  space occupied by table, or NIL if
  225. *                  failure.  (This is the space to be
  226. *                  freed when the table can be abandoned.)
  227. *
  228. * Description    ENVPAK collects the environment strings pointed to by
  229. *        the standard global variable environ and packs them into
  230. *        the form demanded by the DOS Execute function (0x4b).
  231. *        The address of the packed table is returned as the value
  232. *        of the function.
  233. *
  234. *        Space for the packed table is allocated by calloc().  A
  235. *        pointer to the allocated space is returned in *ppspace.
  236. *        THIS DOES NOT NECESSARILY COINCIDE WITH ptable
  237. *        (typically it will be a few bytes in advance of ptable).
  238. *        Use the value *ppspace to free the space when it is no
  239. *        longer needed.
  240. *
  241. *        The table is in the form of a sequence of consecutive
  242. *        strings, each terminated by the usual NUL character
  243. *        ('\0').  The last string is followed by a null string,
  244. *        i.e., just a single NUL.  The first string begins at a
  245. *        16-byte boundary.
  246. *
  247. *        An error occurs if space cannot be allocated for the
  248. *        packed table.  If so, NIL is returned in *ppspace and as
  249. *        the value of the function.
  250. *
  251. * Example    The following example shows how to call ENVPAK, how to
  252. *        declare its arguments, and how to free the allocated
  253. *        space afterward.
  254. *
  255. *            #include <bprogctl.h>
  256. *            #include <butility.h>   <-- for declaration of NIL
  257. *
  258. *            #if MSC300
  259. *            #include <malloc.h>     <-- for declaration of free()
  260. *            #else
  261. *            #include <stdlib.h>     <-- for declaration of free()
  262. *            #endif
  263. *
  264. *            char *ptable,*pspace;
  265. *
  266. *            ptable = envpak(&pspace);
  267. *            if (ptable != NIL)
  268. *            {
  269. *            . . . Use the table . . .
  270. *
  271. *            free(pspace);
  272. *            }
  273. *
  274. * Returns    *ptable       Packed table, or NIL if failure.
  275. *        *ppspace      Address of beginning of space occupied
  276. *                  by table, or NIL if failure.    (This is
  277. *                  the space to be freed when the table
  278. *                  can be abandoned.)
  279. *
  280. **/
  281.  
  282. #if LAT300
  283. extern char **environ;
  284. #endif
  285.  
  286. static char *envpak(ppspace)
  287. char **ppspace;
  288. {
  289.     register char **envtbl;   /* Moving pointer into table of          */
  290.                   /* pointers to environment strings.     */
  291.  
  292.     register char *envstr;    /* Pointer to one environment entry.    */
  293.     char *ptable;
  294.     char *pentry;          /* Moving pointer into packed table.    */
  295.     ADS space_ads;
  296.     int total_len;
  297.     int len;
  298.  
  299.     envtbl    = environ;
  300.     total_len = 0;
  301.     while (envstr = *envtbl++)          /* Step through the entries,    */
  302.     {                      /* counting total length          */
  303.                       /* (including each trailing NUL)*/
  304.     if (0 != (len = (int) strlen(envstr)))
  305.         total_len += len + 1;
  306.     }
  307.  
  308. #define size  (total_len + 1)          /* Account for final trailing   */
  309.                       /* NUL.                  */
  310.  
  311.                       /* Allocate 15 extra bytes so   */
  312.                       /* we can align on 16-byte      */
  313.                       /* boundary.              */
  314.     if (NIL == (*ppspace = calloc((unsigned int) (size + 15),1)))
  315.     return NIL;              /* Insufficient memory for      */
  316.                       /* table.               */
  317.  
  318.     utabsptr(*ppspace,&space_ads);    /* Point ptable at first 16-    */
  319.                       /* byte boundary in the space.  */
  320.     ptable = *ppspace + ((16 - (space_ads.r & 0x000f)) % 16);
  321.  
  322.     envtbl = environ;
  323.     pentry = ptable;
  324.     while (envstr = *envtbl++)          /* Copy each entry.          */
  325.     {
  326.     if (0 != (len = (int) strlen(envstr)))
  327.     {
  328.         strcpy(pentry,envstr);
  329.         pentry += len + 1;
  330.     }
  331.     }
  332.     *pentry = '\0';                   /* Extra NUL after all entries. */
  333.  
  334.     return ptable;
  335. }
  336.