home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus Special 6 / Sonderheft_6-96.iso / pd / libraries / wbstart / src / start.c < prev    next >
C/C++ Source or Header  |  1996-11-03  |  13KB  |  522 lines

  1. /*
  2.  * start.c  V2.2
  3.  *
  4.  * Start a Workbench program
  5.  *
  6.  * (c) 1991-1996 Stefan Becker
  7.  */
  8.  
  9. #include "wbstart.h"
  10.  
  11. /* Local data structure */
  12. struct ProcessData {
  13.  struct WBStartup  pd_WBStartup;
  14.  BPTR              pd_HomeDir;
  15.  ULONG             pd_StackSize;
  16.  struct WBArg     *pd_CurrentArg;
  17.  /* Array of WBArgs follows */
  18. };
  19.  
  20. /* Local data */
  21. static const struct TagItem ProcTags[] = {
  22.  NP_FreeSeglist, FALSE,
  23.  NP_Input,       NULL,
  24.  NP_CloseInput,  FALSE,
  25.  NP_Output,      NULL,
  26.  NP_CloseOutput, FALSE,
  27.  NP_Error,       NULL,
  28.  NP_CloseError,  FALSE,
  29.  NP_CurrentDir,  NULL,  /* Makes sure that you don't see the guy from India */
  30.  NP_ConsoleTask, NULL,
  31.  NP_WindowPtr,   NULL,
  32.  TAG_DONE
  33. };
  34.  
  35. /* Duplicate a string */
  36. static char *StrDup(char *orig)
  37. {
  38.  char *rc;
  39.  
  40.  /* Allocate memory for string and copy it */
  41.  if (rc = AllocateMemory(strlen(orig) + 1)) strcpy(rc, orig);
  42.  
  43.  return(rc);
  44. }
  45.  
  46. /* Copy argument list */
  47. static BOOL CopyArguments(struct ProcessData *pd, struct WBArg *orig,
  48.                           ULONG count)
  49. {
  50.  struct WBArg *dest = pd->pd_CurrentArg;
  51.  BOOL rc            = TRUE;
  52.  
  53.  /* Scan original list */
  54.  while (count--) {
  55.  
  56.   DEBUGLOG(kprintf("Copy in : Lock: 0x%08lx, Name: %s (0x%08lx)\n",
  57.                    orig->wa_Lock, orig->wa_Name, orig->wa_Name);)
  58.  
  59.   /* Duplicate name and lock (NULL locks are only allowed for devices!) */
  60.   if (((dest->wa_Name = StrDup(orig->wa_Name)) == NULL) ||
  61.       (pd->pd_WBStartup.sm_NumArgs++,
  62.        (((dest->wa_Lock = DupLock(orig->wa_Lock)) == NULL) &&
  63.         (dest->wa_Name[strlen(dest->wa_Name) - 1] != ':')))) {
  64.  
  65.    /* Error */
  66.    rc = FALSE;
  67.  
  68.    /* Leave loop */
  69.    break;
  70.   }
  71.  
  72.   DEBUGLOG(kprintf("Copy Out: Lock: 0x%08lx, Name: %s (0x%08lx)\n",
  73.                    dest->wa_Lock, dest->wa_Name, dest->wa_Name);)
  74.  
  75.   /* Next entries */
  76.   orig++;
  77.   dest++;
  78.  }
  79.  
  80.  return(rc);
  81. }
  82.  
  83. /* Fill current WBArg */
  84. static BOOL FillCurrentArg(struct ProcessData *pd, BPTR currentdir, char *name)
  85. {
  86.  struct WBArg *wa = pd->pd_CurrentArg++;
  87.  BOOL rc          = FALSE;
  88.  
  89.  DEBUGLOG(kprintf("Fill in : Lock: 0x%08lx, Name: %s\n", currentdir, name);)
  90.  
  91.  /* Duplicate name */
  92.  if (wa->wa_Name = StrDup(name)) {
  93.   char *filepart;
  94.  
  95.   /* Increment argument count */
  96.   pd->pd_WBStartup.sm_NumArgs++;
  97.  
  98.   /* Clear lock */
  99.   wa->wa_Lock = NULL;
  100.  
  101.   /* Does name contain a path? */
  102.   if ((filepart = FilePart(wa->wa_Name)) != wa->wa_Name) {
  103.  
  104.    DEBUGLOG(kprintf("Name contains path\n");)
  105.  
  106.    /* Get a lock from the path part */
  107.    {
  108.     char savechar = *filepart;
  109.  
  110.     /* Add string terminator to path */
  111.     *filepart = '\0';
  112.  
  113.     /* Get lock */
  114.     rc = (wa->wa_Lock = Lock(wa->wa_Name, SHARED_LOCK)) != NULL;
  115.  
  116.     /* Restore file name */
  117.     *filepart = savechar;
  118.    }
  119.  
  120.    /* All OK? */
  121.    if (rc) {
  122.     BPTR parentlock = NULL;
  123.  
  124.     DEBUGLOG(kprintf("Path lock: 0x%08lx\n", wa->wa_Lock);)
  125.  
  126.     /* Lock the file and get a lock of the parent directory */
  127.     {
  128.      BPTR filelock;
  129.  
  130.      /* Try to lock complete file name */
  131.      if (filelock = Lock(wa->wa_Name, SHARED_LOCK)) {
  132.  
  133.       DEBUGLOG(kprintf("File lock: 0x%08lx\n", filelock);)
  134.  
  135.       /* Get lock of parent directory */
  136.       rc = (parentlock = ParentDir(filelock)) != NULL;
  137.  
  138.       /* Release lock on file */
  139.       UnLock(filelock);
  140.      }
  141.     }
  142.  
  143.     DEBUGLOG(kprintf("Parent Dir lock: 0x%08lx (rc %ld)\n", parentlock, rc);)
  144.  
  145.     /* All OK? */
  146.     if (rc &&
  147.  
  148.     /* Does the Path have at least one directory? */
  149.         ((*(filepart - 1) == '/') ||
  150.  
  151.     /* Path is a Device/Volume/Assign. Is the parent lock valid? */
  152.          ((parentlock != NULL) &&
  153.  
  154.     /* ...and is the parent dir lock the same as the path lock? */
  155.          (SameLock(parentlock, wa->wa_Lock) == LOCK_SAME)))) {
  156.  
  157.      DEBUGLOG(kprintf("Path contains directory or no Multi-Assign\n");)
  158.  
  159.      /* Path lock is valid. Delete path part in name buffer */
  160.      strcpy(wa->wa_Name, filepart);
  161.     }
  162.  
  163.     /* Release parent lock */
  164.     UnLock(parentlock);
  165.    }
  166.  
  167.   } else
  168.  
  169.    /* No, just duplicate current dir lock */
  170.    rc = (wa->wa_Lock = DupLock(currentdir)) != NULL;
  171.  }
  172.  
  173.  DEBUGLOG(kprintf("Fill out: Lock: 0x%08lx, Name: %s, RC %ld\n",
  174.                   wa->wa_Lock, wa->wa_Name, rc);)
  175.  
  176.  return(rc);
  177. }
  178.  
  179. /* Load program code */
  180. static BOOL LoadProgram(struct ProcessData *pd, BPTR currentdir, char *name)
  181. {
  182.  BPTR oldlock;
  183.  struct DiskObject *dobj;
  184.  BOOL rc                 = FALSE;
  185.  
  186.  DEBUGLOG(kprintf("Current Dir: 0x%08lx\n", currentdir);)
  187.  
  188.  /* Go to current directory */
  189.  oldlock = CurrentDir(currentdir);
  190.  
  191.  DEBUGLOG(kprintf("Load Icon: %s\n", name);)
  192.  
  193.  /* Get icon and check for projects */
  194.  if (dobj = GetDiskObject(name)) {
  195.  
  196.   /* Get stack size */
  197.   pd->pd_StackSize = dobj->do_StackSize;
  198.  
  199.   /* Check icon type */
  200.   switch (dobj->do_Type) {
  201.  
  202.    case WBTOOL:      /* Program is a TOOL */
  203.  
  204.     DEBUGLOG(kprintf("Tool icon\n");)
  205.  
  206.     /* Fill first WBArg */
  207.     rc = FillCurrentArg(pd, currentdir, name);
  208.  
  209.     /* Get home directory */
  210.     pd->pd_HomeDir = pd->pd_WBStartup.sm_ArgList->wa_Lock;
  211.     break;
  212.  
  213.    case WBPROJECT: { /* Program is a PROJECT */
  214.      char *tool = dobj->do_DefaultTool;
  215.  
  216.      DEBUGLOG(kprintf("Project icon, Tool: %s\n", tool);)
  217.  
  218.      /* Does the default tool contain a relative/absolute path? */
  219.      if (FilePart(tool) != tool) {
  220.  
  221.       /* Yes, fill first WBArg with default tool, second with project */
  222.       if (rc = (FillCurrentArg(pd, currentdir, tool) &&
  223.                 FillCurrentArg(pd, currentdir, name)))
  224.  
  225.        /* Get home directory */
  226.        pd->pd_HomeDir = pd->pd_WBStartup.sm_ArgList->wa_Lock;
  227.  
  228.      } else {
  229.       struct WBArg *first = pd->pd_WBStartup.sm_ArgList;
  230.  
  231.       /* No, fill first WBArg with project, second with default tool, */
  232.       /* but use the projects directory lock as current dir lock      */
  233.       if (rc = (FillCurrentArg(pd, currentdir, name) &&
  234.                 FillCurrentArg(pd, first->wa_Lock, tool))) {
  235.         struct WBArg temp;
  236.         struct WBArg *second = first + 1;
  237.  
  238.         /* Now swap first and second WBArg */
  239.         temp    = *first;
  240.         *first  = *second;
  241.         *second = temp;
  242.  
  243.         /* Scan load path for default tool */
  244.         pd->pd_HomeDir = ScanLoadPath(tool, currentdir);
  245.       }
  246.      }
  247.     }
  248.     break;
  249.   }
  250.  
  251.   /* Free icon */
  252.   FreeDiskObject(dobj);
  253.  
  254.   /* No icon. This is a special case which can never happen with    */
  255.   /* the Workbench. In this case the Workbench starts a CLI process */
  256.  } else {
  257.  
  258.   DEBUGLOG(kprintf("No program icon found\n");)
  259.  
  260.   /* Program is a TOOL. Fill first WBArg */
  261.   if (rc = FillCurrentArg(pd, currentdir, name))
  262.  
  263.    /* Does the program name contain a path? */
  264.    if (FilePart(name) != name)
  265.  
  266.     /* Yes, get home directory from first WBArg */
  267.     pd->pd_HomeDir = pd->pd_WBStartup.sm_ArgList->wa_Lock;
  268.  
  269.    else
  270.  
  271.     /* No, scan load path */
  272.     pd->pd_HomeDir = ScanLoadPath(name, currentdir);
  273.  }
  274.  
  275.  /* All OK? */
  276.  if (rc) {
  277.   char *tool = pd->pd_WBStartup.sm_ArgList->wa_Name;
  278.  
  279.   /* Yes, go to home directory */
  280.   CurrentDir(pd->pd_HomeDir);
  281.  
  282.   DEBUGLOG(kprintf("Loading program\n");)
  283.  
  284.   /* Load program */
  285.   if (rc = ((pd->pd_WBStartup.sm_Segment = NewLoadSeg(tool, NULL)) != NULL)) {
  286.  
  287.    DEBUGLOG(kprintf("Program loaded, retrieving icon\n");)
  288.  
  289.    /* Get tool icon */
  290.    if (dobj = GetDiskObject(tool)) {
  291.  
  292.     /* Copy Toolwindow */
  293.     if (dobj->do_ToolWindow)
  294.      rc = ((pd->pd_WBStartup.sm_ToolWindow = StrDup(dobj->do_ToolWindow))
  295.             != NULL);
  296.  
  297.     /* Free icon */
  298.     FreeDiskObject(dobj);
  299.    }
  300.   }
  301.  
  302.   DEBUGLOG(kprintf("Tool: %s, Home: 0x%08lx, Stack %ld\n",
  303.                    tool, pd->pd_HomeDir, pd->pd_StackSize);)
  304.  }
  305.  
  306.  /* Go back to old directory */
  307.  CurrentDir(oldlock);
  308.  
  309.  return(rc);
  310. }
  311.  
  312. /* Start a Workbench program */
  313. LONG StartProgram(struct TagItem *tags)
  314. {
  315.  LONG rc            = RETURN_FAIL;
  316.  char *name         = NULL;
  317.  BPTR dirlock       = NULL;
  318.  LONG priority      = 0;
  319.  ULONG stack        = 0;
  320.  ULONG count        = 0;
  321.  struct WBArg *args = NULL;
  322.  
  323.  /* Scan tag items */
  324.  {
  325.   struct TagItem *tstate = tags;
  326.   struct TagItem *ti;
  327.  
  328.   /* Get next tag item */
  329.   while (ti = NextTagItem(&tstate)) {
  330.  
  331.    DEBUGLOG(kprintf("Tag: 0x%08lx, Data: 0x%08lx\n", ti->ti_Tag, ti->ti_Data);)
  332.  
  333.    /* Which tag? */
  334.    switch (ti->ti_Tag) {
  335.  
  336.     case WBStart_Name:
  337.      name = (char *) ti->ti_Data;
  338.      break;
  339.  
  340.     case WBStart_DirectoryName:
  341.      if (ti->ti_Data) {
  342.       BPTR newlock;
  343.  
  344.       /* Get new lock */
  345.       if (newlock = Lock((STRPTR) ti->ti_Data, ACCESS_READ)) {
  346.  
  347.        DEBUGLOG(kprintf("Locked %s (0x%08lx), Unlocking 0x%08lx\n",
  348.                         ti->ti_Data, newlock, dirlock);)
  349.  
  350.        /* Release old directory lock first */
  351.        UnLock(dirlock);
  352.  
  353.        /* Set new lock */
  354.        dirlock = newlock;
  355.       }
  356.      }
  357.      break;
  358.  
  359.     case WBStart_DirectoryLock: {
  360.       BPTR newlock;
  361.  
  362.       /* Duplicate lock */
  363.       if (newlock = DupLock(ti->ti_Data)) {
  364.  
  365.        DEBUGLOG(kprintf("Duplicated 0x%08lx (0x%08lx), Unlocking 0x%08lx\n",
  366.                         ti->ti_Data, newlock, dirlock);)
  367.  
  368.        /* Release old directory lock first */
  369.        UnLock(dirlock);
  370.  
  371.        /* Set new lock */
  372.        dirlock = newlock;
  373.       }
  374.      }
  375.      break;
  376.  
  377.     case WBStart_Stack:
  378.      stack = ti->ti_Data;
  379.      break;
  380.  
  381.     case WBStart_Priority:
  382.      priority = ti->ti_Data;
  383.      break;
  384.  
  385.     case WBStart_ArgumentCount:
  386.      count = ti->ti_Data;
  387.      break;
  388.  
  389.     case WBStart_ArgumentList:
  390.      args = (struct WBArg *) ti->ti_Data;
  391.      break;
  392.    }
  393.   }
  394.  
  395.   DEBUGLOG(kprintf("Tags parsed.\n");)
  396.  }
  397.  
  398.  /* Parameter check                                                       */
  399.  /* a) Name must be specified                                             */
  400.  /* b) If argument list is specified then arg count must be specified too */
  401.  if (name && ((args == NULL) || (count != 0))) {
  402.   struct ProcessData *pd;
  403.  
  404.   DEBUGLOG(kprintf(
  405.   "Name: %s, Dir: 0x%08lx, Stack: %ld, Prio: %ld, Count: %ld, Args: 0x%08lx\n",
  406.   name, dirlock, stack, priority, count, args);)
  407.  
  408.   /* Sanity check for argument count */
  409.   if (args == NULL) count = 0;
  410.  
  411.   /* Sanity check for stack size */
  412.   if (stack < 4096) stack = 4096;
  413.  
  414.   /* Allocate WBStartup structure and argument array     */
  415.   /* Note that we reserve memory for two more arguments! */
  416.   if (pd = AllocateMemory(sizeof(struct ProcessData) +
  417.                           sizeof(struct WBArg) * (count + 2))) {
  418.  
  419.    DEBUGLOG(kprintf("Process data: 0x%08lx\n", pd);)
  420.  
  421.    /* Initialize ProcessData structure */
  422.    pd->pd_WBStartup.sm_Message.mn_Node.ln_Pri = 0;
  423.    pd->pd_WBStartup.sm_Message.mn_ReplyPort   = WBStartBase->wbsb_Port;
  424.    pd->pd_WBStartup.sm_Message.mn_Length      = sizeof(struct WBStartup);
  425.    pd->pd_WBStartup.sm_Segment                = NULL;
  426.    pd->pd_WBStartup.sm_NumArgs                = 0;
  427.    pd->pd_WBStartup.sm_ToolWindow             = NULL;
  428.    pd->pd_WBStartup.sm_ArgList                = (struct WBArg *) (pd + 1);
  429.    pd->pd_StackSize                           = stack;
  430.    pd->pd_CurrentArg                          = pd->pd_WBStartup.sm_ArgList;
  431.  
  432.    /* Load program code */
  433.    if (LoadProgram(pd, dirlock, name)) {
  434.  
  435.     DEBUGLOG(kprintf("Program loaded.\n");)
  436.  
  437.     /* Copy argument list */
  438.     if (CopyArguments(pd, args, count)) {
  439.      BPTR homelock;
  440.  
  441.      DEBUGLOG(kprintf("Arguments copied.\n");)
  442.  
  443.      /* Duplicate home directory lock */
  444.      if (homelock = DupLock(pd->pd_HomeDir)) {
  445.       struct Process *newproc;
  446.  
  447.       DEBUGLOG(kprintf("Home Dir Lock: 0x%08lx\n", homelock);)
  448.  
  449.       /* Create new process */
  450.       if (newproc = CreateNewProcTags(
  451.            NP_Seglist,   pd->pd_WBStartup.sm_Segment,
  452.            NP_StackSize, (stack > pd->pd_StackSize) ? stack : pd->pd_StackSize,
  453.            NP_Name,      pd->pd_WBStartup.sm_ArgList->wa_Name,
  454.            NP_Priority,  priority,
  455.            NP_HomeDir,   homelock,
  456.  
  457.            /* The rest is constant */
  458.            TAG_MORE,      ProcTags)) {
  459.        struct MsgPort *p = &newproc->pr_MsgPort;
  460.  
  461.        DEBUGLOG(kprintf("New process created: 0x%08lx\n", newproc);)
  462.  
  463.        /* Set WBStartup process pointer */
  464.        pd->pd_WBStartup.sm_Process = p;
  465.  
  466.        /* Send startup message to new process */
  467.        PutMsg(p, (struct Message *) pd);
  468.  
  469.        /* All OK */
  470.        rc = RETURN_OK;
  471.  
  472.       } else
  473.         /* Process not created,  free duplicate of home directory lock */
  474.         UnLock(homelock);
  475.      }
  476.     }
  477.    }
  478.  
  479.    /* Error? */
  480.    if (rc != RETURN_OK) FreeProcessData((struct Message *) pd, FALSE);
  481.   }
  482.  }
  483.  
  484.  /* Free directory lock */
  485.  UnLock(dirlock);
  486.  
  487.  return(rc);
  488. }
  489.  
  490. /* Free process data */
  491. void FreeProcessData(struct Message *msg, BOOL reply)
  492. {
  493.  struct ProcessData *pd = (struct ProcessData *) msg;
  494.  struct WBArg *wa       = pd->pd_WBStartup.sm_ArgList;
  495.  int i                  = pd->pd_WBStartup.sm_NumArgs;
  496.  
  497.  /* Scan array */
  498.  while (i--) {
  499.  
  500.   DEBUGLOG(kprintf("Free WBArg %s (0x%08lx)\n", wa->wa_Name, wa->wa_Lock);)
  501.  
  502.   /* Free directory lock */
  503.   UnLock(wa->wa_Lock);
  504.  
  505.   /* Free name buffer */
  506.   if (wa->wa_Name) FreeMemory(wa->wa_Name);
  507.  
  508.   /* Next entry */
  509.   wa++;
  510.  }
  511.  
  512.  /* Free tool window specificaton */
  513.  if (pd->pd_WBStartup.sm_ToolWindow)
  514.   FreeMemory(pd->pd_WBStartup.sm_ToolWindow);
  515.  
  516.  /* Free program segments */
  517.  if (pd->pd_WBStartup.sm_Segment) UnLoadSeg(pd->pd_WBStartup.sm_Segment);
  518.  
  519.  /* Free process data structure */
  520.  FreeMemory(pd);
  521. }
  522.