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