home *** CD-ROM | disk | FTP | other *** search
/ World of A1200 / World_Of_A1200.iso / programs / workbench / wbstart / wbstart-handler.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-27  |  11.7 KB  |  480 lines

  1. /*
  2.  * WBStart-Handler.c   V1.3
  3.  *
  4.  * Handler code
  5.  *
  6.  * (c) 1991-93 Stefan Becker
  7.  *
  8.  */
  9.  
  10. /* Handler includes */
  11. #include "WBStart.h"
  12.  
  13. /* System includes */
  14. #include <dos/dostags.h>
  15. #include <exec/memory.h>
  16. #include <workbench/icon.h>
  17. #include <workbench/workbench.h>
  18.  
  19. /* Prototypes */
  20. #include <clib/dos_protos.h>
  21. #include <clib/exec_protos.h>
  22. #include <clib/icon_protos.h>
  23. void _waitwbmsg(void);
  24.  
  25. /* Pragmas */
  26. #include <pragmas/dos_pragmas.h>
  27. #include <pragmas/exec_pragmas.h>
  28. #include <pragmas/icon_pragmas.h>
  29.  
  30. /* ANSI C includes */
  31. #include <stdlib.h>
  32. #include <string.h>
  33.  
  34. /* Defines */
  35. #define MINSTACKSIZE 4096
  36.  
  37. /* Structure for path lists */
  38. struct PathList {
  39.                  BPTR NextPath; /* Pointer to next PathList */
  40.                  BPTR PathLock; /* Lock on directory */
  41.                 };
  42.  
  43. /* Library bases */
  44. extern struct Library *SysBase, *DOSBase, *IconBase;
  45.  
  46. /* Global data */
  47. static struct PathList *LoadPath=NULL; /* Path for loading programs */
  48. static struct MsgPort *HandlerPort;    /* Handler message port */
  49. static ULONG wbactive=0;               /* Number of active WB processes */
  50.  
  51. /* Version string */
  52. static const char Version[]="$VER: WBStart-Handler 1.3 ("
  53.                              __COMMODORE_DATE__ ")";
  54.  
  55. /* Duplicate a string */
  56. static char *StrDup(char *old)
  57. {
  58.  char *new;
  59.  
  60.  /* Allocate memory and copy string */
  61.  if (new=AllocVec(strlen(old)+1,MEMF_PUBLIC))
  62.   strcpy(new,old);
  63.  return(new);
  64. }
  65.  
  66. /* Try to load a program, return pointer to segment and lock to home dir */
  67. static BPTR LoadSegPath(char *name, BPTR curdir, BPTR *homedir)
  68. {
  69.  BPTR segment;
  70.  struct PathList *pl;
  71.  
  72.  /* Load from current directory */
  73.  if (segment=NewLoadSeg(name,NULL))
  74.   /* Copy lock */
  75.   if (*homedir=DupLock(curdir))
  76.    return(segment);
  77.   else
  78.    return(NULL); /* Error */
  79.  
  80.  /* Load from path */
  81.  pl=LoadPath;
  82.  while (pl) {
  83.   /* Set new directory */
  84.   CurrentDir(pl->PathLock);
  85.  
  86.   /* Try to load program */
  87.   if (segment=NewLoadSeg(name,NULL)) {
  88.    /* Return to old directory */
  89.    CurrentDir(curdir);
  90.  
  91.    /* Copy lock */
  92.    if (*homedir=DupLock(pl->PathLock))
  93.     return(segment);
  94.    else
  95.     return(NULL); /* Error */
  96.   }
  97.  
  98.   /* Next path entry */
  99.   pl=BADDR(pl->NextPath);
  100.  }
  101.  
  102.  /* Load from "C:" */
  103.  {
  104.   BPTR lock;
  105.  
  106.   /* Get directory lock */
  107.   if (lock=Lock("C:",ACCESS_READ)) {
  108.    CurrentDir(lock);
  109.  
  110.    /* Try to load program */
  111.    if (segment=NewLoadSeg(name,NULL)) {
  112.     /* Return to old directory */
  113.     CurrentDir(curdir);
  114.  
  115.     /* Set lock */
  116.     *homedir=lock;
  117.     return(segment);
  118.    }
  119.  
  120.    /* Free lock */
  121.    UnLock(lock);
  122.   }
  123.  }
  124.  
  125.  /* Return to old directory */
  126.  CurrentDir(curdir);
  127.  
  128.  /* Load failed */
  129.  return(NULL);
  130. }
  131.  
  132. /* Start program as a WB process */
  133. static BOOL StartProgram(struct WBStartMsg *msg)
  134. {
  135.  struct WBStartup *wbs;
  136.  
  137.  /* Allocate memory for WBStartup */
  138.  if (wbs=AllocVec(sizeof(struct WBStartup)+
  139.                   sizeof(struct WBArg)*(msg->wbsm_NumArgs+2),
  140.                   MEMF_PUBLIC|MEMF_CLEAR)) {
  141.   BPTR olddir,homedir;
  142.   char *toolname=msg->wbsm_Name;
  143.   char *projectname=NULL;
  144.   ULONG stacksize=msg->wbsm_Stack;
  145.  
  146.   /* Go to tools current directory */
  147.   olddir=CurrentDir(msg->wbsm_DirLock);
  148.  
  149.   /* Check for project icon */
  150.   {
  151.    struct DiskObject *dobj;
  152.  
  153.    /* Get program icon */
  154.    if ((dobj=GetDiskObject(toolname)) &&
  155.        (dobj->do_Type==WBPROJECT)) {
  156.     /* It's a project icon, get the name & icon of the default tool */
  157.     projectname=toolname;
  158.     if (toolname=StrDup(dobj->do_DefaultTool)) {
  159.      /* Free old icon */
  160.      FreeDiskObject(dobj);
  161.  
  162.      /* Get new icon */
  163.      dobj=GetDiskObject(toolname);
  164.     }
  165.    }
  166.  
  167.    /* No error and tool icon? */
  168.    if (toolname && dobj && (dobj->do_Type==WBTOOL)) {
  169.     /* Get stack size from tool icon */
  170.     if (dobj->do_StackSize>stacksize) stacksize=dobj->do_StackSize;
  171.  
  172.     /* Get tool window description (Maybe obsolete???) */
  173.     if (dobj->do_ToolWindow) wbs->sm_ToolWindow=StrDup(dobj->do_ToolWindow);
  174.    }
  175.  
  176.    /* Free Disk object */
  177.    if (dobj) FreeDiskObject(dobj);
  178.   }
  179.  
  180.   /* No error and can we load the program? */
  181.   if (toolname &&
  182.       (wbs->sm_Segment=LoadSegPath(toolname,msg->wbsm_DirLock,&homedir))) {
  183.    /* Program loaded */
  184.    struct WBArg *wbas;
  185.    struct WBArg *wbad;
  186.  
  187.    /* Build WBStartup message */
  188.    /* wbs->sm_Message.mn_Node.ln_Type=NT_MESSAGE; PutMsg() does this for us! */
  189.    wbs->sm_Message.mn_ReplyPort=HandlerPort;
  190.    wbs->sm_Message.mn_Length=sizeof(struct WBStartup);
  191.    wbs->sm_NumArgs=msg->wbsm_NumArgs+1;
  192.    wbs->sm_ArgList=(struct WBArg *)(wbs+1); /* WBArgs follow after WBStartup */
  193.  
  194.    /* Initialize WBArg list pointers */
  195.    wbas=msg->wbsm_ArgList; /* Source */
  196.    wbad=wbs->sm_ArgList;   /* Destination */
  197.  
  198.    /* The first argument is the tool itself. a) Copy lock */
  199.    if (wbad->wa_Lock=DupLock(homedir)) {
  200.     int i;
  201.  
  202.     /* b) Copy name */
  203.     wbs->sm_NumArgs=1;
  204.     if (wbad->wa_Name=(BYTE *) StrDup(toolname)) {
  205.      /* If it is a project, then use project as second argument */
  206.      if (!projectname ||
  207.           (wbs->sm_NumArgs=2, wbad++,
  208.            (wbad->wa_Lock=DupLock(msg->wbsm_DirLock)) &&
  209.            (wbad->wa_Name=(BYTE *) StrDup(projectname)))) {
  210.       BOOL noerror=TRUE;
  211.  
  212.       /* Next destination argument */
  213.       wbad++;
  214.  
  215.       /* Copy WBArgs from message */
  216.       for (i=msg->wbsm_NumArgs; i; i--,wbas++)
  217.        /* Copy lock (skip arguments with invalid locks) */
  218.        if (wbad->wa_Lock=DupLock(wbas->wa_Lock)) {
  219.         /* Increment argument count */
  220.         wbs->sm_NumArgs++;
  221.  
  222.         /* Check & copy name */
  223.         if (!(wbas->wa_Name &&
  224.               (wbad->wa_Name=(BYTE *) StrDup(wbas->wa_Name)))) {
  225.          /* ERROR --> leave loop */
  226.          noerror=FALSE;
  227.          break;
  228.         }
  229.  
  230.         /* Next destination WBArg */
  231.         wbad++;
  232.        }
  233.  
  234.       /* No error? */
  235.       if (noerror) {
  236.        /* Make sure that the stack size is valid */
  237.        if (stacksize<MINSTACKSIZE) stacksize=MINSTACKSIZE;
  238.        stacksize=(stacksize+3)&(~3); /* Stack size must be a multiple of 4! */
  239.  
  240.        /* Create process */
  241.        Forbid(); /* We want to manipulate the process first! */
  242.        if (wbs->sm_Process=CreateProc(wbs->sm_ArgList->wa_Name,msg->wbsm_Prio,
  243.                                       wbs->sm_Segment,stacksize)) {
  244.         /* Set PROGDIR: *** ATTENTION: Don't try this at home, kids :-) *** */
  245.         {
  246.          struct Process *pr=(struct Process *) wbs->sm_Process->mp_SigTask;
  247.  
  248.          pr->pr_HomeDir=homedir;
  249.          pr->pr_WindowPtr=NULL;
  250.          pr->pr_ConsoleTask=NULL;
  251.         }
  252.         Permit(); /* Ready to rock'n'roll :-) */
  253.  
  254.         /* Send WBStartup message to new process */
  255.         PutMsg(wbs->sm_Process,(struct Message *) wbs);
  256.  
  257.         /* Free tool name */
  258.         if (projectname) FreeVec(toolname);
  259.  
  260.         /* Go back to old directory */
  261.         CurrentDir(olddir);
  262.  
  263.         /* Program successfully started! */
  264.         wbactive++;
  265.         return(TRUE);
  266.        } else
  267.         /* Couldn't create process */
  268.         Permit();
  269.       }
  270.      }
  271.     }
  272.  
  273.     /* Free WBArgs */
  274.     for (i=wbs->sm_NumArgs; i; i--, wbas++) {
  275.      /* Free lock */
  276.      UnLock(wbas->wa_Lock);
  277.  
  278.      /* Free name */
  279.      if (wbas->wa_Name) FreeVec(wbas->wa_Name);
  280.     }
  281.    }
  282.  
  283.    /* Free lock */
  284.    UnLock(homedir);
  285.  
  286.    /* Unload segment */
  287.    UnLoadSeg(wbs->sm_Segment);
  288.   }
  289.  
  290.   /* Free tool window description */
  291.   if (wbs->sm_ToolWindow) FreeVec(wbs->sm_ToolWindow);
  292.  
  293.   /* Free tool name */
  294.   if (projectname && toolname) FreeVec(toolname);
  295.  
  296.   /* Go back to old directory */
  297.   CurrentDir(olddir);
  298.   FreeVec(wbs);
  299.  }
  300.  
  301.  /* Call failed */
  302.  return(FALSE);
  303. }
  304.  
  305. /* Copy a path list */
  306. static BOOL CopyPathList(struct PathList **pla, struct PathList **plc,
  307.                          struct PathList *oldpl)
  308. {
  309.  struct PathList *pl1=oldpl,*pl2=*plc,*pl3=NULL;
  310.  
  311.  while (pl1) {
  312.   /* Get memory for path list entry */
  313.   if (!(pl3 || (pl3=AllocVec(sizeof(struct PathList),MEMF_PUBLIC|MEMF_CLEAR))))
  314.    return(FALSE); /* No more memory... */
  315.  
  316.   /* Copy path entry */
  317.   if (pl3->PathLock=DupLock(pl1->PathLock)) {
  318.    /* Copy successful, append new entry to list. Head of list? */
  319.    if (*pla)
  320.     pl2->NextPath=MKBADDR(pl3); /* No, append it to list */
  321.    else
  322.     *pla=pl3;                   /* Yes, set list anchor */
  323.  
  324.    /* Save pointer */
  325.    pl2=pl3;
  326.  
  327.    /* Invalidate pointer, next time a new PathList will be allocated */
  328.    pl3=NULL;
  329.   }
  330.  
  331.   /* Get next path list entry */
  332.   pl1=BADDR(pl1->NextPath);
  333.  }
  334.  
  335.  /* Free memory */
  336.  if (pl3) FreeVec(pl3);
  337.  
  338.  /* All OK */
  339.  *plc=pl2; /* Save pointer to new end of list */
  340.  return(TRUE);
  341. }
  342.  
  343. /* Free a path list */
  344. static void FreePathList(struct PathList *pla)
  345. {
  346.  /* Check for NULL */
  347.  if (pla) {
  348.   struct PathList *pl1=pla,*pl2;
  349.  
  350.   /* Scan list */
  351.   do {
  352.    /* Get pointer to next entry */
  353.    pl2=BADDR(pl1->NextPath);
  354.  
  355.    /* Free entry */
  356.    UnLock(pl1->PathLock);
  357.    FreeVec(pl1);
  358.   } while (pl1=pl2);
  359.  }
  360. }
  361.  
  362. __stkargs void _main(int arglen, char *argptr)
  363. {
  364.  struct PathList *oldpath;
  365.  struct PathList *newpath=NULL;
  366.  struct CommandLineInterface *mycli;
  367.  
  368.  /* Check OS version */
  369.  if (SysBase->lib_Version<37) return;
  370.  
  371.  /* CLI Process? */
  372.  if (mycli=Cli()) {
  373.   /* Yes, try to copy path from Workbench process */
  374.   struct Process *wbproc=(struct Process *) FindTask("Workbench");
  375.  
  376.   /* Get pointer to our old path */
  377.   oldpath=(struct PathList *) BADDR(mycli->cli_CommandDir);
  378.   LoadPath=oldpath;
  379.  
  380.   /* Task found? Make sure it IS a process */
  381.   if (wbproc && (wbproc->pr_Task.tc_Node.ln_Type==NT_PROCESS)) {
  382.    /* It is a process */
  383.    struct CommandLineInterface *wbcli=BADDR(wbproc->pr_CLI);
  384.  
  385.    /* Make sure it IS a CLI process */
  386.    if (wbcli) {
  387.     struct PathList *dummy;
  388.  
  389.     /* Build new path: a) our old path, b) WB path */
  390.     if (CopyPathList(&newpath,&dummy,oldpath) &&
  391.         CopyPathList(&newpath,&dummy,
  392.                      (struct PathList *) BADDR(wbcli->cli_CommandDir))) {
  393.      /* Path successfully copied, install it in our process */
  394.      mycli->cli_CommandDir=MKBADDR(newpath);
  395.      LoadPath=newpath;
  396.     } else {
  397.      /* Error, free path list */
  398.      FreePathList(newpath);
  399.      return;
  400.     }
  401.    }
  402.   }
  403.  }
  404.  
  405.  /* Create message port */
  406.  if (HandlerPort=CreateMsgPort()) {
  407.   ULONG wsig,psig;
  408.   BOOL notend=TRUE;
  409.  
  410.   /* Make port public */
  411.   HandlerPort->mp_Node.ln_Pri=0;
  412.   HandlerPort->mp_Node.ln_Name=WBS_PORTNAME;
  413.   AddPort(HandlerPort);
  414.  
  415.   /* Init signal masks */
  416.   psig=1L<<HandlerPort->mp_SigBit;
  417.   wsig=psig|SIGBREAKF_CTRL_C;
  418.  
  419.   /* Main event loop */
  420.   while (notend) {
  421.    ULONG gotsigs;
  422.  
  423.    /* Wait on event */
  424.    gotsigs=Wait(wsig);
  425.  
  426.    /* Got a message at our port? */
  427.    if (gotsigs&psig) {
  428.     struct WBStartMsg *msg;
  429.  
  430.     /* Process all messages */
  431.     while (msg=(struct WBStartMsg *) GetMsg(HandlerPort))
  432.      /* Replied message? */
  433.      if (msg->wbsm_Msg.mn_Node.ln_Type==NT_REPLYMSG) {
  434.       /* This is the death message from a tool we started some time ago */
  435.       struct WBStartup *wbs=(struct WBStartup *) msg;
  436.       struct WBArg *wa=wbs->sm_ArgList;
  437.       int i=wbs->sm_NumArgs;
  438.  
  439.       while (i--) {
  440.        UnLock(wa->wa_Lock);      /* Free WB argument */
  441.        if (wa->wa_Name) FreeVec(wa->wa_Name);
  442.        wa++;
  443.       }
  444.  
  445.       if (wbs->sm_ToolWindow)     /* Free tool window specification */
  446.        FreeVec(wbs->sm_ToolWindow);
  447.  
  448.       UnLoadSeg(wbs->sm_Segment); /* Unload code */
  449.       FreeVec(wbs);               /* Free WBStartup */
  450.       wbactive--;                 /* One tool closed down */
  451.      } else {
  452.       /* We got a new message. Handle and reply it. */
  453.       msg->wbsm_Stack=StartProgram(msg);
  454.       ReplyMsg((struct Message *) msg);
  455.      }
  456.    }
  457.  
  458.    /* Received a CTRL-C? */
  459.    if ((gotsigs&SIGBREAKF_CTRL_C) && !wbactive) notend=FALSE;
  460.   }
  461.  
  462.   /* Exit handler */
  463.   RemPort(HandlerPort);
  464.   DeleteMsgPort(HandlerPort);
  465.  }
  466.  
  467.  /* Free path list */
  468.  if (newpath) {
  469.   /* Reinstall old path first */
  470.   mycli->cli_CommandDir=MKBADDR(oldpath);
  471.   FreePathList(newpath);
  472.  }
  473.  
  474.  /* Handler finished */
  475.  return;
  476.  
  477.  /* NOT REACHED */
  478.  _waitwbmsg();    /* Force linking of WB startup code */
  479. }
  480.