home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / MISC / GNU / MAK358AS.ZIP / SPAWN.C < prev    next >
Encoding:
C/C++ Source or Header  |  1992-02-22  |  17.4 KB  |  727 lines

  1. /*  spawn.c - replacements for MSC spawn*() functions
  2.     Copyright (C) 1990 by Thorsten Ohl, ohl@gnu.ai.mit.edu
  3.  
  4.     This program is free software; you can redistribute it and/or modify
  5.     it under the terms of the GNU General Public License as published by
  6.     the Free Software Foundation; either version 1, or (at your option)
  7.     any later version.
  8.  
  9.     This program is distributed in the hope that it will be useful,
  10.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.     GNU General Public License for more details.
  13.  
  14.     You should have received a copy of the GNU General Public License
  15.     along with this program; if not, write to the Free Software
  16.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18.     IMPORTANT:
  19.  
  20.     This code is not an official part of the GNU project and the
  21.     author is not affiliated to the Free Software Foundation.
  22.     He just likes their code and spirit.  */
  23.  
  24. static char RCS_id[] =
  25. "$Header: e:/gnu/make/RCS/spawn.c'v 0.18 90/07/22 14:42:38 tho Exp $";
  26.  
  27.  
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <ctype.h>
  32. #include <process.h>
  33. #include <malloc.h>
  34. #include <errno.h>
  35. #include <direct.h>
  36. #include <dos.h>
  37. #include <io.h>
  38. #include <sys/types.h>
  39.  
  40.  
  41. #define MAX_MSDOS_CMDLINE    126
  42. #define MAX_MSDOS_PATH        144
  43.  
  44. /* IMPORTED DECLARATIONS */
  45.  
  46. enum swapping_mode
  47. {
  48.   none, disk, ems, xms
  49. };
  50.  
  51. extern int
  52. spawn_child (enum swapping_mode mode, char *path, char *cmdline, char *env,
  53.          int len, char *swap_file);
  54.  
  55.  
  56. /* PRIVATE DECLARATIONS */
  57.  
  58. static void swapping_mode_hook (enum swapping_mode * swapping_ptr, char *dev);
  59. static int commandline_hook (char *cmd, char **argv, char **env0,
  60.                  char **respond_file_name_ptr);
  61. static char *putenv_cmdline (char *cmd, char **argv);
  62. static int build_environment (char _far ** envbuf, char *cmdline,
  63.                   char **envvec);
  64. static char *build_link_respond_file (char **argv);
  65. static char *build_lib_respond_file (char **argv);
  66. static char *build_zip_respond_file (char **argv);
  67. static int build_cmdline (char **argv);
  68. static char *expand_path (char *name, char *env, char *(*select) (char *));
  69. static char *executable_p (char *path);
  70. extern void *xmalloc (size_t size);
  71. extern void *xrealloc (void *ptr, size_t size);
  72.  
  73. static char *extensions[] =/* extensions recognized during */
  74. {                /* path search */
  75.   ".bat",            /* this will be passed to the shell */
  76.   ".exe",
  77.   ".com",
  78.   NULL,
  79. };
  80.  
  81. #define PATH_SEP    ';'
  82. #define FSLASH        '/'
  83. #define BSLASH        '\\'
  84.  
  85.  
  86. /* PUBLIC DECLARATIONS */
  87.  
  88. extern char *mktmpname (char *prefix);
  89.  
  90.  
  91. /* The main entry points, work just like spawnvpe?() from the standard MSC
  92.    library.  */
  93.  
  94. int swap_and_spawnvp (char *device, char *cmd, char **argv);
  95. int swap_and_spawnvpe (char *device, char *cmd, char **argv, char **envvec);
  96.  
  97. int
  98. swap_and_spawnvp (char *device, char *cmd, char **argv)
  99. {
  100.   return swap_and_spawnvpe (device, cmd, argv, NULL);
  101. }
  102.  
  103. int
  104. swap_and_spawnvpe (char *device, char *cmd, char **argv, char **envvec)
  105. {
  106.   int len;
  107.   int rc;
  108.   char _far *env = (char _far *) 0;
  109.   char *env0 = NULL;
  110.   char *respond_file_name = NULL;
  111.   char *swap_file_name = mktmpname ("vm");
  112.   enum swapping_mode swapping = xms;
  113.  
  114.   if (device != NULL)
  115.     swapping_mode_hook (&swapping, device);
  116.  
  117.   argv[0] = expand_path (cmd, "PATH", executable_p);
  118.   if (argv[0] == NULL)
  119.     return ENOENT;
  120.  
  121.   rc = commandline_hook (cmd, argv, &env0, &respond_file_name);
  122.   if (rc)
  123.     return rc;
  124.  
  125.   len = build_environment (&env, env0, (envvec == NULL) ? environ : envvec);
  126.   if (!len)
  127.     return E2BIG;
  128.  
  129.   rc = spawn_child (swapping, argv[0], argv[1], env, len, swap_file_name);
  130.  
  131.   if (env0)
  132.     free (env0);
  133.   if (env)
  134.     free (env);
  135.   if (*argv[1])
  136.     free (argv[1]);
  137.   free (swap_file_name);
  138.  
  139.   if (respond_file_name)    /* clean up disk */
  140.     unlink (respond_file_name);
  141.  
  142.   return rc;
  143. }
  144.  
  145.  
  146. /* Look if DEV corresponds to a known swapping device and set *SWAPPING_PTR
  147.    accordingly;  */
  148.  
  149. void
  150. swapping_mode_hook (enum swapping_mode * swapping_ptr, char *dev)
  151. {
  152.   if (dev)
  153.     {
  154.       strlwr (dev);
  155.       if (!strcmp ("xms", dev))
  156.     *swapping_ptr = xms;
  157.       else if (!strcmp ("ems", dev))
  158.     {
  159.       fprintf (stderr, "Swapping to expanded memory is not supported yet, "
  160.            "will try extended memory.\n");
  161.       *swapping_ptr = xms;
  162.     }
  163.       else if (!strcmp ("disk", dev))
  164.     *swapping_ptr = disk;
  165.       else if (!strcmp ("none", dev))
  166.     {
  167.       fprintf (stderr, "No swapping is not supported yet, "
  168.                 "will swap to disk.\n");
  169.       *swapping_ptr = disk;
  170.     }
  171.       else
  172.     {
  173.       fprintf (stderr, "Can't swap to `%s' (no such device), "
  174.            "will try extended memory.\n", dev);
  175.       *swapping_ptr = xms;
  176.     }
  177.     }
  178. }
  179.  
  180. /* Look if CMD allows or requires special treatment, manipulate ARGV
  181.    accordingly. If necessary, create ENV0 and RESPOND_FILE_NAME_PTR.
  182.    In any case, merge ARGV[1], ... into ARGV[1].
  183.    ~~~~~~~~~~~
  184.    Note that the special treatment can be switched off by giving CMD
  185.    uppercase!  */
  186.  
  187. int
  188. commandline_hook (char *cmd, char **argv, char **env0,
  189.           char **respond_file_name_ptr)
  190. {
  191.   if (!strcmp ("cl", cmd) || !strcmp ("fl", cmd) || !strcmp ("masm", cmd))
  192.     *env0 = putenv_cmdline (cmd, argv);
  193.   else if (!strcmp ("link", cmd))
  194.     {
  195.       *respond_file_name_ptr = build_link_respond_file (argv);
  196.       if (*respond_file_name_ptr == NULL)
  197.     return E2BIG;
  198.     }
  199.   else if (!strcmp ("lib", cmd))
  200.     {
  201.       *respond_file_name_ptr = build_lib_respond_file (argv);
  202.       if (*respond_file_name_ptr == NULL)
  203.     return E2BIG;
  204.     }
  205.   else if (!strcmp ("pkzip", cmd) || !strcmp ("pkunzip", cmd))
  206.     {
  207.       *respond_file_name_ptr = build_zip_respond_file (argv);
  208.       if (*respond_file_name_ptr == NULL)
  209.     return E2BIG;
  210.     }
  211.   else if (!build_cmdline (argv))
  212.     return E2BIG;
  213.  
  214.   return 0;            /* success */
  215. }
  216.  
  217.  
  218. /* Manipulating the environment.  */
  219.  
  220. /* Merge CMDLINE, ENVVEC[0], ... into ENVBUF as a well formed MS-DOS
  221.    environment (will be malloc()'d).  Returns the length (incl. the
  222.    trailing '\0's)  of the resulting environment.  */
  223.  
  224. int
  225. build_environment (char _far ** envbuf, char *cmdline, char **envvec)
  226. {
  227.   char *p;
  228.   char **envptr = envvec;
  229.   int len = 1;
  230.  
  231.   if (envvec == NULL && cmdline == NULL)
  232.     return 0;
  233.  
  234.   if (cmdline != NULL)
  235.     len += strlen (cmdline) + 1;
  236.   if (envvec != NULL)
  237.     while (*envptr)
  238.       len += strlen (*envptr++) + 1;
  239.  
  240.   p = *envbuf = (char *) xmalloc (len);
  241.  
  242.   if (cmdline != NULL)
  243.     {
  244.       strcpy (p, cmdline);
  245.       p += strlen (cmdline) + 1;
  246.     }
  247.   envptr = envvec;
  248.   if (envvec != NULL)
  249.     while (*envptr)
  250.       {
  251.     strcpy (p, *envptr);
  252.     p += strlen (*envptr++) + 1;
  253.       }
  254.   *p++ = '\0';            /* end of environment! */
  255.  
  256.   return (len);
  257. }
  258.  
  259.  
  260. /* Manipulating the commandline.  */
  261.  
  262. /* The following functions for manipulating the commandline do NOT free
  263.    the storage of the ARGV[] strings, since they can't know how it was
  264.    allocated (separately or as single block).  */
  265.  
  266. /* Build an environment entry for passing options to the Microsoft C
  267.    and Fortran Compilers and Macro Assembler.  CMD is the command to
  268.    execute.  ARGV[1],... will be moved to an environment entry "CMD" and
  269.    we will have ARGV[1] == "".  */
  270.  
  271. char *
  272. putenv_cmdline (char *cmd, char **argv)
  273. {
  274.   int nologo_flag = 0;
  275.   char **av = argv + 1;
  276.   char *p;
  277.   char *env;
  278.   int len = 3 + strlen (cmd);
  279.  
  280.   /* `fl' and `cl' understand the "-nologo" option to suppress the banner,
  281.       `masm' not.  */
  282.   if (!strcmp (cmd, "fl") || !strcmp (cmd, "cl"))
  283.     {
  284.       nologo_flag = 1;
  285.       len += 8;
  286.     }
  287.  
  288.   while (*av)
  289.     len += strlen (*av++) + 1;
  290.  
  291.   p = env = (char *) xmalloc (len);
  292.  
  293.   strcpy (p, strupr (cmd));
  294.   p += strlen (cmd);
  295.   *p++ = '=';
  296.  
  297.   if (nologo_flag)
  298.     {
  299.       strcpy (p, "-nologo");
  300.       p += 7;
  301.     }
  302.  
  303.   av = argv + 1;
  304.   while (*av)            /* paste arguments together */
  305.     {
  306.       *p++ = ' ';
  307.       strcpy (p, *av);
  308.       p += strlen (*av++);
  309.     }
  310.  
  311.   *argv[1] = '\0';        /* commandline terminated */
  312.  
  313.   return env;
  314. }
  315.  
  316.  
  317. /* Build a respondfile for the Microsoft linker from ARGV[0].  Returns the
  318.    name of the generated file on success, NULL otherwise.  The new
  319.    commandline ARGV[1] holds the proper command for instructing the linker
  320.    to use this respondfile.  */
  321.  
  322. char *
  323. build_link_respond_file (char **argv)
  324. {
  325.   int len = 0;
  326.   char **av = argv;
  327.   FILE *respond_file;
  328.   char *respond_file_name = mktmpname ("lk");
  329.  
  330.   if (!(respond_file = fopen (respond_file_name, "w")))
  331.     {
  332.       fprintf (stderr, "can't open link respond_file %s.\n",
  333.            respond_file_name);
  334.       return NULL;
  335.     }
  336.  
  337.   while (*++av)
  338.     {
  339.       char *cp;
  340.  
  341.       if (strlen (*av) + len > 50)
  342.     {
  343.       fprintf (respond_file, "+\n");
  344.       len = 0;
  345.     }
  346.  
  347.       while (cp = strchr (*av, ','))    /* new respond group? */
  348.     {
  349.       *cp = '\n';
  350.       len = *av - cp - 1;    /* precompensate */
  351.     }
  352.  
  353.       len += fprintf (respond_file, "%s ", *av);
  354.     }
  355.  
  356.   fprintf (respond_file, ";\n");/* avoid prompts! */
  357.  
  358.   fclose (respond_file);
  359.  
  360.   argv[1] = (char *) xmalloc (strlen (respond_file_name) + 9);
  361.   sprintf (argv[1], "/batch @%s", respond_file_name);
  362.  
  363.   return respond_file_name;
  364. }
  365.  
  366.  
  367. /* Build a respondfile for the Microsoft library manager from ARGV[0].
  368.    Returns the name of the generated file on success, NULL otherwise.  The
  369.    new commandline ARGV[1] holds the proper command for instructing the
  370.    library manager to use this respondfile.   A module without command
  371.    inherits the one of it's predecessor.  This allows constructions like
  372.    `lib foo.lib -+ $?' in the makefiles (idea stolen from Kneller's
  373.    `ndmake').  */
  374.  
  375. char *
  376. build_lib_respond_file (char **argv)
  377. {
  378.   int len = 0;
  379.   char **av = argv;
  380.   FILE *respond_file;
  381.   char *respond_file_name = mktmpname ("lb");
  382.   static char lib_action[3] = "+";
  383.  
  384.   if (!(respond_file = fopen (respond_file_name, "w")))
  385.     {
  386.       fprintf (stderr, "can't open lib respond_file %s.\n",
  387.            respond_file_name);
  388.       return NULL;
  389.     }
  390.  
  391.   fprintf (respond_file, " %s\n ", *++av);    /* easy: the lib file  */
  392.  
  393.   if (access (*av, 0))        /* new library */
  394.     fprintf (respond_file, "y\n ");    /* create it! */
  395.  
  396.   while (*++av)
  397.     {
  398.       char *cp;
  399.  
  400.       if (strchr ("+-*", **av))
  401.     {
  402.       lib_action[0] = *(*av)++;
  403.  
  404.       if (strchr ("+-*", **av))
  405.         lib_action[1] = *(*av)++;
  406.       else
  407.         lib_action[1] = '\0';
  408.     }
  409.  
  410.       if (**av)
  411.     {
  412.       if (strlen (*av) + len > 50)
  413.         {
  414.           fprintf (respond_file, "&\n ");
  415.           len = 0;
  416.         }
  417.  
  418.       len += fprintf (respond_file, "%s", lib_action) + 1;
  419.  
  420.       while (cp = strchr (*av, ','))    /* new respond group? */
  421.         {
  422.           *cp = '\n';
  423.           len = *av - cp - 1;    /* precompensate */
  424.           lib_action[0] = '\0';    /* no more actions! */
  425.         }
  426.  
  427.       len += fprintf (respond_file, "%s ", *av) + 1;
  428.     }
  429.     }
  430.  
  431.   fprintf (respond_file, ";\n");/* avoid prompts! */
  432.  
  433.   fclose (respond_file);
  434.  
  435.   argv[1] = (char *) xmalloc (strlen (respond_file_name) + 10);
  436.   sprintf (argv[1], "/nologo @%s", respond_file_name);
  437.  
  438.   return respond_file_name;
  439. }
  440.  
  441.  
  442. /* Build a respondfile for the pk(un)?zip archive managers from ARGV[0].
  443.    Returns the name of the generated file on success, NULL otherwise.  The
  444.    new commandline ARGV[1] holds the proper command for instructing
  445.    pk(un)?zip to use this respondfile.  */
  446.  
  447. char *
  448. build_zip_respond_file (char **argv)
  449. {
  450.   char *cmdline = (char *) xmalloc (127 * sizeof (char));
  451.   char *ptr = cmdline;
  452.   char **av = argv + 1;
  453.   int len = 0;
  454.   FILE *respond_file = NULL;
  455.   char *respond_file_name = mktmpname ("zi");
  456.  
  457.   respond_file = fopen (respond_file_name, "w");
  458.   if (respond_file == NULL)
  459.     {
  460.       fprintf (stderr, "can't open zip respondfile %s.\n", respond_file_name);
  461.       return NULL;
  462.     }
  463.  
  464.   while (**av == '-')        /* leave options on the commandline */
  465.     {
  466.       if (ptr - cmdline + strlen (*av) > 126)
  467.     {
  468.       free (cmdline);
  469.       return NULL;
  470.     }
  471.       strcpy (ptr, *av);
  472.       ptr += strlen (*av);
  473.       *ptr++ = ' ';
  474.       av++;
  475.     }
  476.  
  477.   if (*av == NULL        /* missing zipfilename? */
  478.       || ptr - cmdline + strlen (*av) + strlen (respond_file_name) > 124)
  479.     {
  480.       free (cmdline);
  481.       return NULL;
  482.     }
  483.  
  484.   sprintf (ptr, "%s @%s", *av++, respond_file_name);
  485.  
  486.   while (*av)
  487.     fprintf (respond_file, "%s\n", *av++);
  488.  
  489.   fprintf (respond_file, "\n");
  490.   fclose (respond_file);
  491.  
  492.   argv[1] = cmdline;
  493.  
  494.   return respond_file_name;
  495. }
  496.  
  497.  
  498. /* Build a MS-DOS commandline from the supplied argument vector ARGV and
  499.    put it into ARGV[1].  Storage of the old argv[1], ... is NOT free()'d,
  500.    since we can't know how it was allocated (separately or as single
  501.    block)! ARGV[0] is assumed to be a fully expanded pathname incl
  502.    extension.  If ARGV[0] ends int ".bat", we will pass the command to the
  503.    shell.  Returns 1 on success, 0 if the commandline is too long.  */
  504.  
  505. int
  506. build_cmdline (char **argv)
  507. {
  508.   char *cmdline = (char *) xmalloc (128 * sizeof (char));
  509.   char *p = cmdline;
  510.   char *tmp;
  511.   char **av;
  512.  
  513.   if ((tmp = strrchr (argv[0], '.'))    /* .bat files will be passed */
  514.       && !strcmp (tmp + 1, "bat"))    /* to the shell ...  */
  515.     {
  516.       *tmp = '\0';        /* terminate */
  517.  
  518.       strcpy (p, "/c ");    /* return after execution */
  519.       p += 3;
  520.  
  521.       if ((tmp = strrchr (argv[0], BSLASH))    /* strip path */
  522.       || (tmp = strrchr (argv[0], FSLASH)))
  523.     strcpy (p, tmp + 1);
  524.       else
  525.     strcpy (p, argv[0]);
  526.  
  527.       p += strlen (p);
  528.       *p++ = ' ';
  529.  
  530.       if (!(argv[0] = getenv ("COMSPEC")))
  531.     {
  532.       fprintf (stderr, "command processor not found!");
  533.       exit (1);
  534.     }
  535.     }
  536.  
  537.   av = argv;            /* paste arguments together */
  538.   while (*++av)
  539.     {
  540.       strcpy (p, *av);
  541.       p += strlen (*av);
  542.       *p++ = ' ';
  543.       if ((p - cmdline) > 126)
  544.     return (0);        /* commandline to long for MeSy-DOS */
  545.     }
  546.  
  547.   *p = '\0';
  548.   argv[1] = cmdline;
  549.  
  550.   return (1);            /* success */
  551. }
  552.  
  553.  
  554.  
  555. /* $PATH search.  */
  556.  
  557. /* Look for NAME in the directories from $ENV ($PATH, if ENV is NULL),
  558.    satisfying SELECT.  */
  559.  
  560. char *
  561. expand_path (char *name, char *env, char *(*select) (char *))
  562. {
  563.   size_t name_len = strlen (name) + 6;    /*  SELECT may append 4 chars! */
  564.   char *exp = (char *) xmalloc (name_len);
  565.  
  566.   strcpy (exp, name);
  567.  
  568.   if ((*select) (exp))        /* first look in current directory. */
  569.     return exp;
  570.  
  571.   /* If not an absolute path, scan $PATH  */
  572.  
  573.   if (exp[1] != ':' && *exp != BSLASH && *exp != FSLASH)
  574.     {
  575.       char *ptr = getenv ((env == NULL) ? "PATH" : env);
  576.       if (ptr != NULL)
  577.     {
  578.       char *path = (char *) alloca (strlen (ptr) + 1);
  579.       strcpy (path, ptr);    /* get a copy strtok() can butcher. */
  580.  
  581.       ptr = strtok (path, ";");
  582.  
  583.       while (ptr != NULL)
  584.         {
  585.           exp = (char *) xrealloc (exp, strlen (ptr) + name_len);
  586.           if ((*select) (strcat (strcat (strcpy (exp, ptr), "/"), name)))
  587.         return exp;
  588.           ptr = strtok (NULL, ";");
  589.         }
  590.     }
  591.     }
  592.  
  593.   free (exp);
  594.   return NULL;            /* We've failed!  */
  595. }
  596.  
  597.  
  598. /* Return the expanded path with extension iff PATH is an executable MS-DOS
  599.    program, NULL otherwise.  */
  600.  
  601. static char *
  602. executable_p (char *path)
  603. {
  604.   char *base;
  605.   const char **ext = extensions;
  606.  
  607.   base = strrchr (strrchr (path, BSLASH), FSLASH);
  608.   if (base == NULL)
  609.     base = path;
  610.  
  611.   if (strchr (base, '.'))    /* explicit extension? */
  612.     {
  613.       if (!access (path, 0))
  614.     return path;
  615.     }
  616.   else
  617.     {
  618.       while (*base)        /* point to the end */
  619.     *base++;
  620.  
  621.       while (*ext)        /* try all extensions */
  622.     {
  623.       strcpy (base, *ext++);
  624.       if (!access (path, 0))
  625.         return path;
  626.     }
  627.     }
  628.  
  629.   return NULL;            /* failed */
  630. }
  631.  
  632.  
  633. /* Get a unique filename in the temporary directory from the environment
  634.    entry TMP or TEMP, if this fails, use current directory.  (replacement
  635.    for tempnam(), whish is *too* touchy about trailing path separators!) */
  636.  
  637. char *
  638. mktmpname (char *prefix)
  639. {
  640.   register int len;
  641.   register char *ptr;
  642.   register char *tmpname;
  643.   static char default_prefix[3] = "vm";
  644.  
  645.   if (!prefix[0] || !prefix[1])    /* did the user supply a prefix? */
  646.     prefix = default_prefix;
  647.  
  648.   if (!(ptr = getenv ("TMP")) && !(ptr = getenv ("TEMP")))
  649.     {
  650.  
  651.       ptr = ".";
  652.       len = 1;
  653.     }
  654.   else
  655.     {
  656.       len = strlen (ptr) - 1;
  657.       if ((ptr[len] == FSLASH) || (ptr[len] == BSLASH))
  658.     ptr[len] = '\0';
  659.     }
  660.  
  661.   tmpname = xmalloc (len + 10);
  662.  
  663.   sprintf (tmpname, "%s\\%2sXXXXXX", ptr, prefix);
  664.   mktemp (tmpname);
  665.  
  666.   return tmpname;
  667. }
  668.  
  669.  
  670. #ifdef TEST
  671.  
  672. extern void main (int ac, char **av);
  673.  
  674. void *
  675. xmalloc (size_t size)
  676. {
  677.   void *result = malloc (size);
  678.   if (result == NULL)
  679.     {
  680.       fprintf (stderr, "virtual memory exhausted");
  681.       abort ();
  682.     }
  683.   return result;
  684. }
  685.  
  686. void *
  687. xrealloc (void *ptr, size_t size)
  688. {
  689.   void *result = realloc (ptr, size);
  690.   if (result == NULL)
  691.     {
  692.       fprintf (stderr, "virtual memory exhausted");
  693.       abort ();
  694.     }
  695.   return result;
  696. }
  697.  
  698. void
  699. main (int ac, char **av)
  700. {
  701.   int n = 0;
  702.   int j = 2;
  703.   char **argv;
  704.  
  705.   argv = (char **) xmalloc ((ac - 1) * sizeof (char **));
  706.  
  707.   while (j < ac)
  708.     {
  709.       argv[n] = (char *) xmalloc (strlen (av[j]) + 1);
  710.       strcpy (argv[n++], av[j++]);
  711.     }
  712.   argv[n] = NULL;
  713.  
  714.   swap_and_spawnvp (av[1], *argv, argv);
  715. }
  716.  
  717. #endif /* TEST */
  718.  
  719.  
  720. /*
  721.  * Local Variables:
  722.  * mode:C
  723.  * ChangeLog:ChangeLog
  724.  * compile-command:cl -DTEST -W3 vmspawn.c swapcore
  725.  * End:
  726.  */
  727.