/*
 To compile:  lc -L sample.c
*/
/* This program demonstrates several techniques for using taglists with
   the 2.0 system calls.  As a whole, the program is not intended to be
   a good application, but to illustrate the different methods available
   for passing tag lists.
   
   Once the program is running, just select one of the 3 menu items to
   use the functions.
*/

#include <stdio.h>
#include <exec/types.h>
#include <dos/dos.h>
#include <dos/dostags.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/gadtools.h>
#include <utility/tagitem.h>
#include <libraries/gadtools.h>

/* These functions are used to show off tag lists in DOS calls */
void dosync(void);
void doasync(void);

/* This routine will provide a stub for calling System with a taglist */
LONG TagSystem(char *, long, ...);

/* These compile time tags are passed to OpenWindowTagList */
struct TagItem wtags[] = {
    { WA_Left,         10  },
    { WA_Top,          10  },
    { WA_Width,        400 },
    { WA_Height,       100 },
    { WA_Title,        (LONG)"Sample of Taglists - please select a menu item" },
    { WA_SizeGadget,   TRUE},
    { WA_CloseGadget,  TRUE },
    { WA_Activate,     TRUE },
    { WA_SmartRefresh, TRUE },
    { WA_DepthGadget,  TRUE },
    { WA_IDCMP,        MENUPICK|CLOSEWINDOW },
    { TAG_DONE,        0 }
};

/* Used for LayoutMenu - note that there are really no tags passed */
struct TagItem layouttags[] = {
    { TAG_DONE,        0 }
};

/* This is the simple menu to be attached to our window */
struct NewMenu mynewmenu[] =
{
   { NM_TITLE, "Project",        0,  0, 0, 0},
      { NM_ITEM,  "Sync Test",  "1", 0, 0, (APTR)1},
      { NM_ITEM,  "Async Test", "2", 0, 0, (APTR)2},
      { NM_ITEM,  NM_BARLABEL,   0,  0, 0, 0},
      { NM_ITEM,  "Quit",        0,  0, 0, 0},
   { NM_END,  0,                 0,  0, 0, 0},
};

struct Library *GadToolsBase;
struct IntuitionBase *IntuitionBase;

void main()
{
   struct IntuiMessage *msg;
   int runflag;
   long servfunc;
   APTR vi = NULL;
   int menunum;
   struct MenuItem *item;
   struct Window *window = NULL;
   struct Menu *menustrip = NULL;

   GadToolsBase = OpenLibrary("gadtools.library", 0);
   if (GadToolsBase == NULL) return;
   
   /* Get intuition opened for our work.  We must have at least 37 or */
   /* nothing will work.  We can rely on DOS being at level 37 also   */
   IntuitionBase = (struct IntuitionBase *)
                   OpenLibrary("intuition.library", 37);
   if (IntuitionBase == NULL)
   {
      CloseLibrary(GadToolsBase);
      return;
   }

   /* Our first tag list - use the compile time initialized taglist */
   /* to open up a window.  Note that when we provide as much as we */
   /* have, there really isn't a need for a NewWindow structure     */
   window = OpenWindowTagList(NULL, wtags);
   if (window == NULL) goto quitit;

   /* Pass the taglist as a parameter - since there are no interesting */
   /* tags to be sent, we just give a TAG_DONE.  Note that we do not   */
   /* have to pass a data item since it would be ignored anyway        */
   vi = GetVisualInfo(window->WScreen, TAG_DONE);
   if (vi == NULL) goto quitit;

   /* Here we also pass the tag list, but we have at least one tag     */
   menustrip = CreateMenus(mynewmenu, GTMN_FrontPen, 0,
                                      TAG_DONE);
   if (menustrip == NULL) goto quitit;

   /* Again, we use the compile timee initialized taglist.  In this  */
   /* call, the taglist is basically empty.  Note that we could have */
   /* called LayoutMenus(menustrip, vi, TAG_DONE) to get the same    */
   /* result.  The A at the end indicates that it wants the address  */
   /* of a taglist instead of a taglist directly                     */
   if (!LayoutMenusA(menustrip, vi, layouttags)) goto quitit;

   /* Put the menu on our window */
   SetMenuStrip(window, menustrip);

   /* Go until someone tells us to quit */
   for(runflag = 1; runflag;)
   {
      WaitPort(window->UserPort);
      if (msg = (struct IntuiMessage *)GetMsg(window->UserPort))
      {
         switch(msg->Class)
         {
            case CLOSEWINDOW:
               runflag = 0;
               break;
            case MENUPICK:
               menunum = msg->Code;
               while(menunum != MENUNULL)
               {
                  item = ItemAddress(menustrip, menunum);
                  /* Let gadtools give us the aptr that we passed to */
                  /* it when we created the menu items               */
                  servfunc = (long)GTMENUITEM_USERDATA(item);
                  switch(servfunc)
                  {
                     case 0:  runflag = 0;  break;
                     case 1:  dosync();     break;
                     case 2:  doasync();    break;
                     default: runflag = 0;  break;
                  }
                  menunum = item->NextSelect;
               }
               break;
            default:
               break;
         }
         ReplyMsg((struct Message *)msg);
      }
   }
   ClearMenuStrip(window);
   
quitit:
   /* Cleanup and exit */
   if (vi != NULL) FreeVisualInfo(vi);
   if (menustrip != NULL) FreeMenus(menustrip);
   if (window != NULL) CloseWindow(window);
   CloseLibrary(GadToolsBase);
   CloseLibrary((struct Library *)IntuitionBase);
}

/* This shows an example of running a process synchronously.          */
/* While the actuall operation here is not very useful (we could have */
/* called CreateDir() directly) is does show calling System and using */
/* the result                                                         */
void dosync()
{
   /* We will build this taglist by hand */
   struct TagItem tags[5];
   
   BPTR infh, fh;
   infh = Open("Nil:", MODE_OLDFILE);
   if (infh != NULL)
   {
      fh = Open("Nil:", MODE_OLDFILE);
      if (fh != NULL)
      {
         /* Set up the taglist to be passed */
         tags[0].ti_Tag  = SYS_Output; 
         tags[0].ti_Data = infh;
         tags[1].ti_Tag  = SYS_Input;
         tags[1].ti_Data = fh;
         tags[2].ti_Tag  = TAG_DONE;
         /* First we create a directory in Ram: */
         if (!System("makedir ram:YYJunkDIRECTORY", tags))
         {
            /* Then we delete it.  Note that we can reuse the taglist */
            /* because it is not destroyed in the process.            */
            System("delete  ram:YYJunkDIRECTORY", tags);
            System("echo >CON:0/0/100/100/DONE DONE", tags);
         }
         Close(fh);
      }
      Close(infh);
   }
}

void doasync()
{
   BPTR infh, fh;

   /* Get a phony input file handle (no input will be done) */
   infh = Open("Nil:", MODE_OLDFILE);
   if (infh == NULL) return;
   
   /* Get an output location for the data to go */
   fh = Open("CON:0/0/300/200/ASyncOut/CLOSE", MODE_NEWFILE);
   if (fh == NULL)
   {
      /* Oops, couldn't open the console, abort everything */
      Close(infh);
   }
   else
   {
      /* Everything worked out, so run the program               */
      /* Since System() does not have a tag array form, we call  */
      /* our stub which will generate a taglist by the virtue of */
      /* the C calling conventions.                              */
      /* This can be useful for creating your own tag function   */
      /* and not having to create any tag stubs in a library.    */
      TagSystem("dir df0:", SYS_Asynch, TRUE,
                            SYS_Output, fh,
                            SYS_Input,  infh,
                            TAG_DONE);
   }
}

/* This stub function takes the parameters and just calls System. */
/* Since C calling conventions put the parameters on the stack in */
/* reverse order, it falls directly into the format that a taglist*/
/* expects.  We can take advantage of this and just pass the      */
/* address of the first parameter to create a taglist on the fly  */
LONG TagSystem(char *command, long tag1, ...)
{
   return(System(command, (struct TagItem *)&tag1));
}
