home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 August - Disc 3 / chip_20018103_hu.iso / amiga / chiputil / additem.lha / AddItem / Source / AddItemV2.2.c < prev   
Encoding:
C/C++ Source or Header  |  2001-06-24  |  30.0 KB  |  1,024 lines

  1. /*
  2.     AddItem
  3.  
  4.     This program was written to add easily some items to the workbench tool menu which can be used to
  5.     cause an action.
  6.  
  7.     You can enter in the ToolTypes of AddItem's icon the
  8.     ITEM TEXT
  9.     COMMAND TEXT
  10.     OUTPUT TEXT .
  11.     Those entries must be separated by the comma, e.g.
  12.     NoTurbo,C:CPU NOCACHE,NIL:
  13.      where "NoTurbo"    is the item-text (visible)
  14.      "C:CPU NOCACHE"    is the command line (same as in Shell)
  15.      "NIL:"                is the stream where the outputs of the
  16.                         command should be displayed .
  17.  Please note:
  18.     The  command-text  itself  should be set in quotes when it contains commas, otherwise not. If the
  19.     argument  which  is  supplied  for  the command contains blanks (" "), the argument itself has to
  20.     stand within double quotes, e.g. C:Type "%s" .
  21.     Please note also:
  22.     Blanks  are  not  skipped! Do not use them at all in front of a CMD-text or Output-text, although
  23.     the DOS will handle it correctly!
  24.  
  25.  ADDITEM=<,,> is the keyword for the tooltypes. Other keywords
  26.  are ignored by "AddItem".
  27.  
  28. #    A D D E D    F O R    V E R S I O N    2 . 0    O F   A D D I T E M
  29. #
  30. #    For the now comming part you can thank Marc Berson.
  31. #    It was his idea.
  32. #
  33. #    If  the  output  text is a number (e.g. 4096) the whole entries are interpreted as an argument to
  34. #    force  the  command  part NOT to execute as a single command, instead it is forced to a backgound
  35. #    process.
  36. #
  37. #    This  new  background  process  will  get  from  AddItem  a message which is likely the same as a
  38. #    workbench  message. Thus its seems for the application that it was started from Workbench and not
  39. #    from CLI! The new keyword to do:
  40. #
  41. #    ADDITEM=itemname,objectname,stacksize
  42. #
  43. #    ADDITEM=DOpus,Work:Tools/Opus/DirectoryOpus,20480
  44. #
  45. #    which means:
  46. #
  47. #    DOpus - appearing  string  of  the item (visible)
  48. #    Work:Tools/Opus/DirectoryOpus - the full  application name
  49. #    20480 - stacksize for the application
  50. #
  51. #    Please note:
  52. #    The   full  application  name  ╖must  not╖  conatian  double  quotes,  e.g.
  53. #    ADDITEM=IntelliFont,"Worbench/System/IntelliFont",4096 - W R O N G !!!
  54. #
  55. #    use   instead:   ADDITEM=IntelliFont,Worbench/System/IntelliFont,4096  even
  56. #    when the full application name contains blanks
  57. #
  58. #    ADDITEM=Replayer,Work:Tools/This  Player,4096  -  O  K !!! where 'This Player' is the name of the
  59. #    object module. Note also: Arguments '%s' for the application aren't allowed (yet).
  60. #
  61. #    The default I currently use:
  62. #
  63. #    DONOTWAIT
  64. #    ADDITEM=NewShell,NewShell CON:///130/AmigaShell/AUTO/CLOSE,NIL:
  65. #    ADDITEM=Turn Caches On,C:Cpu CACHE,NIL:
  66. #    ADDITEM=Turn Caches Off,C:Cpu NOCACHE:,NIL:
  67. #    ADDITEM=Lock <> On,C:Lock "%s" ON,NIL:
  68. #    ADDITEM=Lock <> Off,C:Lock "%s" OFF,NIL:
  69. #    ADDITEM=View <>,Run >NIL: <NIL: Work:Tools/Viewer "%s",NIL:
  70. #    ADDITEM=PPaint,Work-II:DTP/PPaint/PPaint,4096
  71. #
  72. #    The  %s  specifies the argument passed by workbench. This argument is the current volume, current
  73. #    drawer  and  current  file  you  have got selected via the mouse. Clearly spoken: It is (are) the
  74. #    active icon(s)!
  75.  
  76. #    Version 2.2 of AddItems allows now to pass an argument to the background process.
  77.  
  78.     To  quit  AddItem  and  thus  remove the items made by it in the tool menu you can send AddItem a
  79.     CTRL-C  (BREAK)  signal,  or  easily, start AddItem again. When started a second time, AddItem(2)
  80.     looks  for  a  created  port  named  as "AddItem's WBench AppPort", if this port is found it will
  81.     signal  the  task  who  is  the  owner of this port a signal (CTRL-C) and thus remove the program
  82.     AddItem(1).
  83.  
  84.     This program was written by Joerg van de Loo
  85.                                 Hoevel 15
  86.                                 47559 Kranenburg
  87.                                 Germany
  88.  
  89. It was tested on:
  90.     Amiga 1200, 68030 (EC)    40 MHz, 2MB CHIP,  8 MB FAST, OS3.0, AGA
  91.     Amiga 4000, 68040        25 MHz, 2MB CHIP,  4 MB FAST, OS3.0, AGA
  92.     Amiga 4000, 68040        25 MHz, 2MB CHIP, 16 MB FAST, OS3.0, Picasso96/CV3D
  93.     Draco        68060        66 MHz, 4MB VRAM, 64 MB FAST, OS3.1, CyberGraphX/Altais
  94.  
  95. !!! Enforcer proofed !!!
  96.  
  97.     Can be linked without "amiga.lib"!
  98.  
  99.     This source-code is Amiga-ROM« specific!
  100.  
  101.     It's  placed  in  the public domain pool as public domain - thus everybody is able to modify this
  102.     program.
  103.  
  104.     Because  I don't ask for something, you can't ask for anything. Don't blame me when this material
  105.     bombs your Amiga. All risk is at your own.
  106.  
  107. */
  108.  
  109. char VersionString[]    = "$VER: AddItem 2.21 (13-Jun-01) Written by ONIX";
  110. char AIName[]            = "AddItem";
  111. char PortName[]            = "AddItem's WBench AppPort";
  112. char SyntaxTxt[]        = "╗Used to add items into Workbench's Tools Menu.½\n" \
  113.                           "Use within desk-top 'Icon-Information' and enter for every item:\n" \
  114.                           " ADDITEM=<itemtext>,<doscommand>,<output-stream or stacksize>\n";
  115.  
  116. #include    <exec/types.h>
  117. #include    <exec/execbase.h>
  118. #include    <exec/ports.h>
  119. #include    <exec/libraries.h>
  120. #include    <exec/memory.h>
  121. #include    <dos/dosextens.h>
  122. #include    <workbench/workbench.h>
  123. #include    <workbench/icon.h>
  124. #include    <workbench/startup.h>
  125. #include    <intuition/intuition.h>
  126.  
  127. #include    <pragma/exec_lib.h>
  128. #include    <pragma/dos_lib.h>
  129. #include    <pragma/intuition_lib.h>
  130. #include    <pragma/icon_lib.h>
  131. #include    <pragma/wb_lib.h>
  132.  
  133. /* Prototypes please - I don't like to crash my system... */
  134. #include    <stdio.h>
  135. #include    <linkerfunc.h>
  136. #include    <clib/exec_protos.h>
  137. #include    <clib/dos_protos.h>
  138. #include    <clib/intuition_protos.h>
  139. #include    <clib/icon_protos.h>
  140. #include    <clib/wb_protos.h>
  141.  
  142.  
  143. /* -----------------------------------------------------------------------
  144.     If compiled with Maxon's C++, we have to make the WBenchMsg available!
  145. */
  146. #if defined(__MAXON__) || defined (__STORM__)
  147.  
  148. struct WBStartup *WBenchMsg = NULL;                /* Variable */
  149. extern "C" void wbparse( struct WBStartup *);    /* Prototype */
  150. extern "C" void wbmain( struct WBStartup *ws)    /* This is called if we're running from WB */
  151. {
  152.     WBenchMsg = ws; /* Remember message */
  153.  
  154.     #if defined(__MAXON__)
  155.     wbparse( ws);    /* Parse WBench arguments (argv[0....])*/
  156.     #endif
  157. }
  158.  
  159. #endif
  160. /* ----------------------------------------------------------------------- */
  161.  
  162. extern struct ExecBase     *SysBase;
  163. struct Process             *ThisTask;
  164. struct IntuitionBase     *IntuitionBase;
  165. struct Library             *WorkbenchBase;
  166. struct Library             *IconBase;
  167. struct MsgPort             *MsgPort, *Port, *WBPort = NULL;
  168. extern struct WBStartup  *WBenchMsg;
  169. struct DiskObject         *PrgIcon;
  170. char                    **ToolTypes;
  171. UBYTE                     *ToolText, *ItemTxt, *CMDTxt, *OTxt;
  172. ULONG                      SignalSet, WBSignal, LaunchCnt = NULL, ILen, CMDLen, OLen;
  173. struct stuff             *ArrayPtr;
  174. APTR                      DummyPtr, CurrItem;
  175. struct Remember            **RememberKey = NULL, *ItemList = NULL, *NextItem = NULL;
  176. struct AppMenuItem         *WBMadeItem;
  177. struct AppMessage         *AMsg, *PMsg;
  178.  
  179. struct EasyStruct Say =
  180. {
  181.     sizeof( EasyStruct),
  182.     NULL,
  183.     AIName,
  184.     NULL,
  185.     " Ok "
  186. };
  187.  
  188. struct stuff
  189. {
  190.     APTR    TextLinePtr;
  191.     APTR    ItemTextPtr;
  192.     APTR    CMDTextPtr;
  193.     APTR    OutputTextPtr;
  194. };
  195.  
  196. struct PseudoMsg {
  197.     struct WBStartup pm_Startup;
  198.     BPTR                 pm_Lock;
  199.     char                *pm_Name;
  200.     BPTR                 pm_ArgLock;
  201.     char                *pm_ArgName;
  202.     char                 pm_Dir[256];
  203.     char                 pm_FileName[108];
  204.     char                 pm_ArgStrName[108];
  205. };
  206.  
  207.  
  208. /*    Own  made  ItemList (Intuition Remember Variable -> Memory) holds the pointer to this list, which
  209.     in fact is only a pointer to the added Item! */
  210.  
  211. struct ilist
  212. {                                            /*    ------------------------ */
  213.     struct AppMenuItem *ilistItem;            /* | Intuition Remember Var |          -------- */
  214.     ULONG    exter;    /* Currently not used        ------------------------    ---> | Memory |          ---------     */
  215. };                                                                            /*     --------    ---> | AppItem | */
  216.                                                                             /*                      ---------  */
  217.  
  218. /* ######################################## */
  219. struct localtable
  220. {
  221.     void *bg;
  222.     int size;
  223.     BPTR o;
  224.     char *bufptr;
  225. };
  226.  
  227. void funny_code( register __a0 char *d, register __a1 char *d1, register __a2 char *d2, register __a3 volatile struct localtable *lt, register __d0 volatile char c, register __d1 int *d3, register __d2 int *d4)
  228. {
  229.     #ifdef __MAXON__
  230.     GetBaseReg();
  231.     #else
  232.     geta4();
  233.     #endif
  234.  
  235.     if (lt->size < 78)
  236.     {
  237.         lt->bufptr[lt->size] = c;
  238.         lt->bufptr[lt->size + 1] = 0;
  239.         lt->size ++;
  240.     }
  241.     else
  242.     {
  243.         if (lt->bufptr[ lt->size - 1] != 0)
  244.             Write( lt->o, lt->bufptr, lt->size );
  245.                 else
  246.             Write( lt->o, lt->bufptr, lt->size - 1 );
  247.         lt->bufptr[0] = c;
  248.         lt->bufptr[1] = 0;
  249.         lt->size = 1;
  250.     }
  251.  
  252. }
  253.  
  254. #define FUNC (void (*)()) &funny_code    /* Code will use: lea funny_code(a4),a2 */
  255.  
  256. void printfNR( char *s, ...)
  257. {
  258.     char buf[80], *a;
  259.     struct localtable lt;
  260.  
  261.     lt.bg = 0;                // Drop value that the register a4 currently holds!
  262.     lt.size = 0;            // No characters stored till now.
  263.     lt.o = Output();        // Result is printed to <whatsoever>
  264.     lt.bufptr = buf;        // Address local buffer for characters
  265.  
  266.     if (lt.o)
  267.     {
  268.         (char *) a = (char *) &s;    // Address format string on stack
  269.         a += 4;                        // Address 1st additional argument
  270.         RawDoFmt( s, a, FUNC, ((APTR) <) );
  271.         if (lt.size)
  272.             Write( lt.o, lt.bufptr, lt.size - 1 );
  273.     }
  274. }
  275.  
  276. static unsigned int strlenNR( register const unsigned char *str)
  277. {
  278.     register unsigned int i = 0;
  279.  
  280.     while (*str++)
  281.         i++;
  282.     return i;
  283. }
  284.  
  285. static void strncpyNR( register unsigned char *d, register const unsigned char *s, register unsigned int i)
  286. {
  287.     while (i)
  288.     {
  289.         *d++ = *s++;
  290.         i--;
  291.     }
  292.     *d = 0;
  293. }
  294.  
  295. static void strcpyNR( register unsigned char *d, register const unsigned char *s)
  296. {
  297.     while (*s)
  298.         *d++ = *s++;
  299.     *d = 0;
  300. }
  301.  
  302. static unsigned int strcmpNR( register unsigned char *d, register const unsigned char *s)
  303. {
  304.     while (*s)
  305.     {
  306.         if (*d++ != *s++)
  307.             break;
  308.     }
  309.  
  310.     if ( !*s && !*d)
  311.         return FALSE;
  312.             else
  313.         return TRUE;
  314. }
  315.  
  316. static unsigned int strncmpNR( register unsigned char *d, register const unsigned char *s, register unsigned int i)
  317. {
  318.     while (i)
  319.     {
  320.         if (*d++ != *s++)
  321.             break;
  322.         i--;
  323.     }
  324.  
  325.     return i;
  326. }
  327.  
  328. static char *strchrNR( char *s, char c)
  329. {
  330.     while (*s)
  331.     {
  332.         if (*s++ == c)
  333.             break;
  334.     }
  335.  
  336.     if (s[-1] == c)
  337.         return s - 1;
  338.             else
  339.         return 0;
  340. }
  341.  
  342. /* ######################################## */
  343. void CloseThem( void)
  344. {
  345.     if (ItemList)
  346.     {
  347.         NextItem = (struct Remember *) ItemList;    /* Intuition made list... */
  348.  
  349.         while (1)
  350.         {
  351.              CurrItem = NextItem -> Memory;    /*    Pointer to memory which holds
  352.                                                 the address of the created Item */
  353.              RemoveAppMenuItem( ( (struct ilist *) CurrItem) -> ilistItem);
  354.              NextItem = (struct Remember *) NextItem -> NextRemember;
  355.              if ( !(NextItem) )
  356.                 break;
  357.         }
  358.             
  359.         FreeRemember( &ItemList, TRUE);
  360.     }
  361.  
  362.     if (RememberKey)
  363.         FreeRemember( (struct Remember **) &RememberKey, TRUE);
  364.  
  365.     if (PrgIcon)
  366.         FreeDiskObject( PrgIcon);
  367.  
  368.     if (MsgPort)    /* Did we create a MessagePort ? */
  369.     {
  370.         Port = (struct MsgPort *) FindPort( PortName);    /* Find public port */
  371.         if ( Port == MsgPort)                            /* Public port and our private port the same ? */
  372.             RemPort( MsgPort);                            /* If so, remove public port from list of ports */
  373.         DeleteMsgPort( MsgPort);                        /* Free our private port */
  374.     }
  375.  
  376.     if (IconBase)
  377.         CloseLibrary( IconBase);
  378.  
  379.     if (WorkbenchBase)
  380.         CloseLibrary( WorkbenchBase);
  381.  
  382.     if (IntuitionBase)
  383.         CloseLibrary( (struct Library *) IntuitionBase);
  384. }
  385.  
  386. /* ######################################## */
  387. void RemMessage( struct PseudoMsg *msg)
  388. {
  389.     LaunchCnt --;
  390.     UnLock( msg -> pm_Lock);
  391.     UnLoadSeg( msg -> pm_Startup . sm_Segment);
  392.  
  393.     if (msg -> pm_ArgLock != -1)
  394.         UnLock( msg->pm_ArgLock);
  395.  
  396.     FreeMem( msg, sizeof (PseudoMsg) );
  397.  
  398.     if ( !( LaunchCnt))
  399.     {
  400.         DeleteMsgPort( WBPort);
  401.         WBPort = NULL;
  402.     }
  403. }
  404.  
  405. /* ######################################## */
  406. void tell( STRPTR Txt)
  407. {
  408.     if (IntuitionBase)
  409.     {
  410.         Say.es_TextFormat = Txt;
  411.         EasyRequestArgs( NULL, &Say, NULL, NULL);
  412.     }
  413.  
  414.     printfNR("%s: %s\n", AIName, Txt);
  415. }
  416.  
  417. /* ######################################## */
  418. void closeall( void)
  419. {
  420.     struct Message *msg;
  421.  
  422.     if ( !(WBPort) ) /* No pseudo WBench port ? */
  423.     {
  424.         CloseThem();
  425.         exit(0);
  426.     }
  427.     else
  428.     {
  429.         tell(    "Cannot terminate yet completely - there\n"
  430.                 "are still some \"launched\" programs.\n"
  431.                 "Don't forget to terminate them later.");
  432.  
  433.          /* Free the stuff we don't need anymore */
  434.         CloseThem();
  435.          /* ... and wait for all processes we created and which are still running */
  436.         while ( LaunchCnt)
  437.         {
  438.             WaitPort( WBPort);
  439.             msg = (struct Message *) GetMsg( WBPort);
  440.             if (msg)
  441.                 RemMessage( (struct PseudoMsg *) msg);
  442.         }
  443.  
  444.          exit(0);
  445.     }
  446. }
  447.  
  448. /* ######################################## */
  449. void bailoutold( ULONG err, STRPTR errTxt)
  450. {
  451.     printfNR("%s missed: %s\n", AIName, errTxt);
  452.     ThisTask = (struct Process *) FindTask( NULL);
  453.     ThisTask -> pr_Result2 = err;
  454.     exit( err);
  455. }
  456.  
  457. /* ######################################## */
  458. void bailout( ULONG err, STRPTR errTxt)
  459. {
  460.     if (IntuitionBase)
  461.     {
  462.         Say.es_TextFormat = errTxt;
  463.         EasyRequestArgs( NULL, &Say, NULL, NULL);
  464.     }
  465.  
  466.     printfNR("%s missed: %s\n", AIName, errTxt);
  467.     CloseThem();
  468.     ThisTask = (struct Process *) FindTask( NULL);
  469.     ThisTask -> pr_Result2 = err;
  470.     exit( err);
  471. }
  472.  
  473. /* ######################################## */
  474. void FreeCmdStuff(APTR memoryBlock, BPTR output)
  475. {
  476.     if (memoryBlock)
  477.         FreeMem( memoryBlock, 1024);
  478.     if (output)
  479.         Close( output);
  480. }
  481.  
  482.  
  483. /* ######################################## */
  484. char * GetStrName( struct stuff *array)
  485. {
  486.     char *nm;
  487.     ULONG len;
  488.  
  489.     nm = array -> CMDTextPtr;
  490.     len = strlenNR( nm);
  491.     len -= 1;
  492.     nm = nm + len;
  493.  
  494.     while ( len)
  495.     {
  496.         if (nm[-1] == '/')
  497.             break;
  498.         if (nm[-1] == ':')
  499.             break;
  500.         len -= 1;
  501.         nm --;
  502.     }
  503.  
  504.     return nm;
  505. }
  506.  
  507. /* ######################################## */
  508. void RHook( register __d0 char c, register __a3 UBYTE *buf)
  509. {
  510.     *buf++ = c;    /* move.b d0,(a3)+ */
  511. }                /* rts */
  512.  
  513. /* ######################################## */
  514. /*    Format CMD-txt with argument,
  515.     Lock "%s" On -> Lock "Workbench:" On */
  516.  
  517. void FormatStr( struct stuff *stuff, APTR fmt, UBYTE *ResultStr)
  518. {
  519.     RawDoFmt( stuff -> CMDTextPtr, fmt, (APTR) &RHook, ResultStr)
  520. }
  521.  
  522.  
  523. /* ######################################## */
  524. #ifndef MTYPE_APPMENUITEM
  525. #define MTYPE_APPMENUITEM AMTYPE_APPMENUITEM
  526. #endif
  527.  
  528. void CallFunc( struct AppMessage *appmsg)
  529. {
  530.     struct  stuff *array;    /* <- the things we remembered in the user-data field... */
  531.     BPTR    output = NULL, OldDir = NULL;
  532.     UBYTE  *memblock = NULL, *ExecuteStr;
  533.     ULONG    dummy;
  534.     LONG    numArgs;
  535.     APTR  **argLock, **argName;
  536.     ULONG    stackSize = NULL;
  537.     BPTR    lockSave = NULL;
  538.     struct MsgPort *procPort = NULL; 
  539.     STRPTR    procName;
  540.  
  541.     if (appmsg == NULL)
  542.         return;
  543.     if (appmsg -> am_Type != MTYPE_APPMENUITEM)
  544.         return;
  545.  
  546.     /*    Lets  first  check  if  the  output-text  is  a  value,  if  it is, treat argument (value) as
  547.         indicator for a workbench start. */
  548.  
  549.  
  550.     StrToLong( ((struct stuff *) appmsg -> am_UserData) -> OutputTextPtr, (LONG *) &stackSize);
  551.     if (!stackSize)
  552.     {
  553.          /* Normal DOS-execute stuff. We need a buffer of 1KB... - for:
  554.          -----------------------------
  555.          | Volume's/directory's name | 256 bytes
  556.          -----------------------------
  557.          | Filename                     | 256 bytes
  558.          -----------------------------
  559.          | Merged command-string     |
  560.          | with those both strings     | 512 bytes = string to execute!
  561.          -----------------------------
  562.         */
  563.         if ( (memblock = (APTR) AllocMem( 1024, MEMF_CLEAR) ))
  564.         {
  565.          /* The argument submitted to us is merged with the command-string, this
  566.             is the buffer for it, 512 Bytes - hopefully enought... */
  567.             ExecuteStr = memblock + 512;    /* Room (512 bytes) behind 512 bytes for name */
  568.  
  569.             array = (struct stuff *) appmsg -> am_UserData;        /* Get array of pointer-table... */
  570.  
  571.             if ( (output = Open( array -> OutputTextPtr, MODE_NEWFILE) ));    /* Open specified output */
  572.             {
  573.                 numArgs = appmsg -> am_NumArgs;
  574.                 argLock = (APTR) &(appmsg -> am_ArgList -> wa_Lock);
  575.                 argName = (APTR) &(appmsg -> am_ArgList -> wa_Name);
  576.  
  577.                 while (1)
  578.                 {
  579.                     OldDir = NULL;    /*    Indicates staying on home-lock - there were we
  580.                                         started from */
  581.  
  582.                     strcpyNR( memblock, "SYS:");    /* Default when nothing is picked... */
  583.                     memblock[4] = NULL;                /* May remove - only for savety... */
  584.  
  585.                     if (numArgs)                    /* Any argument ? */
  586.                     {
  587.                         if (argLock[0])                /* The volume/directory name */
  588.                         {
  589.                             /*    Get volume's/directory's name, store it into first 256 bytes
  590.                                 of buffer */
  591.                             NameFromLock( (BPTR) argLock[0], memblock, 255L);
  592.                             OldDir = CurrentDir( (BPTR) argLock[0]);    /* Change also directory... */
  593.                         }
  594.  
  595.                         dummy = strlenNR( memblock);    /* Length of name */
  596.                         dummy -= 1;    /*    minus 1 so that memblock[dummy] points to the last
  597.                                         valid char of string */
  598.                         if ( memblock[dummy] != ':' && memblock[dummy] != '/')
  599.                         {    
  600.                             dummy += 1;        /* Strlength plus 1 */
  601.                             memblock[dummy] = '/';    /* Add this char at end of string */
  602.                         }
  603.                         /*    Copy the name of the file right at the end of the
  604.                             volume's/diretory's name... */
  605.  
  606.                         if (argName[0])        /* Name of file set? */
  607.                             strncpyNR( &memblock[dummy + 1], (char *) argName[0], 255L);
  608.  
  609. /*                        printfNR("Name of object: %s\n", memblock);    <- can be used for debugging... */
  610.                     }
  611.  
  612.                     dummy = (ULONG) memblock;    /* dummy is used as fmt-array for RawDoFmt() ! */
  613.  
  614.                     FormatStr( array, &dummy, ExecuteStr);    /* Format CMD-text... */
  615.  
  616.                     /*    I do not test here if the command was executed because against
  617.                         the documentation Execute() does ever return BOOL-ok on my machine! */
  618.                     Execute( ExecuteStr, NULL, output);        /* Execute command... */
  619.                     dummy = IoErr();                        /* Was function Execute() succesful ? */
  620.                     if (dummy)
  621.                         tell("Cannot execute command or\n"
  622.                              "command returned an error!");
  623.  
  624.                     if (OldDir)
  625.                         CurrentDir( OldDir);    /*    If we don't restore the original lock
  626.                                                     the DOS will refer to an invalid lock
  627.                                                     -- hello Guru! */
  628.  
  629.                     /*    Lets  say  you  want to open a NewShell. In this case you don't need any args
  630.                         (%s).  But  it  might be that some icons are picked while you choose NewShell
  631.                         from  the  menu.  Because some icons are picked, numArg is taller NULL - this
  632.                         means  as  much icons are selected as many 'NewShells' are created. To avaiod
  633.                         this  I  check  if  the  command  string  is  as  long as the string which is
  634.                         executed,  if  it is, there can't be (?!?!) an arg (%s) thus we can leave the
  635.                         routine here - only once executed.... */
  636.  
  637.                     if ( (strlenNR( ExecuteStr) == strlenNR( array -> CMDTextPtr)) )
  638.                         break;
  639.  
  640.                     argLock += 2;    /* Pointer to next lock */
  641.                     argName += 2;    /* Pointer to next name */
  642.                     numArgs -= 1;    /* One less to work out */
  643.                     if (numArgs <= NULL)
  644.                         break;    /* If zero or -1 break */
  645.                 }
  646.  
  647.                 FreeCmdStuff( memblock, output);
  648.                 return    /* Back */
  649.             }
  650.  
  651.             tell("Error while opening output terminal respectively file");
  652.             FreeCmdStuff( memblock, output);
  653.             return;
  654.         }
  655.  
  656.         tell("Cannot allocate buffer for application-command!");
  657.         return;
  658.     }
  659.     else
  660.     {
  661.  
  662.     /* -----------------    Up from here the stuff to emulate a workbench start ----------- */
  663.  
  664.         if ( (memblock = (APTR) AllocMem( sizeof( PseudoMsg), MEMF_CLEAR) ))
  665.         {
  666.             /* If the WBench Pseudo port doesn't exists, create it! */
  667.             if ( !( WBPort) )
  668.                 WBPort = (struct MsgPort *) CreateMsgPort();
  669.             if ( WBPort)
  670.             {
  671.                 /* Get out of array the private pointer table for the item */
  672.                 array = (struct stuff *) appmsg -> am_UserData;
  673.  
  674.                 /* Extract out of full filename (which includes the pathname) the object (PRG) name */
  675.                 procName = (STRPTR) GetStrName( array);
  676.  
  677.                 /* Get length of drawer and path part of filename */
  678.                 dummy = strlenNR(procName);
  679.                 dummy = strlenNR( array -> CMDTextPtr) - dummy;
  680.  
  681.                 /* Copy drawer and path part to private buffer (e.g. "SYS:SYSTEM/") */
  682.                 strncpyNR( ((struct PseudoMsg *) memblock) -> pm_Dir, array -> CMDTextPtr, dummy);
  683.  
  684.                 /* Lock the drawer and path (directory) */
  685.                 lockSave = Lock( ((struct PseudoMsg *) memblock) -> pm_Dir, ACCESS_READ);
  686.                 if (lockSave)
  687.                 {
  688.                     /* Store lock into variable which can be reach via "wa_Lock" from the application */
  689.                     ((struct PseudoMsg *) memblock) -> pm_Lock = lockSave;
  690.                     /* Change also the directory */
  691.                     OldDir = CurrentDir( lockSave);
  692.                 }
  693.  
  694.                 /* Copy PRG-name into private buffer which can the application reach via "wa_Name" */
  695.                 strcpyNR( &((struct PseudoMsg *) memblock) -> pm_FileName[0], procName );
  696.                 (APTR) ((struct PseudoMsg *) memblock) -> pm_Name = & ((struct PseudoMsg *) memblock) -> pm_FileName;
  697.      
  698.                 /*    Load the object file and store the "Segments" of it in the messsage - so that
  699.                     the application can examine it for its own use and we to unload the prg */
  700.                 ((struct PseudoMsg *) memblock) -> pm_Startup . sm_Segment = LoadSeg( procName);
  701.  
  702.                 /* Successfully loaded in? */
  703.                 if ( ((struct PseudoMsg *) memblock) -> pm_Startup . sm_Segment)
  704.                 {
  705.                     Forbid();
  706.                     /* Create a process via function "CreateProc()".
  707.                     Remember returned MsgPort of this new created process. */
  708.                     procPort =    (struct MsgPort *) CreateProc( procName, 0,
  709.                                 ((struct PseudoMsg *) memblock) -> pm_Startup . sm_Segment,
  710.                                 stackSize);
  711.                     /* Process created? */
  712.                     if (procPort)
  713.                     {
  714.                         /* Setup message with new created process' MsgPort */
  715.                         ((struct PseudoMsg *) memblock) -> pm_Startup . sm_Process = (struct MsgPort *) procPort;
  716.                     
  717.                         /* Setup Home directory (PROGDIR:) */
  718.                         (char *) ThisTask = (char *) procPort - sizeof( struct Task);
  719.                         ThisTask -> pr_HomeDir = lockSave;
  720.  
  721.                         /* ReplyPort to send back the message is our MsgPort 'WBPort' */
  722.                         ((struct PseudoMsg *) memblock) -> pm_Startup . sm_Message . mn_ReplyPort = WBPort;
  723.  
  724.                         /* How tall is the message we will send to the new created process? */
  725.                         ((struct PseudoMsg *) memblock) -> pm_Startup . sm_Message . mn_Length    = sizeof( PseudoMsg);
  726.  
  727.                         /*    We pass one argument to the new process: The lock of its directory
  728.                             and the PRG-name itself */
  729.                         ((struct PseudoMsg *) memblock) -> pm_Startup . sm_NumArgs = 1;
  730.                         ((struct PseudoMsg *) memblock) -> pm_ArgLock = -1;
  731.  
  732.                         /*    Check if we should pass one, single argument to the application we're
  733.                             going to fire up */
  734.                         if (appmsg->am_NumArgs)
  735.                         {
  736.                             ((struct PseudoMsg *) memblock) -> pm_ArgLock = DupLock( appmsg -> am_ArgList[0] . wa_Lock);
  737.                             strcpyNR( & ((struct PseudoMsg *) memblock) -> pm_ArgStrName[0], appmsg -> am_ArgList[0] . wa_Name);
  738.                             ((struct PseudoMsg *) memblock) -> pm_ArgName = & ((struct PseudoMsg *) memblock) -> pm_ArgStrName[0];
  739.                             ((struct PseudoMsg *) memblock) -> pm_Startup . sm_NumArgs = 2;
  740.                         }
  741.  
  742.                          /* sm_ArgList is setup with the address of pm_Lock (wa_Lock!) */
  743.                         (APTR) ((struct PseudoMsg *) memblock) -> pm_Startup . sm_ArgList = & ((struct PseudoMsg *) memblock) -> pm_Lock;
  744.  
  745.                         /* Now, send the message to the process */
  746.                         PutMsg( procPort, (struct Message *) memblock);
  747.  
  748.                         /* Increase counter or number of created processes */
  749.                         LaunchCnt ++;
  750.  
  751.                         /* Restore our (AddItem's) PROG-DIR */
  752.                         if ( OldDir)
  753.                             CurrentDir( OldDir);
  754.                     
  755.                         Permit();
  756.                         return;    /* Done */
  757.  
  758.             /* ------------- ERROR OCCURRED !!! --------------- */
  759.                     }
  760.  
  761.                     Permit();
  762.                     tell("DOS-function CreateProc() failed -\n"
  763.                          "thus cannot create process!");
  764.                     UnLoadSeg( ((struct PseudoMsg *) memblock) -> pm_Startup . sm_Segment);
  765.  
  766.                 }
  767.  
  768.                 if ( OldDir)
  769.                     CurrentDir( OldDir);
  770.                 if (lockSave)
  771.                     UnLock( lockSave);
  772.                 if ( ! (((struct PseudoMsg *) memblock) -> pm_Startup . sm_Segment))
  773.                     tell("Cannot load the programm-code!");
  774.                 if ( !(LaunchCnt) && (WBPort)    )
  775.                     DeleteMsgPort( WBPort);
  776.  
  777.             }
  778.  
  779.             if ( !(WBPort))
  780.                 tell("Cannot create \"ReplyPort\" for \"Pseudo WBench-message\"");
  781.             if ( !(LaunchCnt))
  782.                 WBPort = NULL;
  783.         }
  784.  
  785.         if ( !(memblock))
  786.             tell("Cannot allocate memory for \"Pseudo WBench-message\"");
  787.                 else
  788.             FreeMem( memblock, sizeof( PseudoMsg));
  789.     }
  790. }
  791.  
  792. /* #################### main ################## */
  793.  
  794. ULONG main( ULONG argc, APTR **argv)
  795. {
  796.     if (argc > 1)
  797.     {
  798.         if ( strcmpNR( (char *) argv[1], "?") == NULL )
  799.         {
  800.             printfNR("%s: %s", AIName, SyntaxTxt);
  801.             return 5;
  802.         }
  803.     }
  804.  
  805.     if ( SysBase -> LibNode . lib_Version < 37 )
  806.         bailoutold(122, "Wrong OS-Version! Need at least KS 2.04 .");
  807.  
  808.     IntuitionBase = (struct IntuitionBase *) OldOpenLibrary( "intuition.library");
  809.  
  810.     if ( !( WorkbenchBase = (struct Library *) OldOpenLibrary( "workbench.library") ))
  811.         bailout( 122, "Cannot open \"workbench.library\" !");
  812.  
  813.     if ( !( IconBase = (struct Library *) OpenLibrary( "icon.library", 33) ))
  814.         bailout( 122, "Cannot open \"icon.library\" !");
  815.  
  816.     if ( ((struct Process *) FindTask( NULL)) -> pr_StackSize < 3072 )
  817.         bailout( 20, "Cannot run: Stacksize set too low!");
  818.  
  819.     /*    If there is an existing port with the name "AddItem's WBench AppPort" signal the owner of
  820.         this port his end, do it via a CTRL-C signal. */
  821.     if ( (Port = (struct MsgPort *) FindPort( PortName) ))
  822.     {
  823.         Signal(    Port->mp_SigTask, 0x1000); /* CTRL-BREAK */
  824.         bailout( 5, "Removing existing AddItem program\n"
  825.                     "and terminating myself!");
  826.     }
  827.  
  828.     if ( !( MsgPort = (struct MsgPort *) CreateMsgPort() ))
  829.         bailout( 20, "Cannot create message port!");
  830.  
  831.     MsgPort->mp_Node.ln_Name = PortName;
  832.     MsgPort->mp_Node.ln_Pri = 1;
  833.     AddPort( MsgPort);
  834.  
  835.     /* Now we read the diskobject (icon-structure plus set strings) */
  836.     if (WBenchMsg)
  837.     {
  838.         if (WBenchMsg -> sm_ArgList -> wa_Lock)
  839.             CurrentDir(WBenchMsg -> sm_ArgList -> wa_Lock);
  840.  
  841.         if ( !(PrgIcon = (struct DiskObject *) GetDiskObject( WBenchMsg -> sm_ArgList -> wa_Name) ))
  842.             bailout(205, "Cannot find program specific icon!");
  843.     }
  844.     else
  845.     {
  846.         /*    We were called from CLI/Shell - so argv[0] contains our path and name,
  847.             thus we can use it to load our own program-icon. */
  848.         if ( !(PrgIcon = (struct DiskObject *) GetDiskObject( (UBYTE *) argv[0]) ))
  849.             bailout(205, "Cannot find program specific icon!");
  850.     }
  851.  
  852.     ToolTypes = PrgIcon -> do_ToolTypes;
  853.  
  854.     /* Is there a tooltype which matches with "ADDITEM" ? */
  855.     if ( !(ToolText = (UBYTE *) FindToolType( (UBYTE **) ToolTypes, "ADDITEM") ))
  856.         bailout( 20, "Not even one tool entry which\n"
  857.                      "matches with \"ADDITEM\" !");
  858.  
  859.     /* Now get all strings which are introduced by the text "ADDITEM" ! */
  860.     while (1)
  861.     {
  862.         if ( strncmpNR( ToolTypes[0], "ADDITEM=", 8) == NULL )
  863.         {
  864.             ToolText = (UBYTE *) ToolTypes[0];
  865.  
  866.             ItemTxt = ToolText + 8;    /* Pointer to char behind the "=" char */
  867.  
  868.             if ( !( CMDTxt = (UBYTE *) strchrNR( ItemTxt, ',') )) /* Search for a comma */
  869.                 bailout( 20, "Missing command part!");
  870.  
  871.             OTxt    = NULL;            /* Both are used also as flags... */
  872.             CMDLen    = NULL;
  873.  
  874.             CMDTxt    ++;                /* Skip comma */
  875.  
  876.             if ( CMDTxt[0] == '"')    /* Command part within quotes? */
  877.             {
  878.                 CMDTxt ++;            /* Skip quote */
  879.                 CMDLen = -1L;        /* Skip also unquote! */
  880.  
  881.                 if ( !(OTxt = (UBYTE *) strchrNR( CMDTxt, '"') ))    /* Find unquote... */
  882.                     bailout( 20, "Invalid number of double quotes\n"
  883.                                  "set within command part!");
  884.  
  885.                 if ( OTxt[1] != ',')    /* The next char the comma ? */
  886.                     bailout( 20, "Missing output part!");
  887.  
  888.                 OTxt = OTxt + 2;        /* Skip unquote and comma */
  889.             }
  890.  
  891.             ILen = CMDTxt - ItemTxt - 1;
  892.  
  893.             if ( !(OTxt) )    /* OTxt already set (when in quotes) ? */
  894.             {
  895.                 if ( !(OTxt = (UBYTE *) strchrNR( CMDTxt, ',') ))    /* Search for 2nd comma... */
  896.                     bailout( 20, "Missing command part!");
  897.                 OTxt ++;    /* Skip comma */
  898.             }
  899.             else
  900.             {
  901.                 ILen --; /* otherwise CMDTxt within quotes so correct ILen! */
  902.             }
  903.  
  904.             CMDLen    = CMDLen + ( OTxt - CMDTxt - 1);
  905.             OLen    = strlenNR( OTxt );
  906.  
  907.             /*    Now we allocate an array where we can store the yet computed
  908.                 things; when we create ( see below) a MenuItem the user-data
  909.                 field of it points to this array. */
  910.             ArrayPtr = (APTR) AllocRemember( (struct Remember **) &RememberKey, sizeof( stuff) +
  911.                                              strlenNR(ToolText) + 1 +
  912.                                              ILen + 1 +
  913.                                              CMDLen + 1 +
  914.                                              OLen + 1, MEMF_CLEAR);
  915.             if ( !(ArrayPtr) )
  916.                 bailout( 103, "Error while allocating the Item-stuff!");
  917.  
  918.             /* Pointer to buffer for strings right behind pointer table! */
  919.             DummyPtr = (UBYTE *) ArrayPtr + sizeof( stuff);
  920.             /* TextLinePtr points to the buffer... */
  921.             ArrayPtr ->TextLinePtr = DummyPtr;
  922.             /* Copy string to buffer... */
  923.             CopyMem( ItemTxt, DummyPtr, strlenNR( ItemTxt) );
  924.  
  925.             /* Buffer = Buffer + strlenNR(Buffer) + 1 */
  926.             DummyPtr = (UBYTE *) DummyPtr + strlenNR( ToolText) + 1;
  927.             /* ItemTextPtr = Buffer */
  928.             ArrayPtr -> ItemTextPtr = DummyPtr;
  929.             /* Copy string to Buffer */
  930.             CopyMem( ItemTxt, DummyPtr, ILen );
  931.  
  932.             /* Pointer to next free pool of buffer */
  933.             DummyPtr = (UBYTE *) DummyPtr + ILen + 1;
  934.             /* CMDTextPtr = Buffer */
  935.             ArrayPtr -> CMDTextPtr = DummyPtr;
  936.             /* Copy string to Buffer */
  937.             CopyMem( CMDTxt, DummyPtr, CMDLen );
  938.  
  939.             /* Pointer to next free pool of buffer */
  940.             DummyPtr = (UBYTE *) DummyPtr + CMDLen + 1;
  941.             /* OutputTextPtr = Buffer */
  942.             ArrayPtr -> OutputTextPtr = DummyPtr;
  943.             /* Copy string to buffer */
  944.             CopyMem( OTxt, DummyPtr, OLen );
  945.  
  946. /* Can be used for debugging....
  947.             printfNR("Original: %s\n    Item= %s, Cmd= %s, Out= %s\n",
  948.                      ArrayPtr -> TextLinePtr,
  949.                      ArrayPtr -> ItemTextPtr,
  950.                      ArrayPtr -> CMDTextPtr,
  951.                      ArrayPtr -> OutputTextPtr ); */
  952.  
  953.             /*    Now  we allocate an array where we can store the address of the created MenuItem made
  954.                 with  function AddAppMenuItemA(); we need only 4 bytes but the minimum for allocation
  955.                 should ever be 8 */
  956.  
  957.             CurrItem = (APTR) AllocRemember( &ItemList, sizeof( ilist),    MEMF_CLEAR);
  958.             if ( !(CurrItem) )
  959.                 bailout( 103, "Cannot allocate linked list for Items!");
  960.  
  961.             /* Create a item in the tool-menu.... */
  962.             WBMadeItem = (struct AppMenuItem *)
  963.             AddAppMenuItemA( NULL, (ULONG) ArrayPtr, ArrayPtr -> ItemTextPtr, MsgPort, NULL);
  964.             if (WBMadeItem == NULL)
  965.                 bailout( 20, "Workbench said: Cannot create Item...");
  966.  
  967.             /* Remember Item (created) in allocated array... */
  968.             ((struct ilist *) CurrItem) -> ilistItem = WBMadeItem;
  969.  
  970.             ToolTypes ++;    /* Next tool-entry */
  971.         }
  972.         else
  973.         {
  974.             ToolTypes ++;    /* Wasn't "ADDITEM=" so point only to next tool-entry */
  975.         }
  976.  
  977.         if (ToolTypes[0] == NULL)
  978.             break;    /* No next entry ? */
  979.     }
  980.  
  981.     while (1)
  982.     {
  983.         if (WBPort)        /* Workbench port set (to emulate WBStart?) */
  984.         {
  985.             WBSignal = WBPort->mp_SigBit;    /* If so, get sigbit of WBPort */
  986.             WBSignal = 1 << WBSignal;        /* Convert it into mask */
  987.         }
  988.  
  989.         SignalSet = MsgPort->mp_SigBit;        /* Get Sigbit of msg-port */
  990.         SignalSet = 1 << SignalSet;            /* Convert it into mask */
  991.         SignalSet |= 0x1000;                /* Add also CTRL-C */
  992.  
  993.         if (WBPort)                            /* Emulate WBStart ? */
  994.             SignalSet |= WBSignal;            /* If so, wait also for the reply of messages */
  995.  
  996.         SignalSet = Wait( SignalSet);         /* Wait for signals */
  997.  
  998.         if ( (SignalSet & 0x1000) == 0x1000) /* CTRL-C ? */
  999.         {
  1000.             closeall();
  1001.             exit(0);
  1002.         }
  1003.  
  1004.         if (WBPort)
  1005.         {
  1006.             if ( (SignalSet & WBSignal) == WBSignal)    /* A reply ? */
  1007.             {
  1008.                 while ( WBPort && (PMsg = (APTR) GetMsg( WBPort)) )
  1009.                     RemMessage( (struct PseudoMsg *) PMsg);
  1010.             }
  1011.         }
  1012.  
  1013.         if ( (SignalSet & (1 << MsgPort->mp_SigBit)) == (1 << MsgPort->mp_SigBit) )
  1014.         {
  1015.             /* Else a WBench-Item message */
  1016.             while ( (AMsg = (struct AppMessage *) GetMsg( MsgPort)) )
  1017.             {
  1018.                 CallFunc( AMsg);    /* Do something with that message... */
  1019.                 ReplyMsg( (struct Message *) AMsg);
  1020.             }
  1021.         }
  1022.     }
  1023. }
  1024.