/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* |_o_o|\\ Copyright (c) 1986 The Software Distillery.  All Rights Reserved */
/* |. o.| || This program may not be distributed without the permission of   */
/* | .  | || the authors.                                                    */
/* | o  | ||    Dave Baker     Ed Burnette  Stan Chow    Jay Denebeim        */
/* |  . |//     Gordon Keener  Jack Rouse   John Toebes  Doug Walker         */
/* ======          BBS:(919)-471-6436      VOICE:(919)-469-4210              */ 
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
 * VERY loosely based on the input.device example by Rob Peck, 12/1/85
 */

/*
 * copyproc() copies over the process information from one process (typically
 * a parent) to another process (typically a child). Pass it the pointers
 * to the two processes, and let copyproc() do the rest.
 */

#include "popcli.h"
#include <rexx/storage.h>

/* Dos constants. Don't ask about the 64. */
#define CLISIZE      sizeof(struct CommandLineInterface)
#define STRINGSIZE   64

/* BE SURE TO CALL termproc() WHEN PROCESS "to" TERMINATES!!!!! */

static BPTR DosAlloc( GLOBAL_DATA *, long );

void copyproc( gptr, to, from )
GLOBAL_DATA *gptr;
register struct Process *to;
register struct Process *from;
{
   register struct CommandLineInterface  *tocli;
   register struct CommandLineInterface  *fromcli;

   struct CDIR *current, *new;

   long         tostr;

   /* We need to copy over the information from the process which started */
   /* us. Currently we will copy:                                         */
   /*   Stack size                                                        */
   /*   Path                                                              */
   /*   Prompt                                                            */
   /*   Default Directory                                                 */
   /*   Fail Level                                                        */

   /* First, the current directory. Easy-peasy. */
   CurrentDir( DupLock( from->pr_CurrentDir ) );

   /* See if we have any CLI info to worry about. */
   fromcli = (struct CommandLineInterface *)(from->pr_CLI << 2);
   if (fromcli == NULL)
   {
      to->pr_CLI = NULL;
      return;
   }

   /* Allocate the new CLI structure and prompt structure */
   tocli = (struct CommandLineInterface *)
                     (DosAlloc( gptr, CLISIZE + (2 * STRINGSIZE) ) << 2);
   memset( (char *)tocli, 0, CLISIZE );
   to->pr_CLI = ((long)tocli) >> 2;

   /* Copy the prompt structure to the new block if the old CLI structure */
   /* had a prompt field.                                                 */
   if (fromcli->cli_Prompt)
   {
      tostr = ((long)tocli) + CLISIZE;
      memcpy( (char *)tostr, (char *)(fromcli->cli_Prompt << 2), STRINGSIZE );
      tocli->cli_Prompt = tostr >> 2;
   }

   /* Copy the Current Working Directory Name block, if it exists */
   if (fromcli->cli_SetName)
   {
      tostr = ((long)tocli) + CLISIZE + STRINGSIZE;
      memcpy( (char *)tostr, (char *)(fromcli->cli_SetName << 2), STRINGSIZE );
      tocli->cli_SetName = tostr >> 2;
   }
      
   tocli->cli_FailLevel    = fromcli->cli_FailLevel;
   tocli->cli_DefaultStack = fromcli->cli_DefaultStack;

   /* Now, copy the path. Hardy-pardy. These things are chained with */
   /* (ugh) BPTRs in a strange arrangement described in the CDIR     */
   /* structure above. We merely go thru, allocating new CDIRs and   */
   /* DupLock()ing.                                                  */

   for (current = (struct CDIR *)(fromcli->cli_CommandDir << 2), new = NULL;
        current != NULL;
        current = (struct CDIR *)(current->next << 2))
   {
      if (new == NULL)
      {
         /* Put the first block in the CLI structure. */
         tocli->cli_CommandDir = DosAlloc( gptr, sizeof(struct CDIR) );
         new = (struct CDIR *)(tocli->cli_CommandDir << 2);
      }
      else
      {
         /* Thereafter, new blocks get chained on the previous one.  */
         new->next = DosAlloc( gptr, sizeof(struct CDIR) );
         new = (struct CDIR *)(new->next << 2);
      }

      new->lock = DupLock( current->lock );
      new->next = NULL;  /* just in case this is the last one */
   }
}

/*
 * Allocate block & remember the length.
 * Blocks should be freed with DosFree, in termproc.c
 */

static BPTR DosAlloc( gptr, size )
GLOBAL_DATA *gptr;
register long size;
{
   register long    *new;

   size += 4;

   new = (long *)AllocMem( size, 0 );

/*
   if (new == NULL)
      barf();
*/

   *new++ = size;

   return( ((long)new) >> 2 );
}
