home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 066.lha / ttasks.c < prev    next >
C/C++ Source or Header  |  1986-11-20  |  12KB  |  316 lines

  1.  
  2. /* `TTalk' - Talking Tasks
  3. * -programming example using messages and ports
  4. * (C)1987 Transactor Publishing Inc.
  5. * From Transactor Magazine, written by Chris Zamara, May 1987
  6. * ---->>This program may be freely distributed<<----
  7. *
  8. * This code shows you how to create and find message ports, and how
  9. * to send, receive, and reply to messages.
  10. *
  11. * This program, `TTalk', lets you create several named DOS windows, and send
  12. * messages between them. Just give each task its name when you run it
  13. * from the CLI, e.g. "run TTalk Fred". If you start another task,
  14. * like "run TTalk Edna", you can send Edna a message from Fred by typing
  15. * into Fred's window something like, "Edna, you look lovely today!"
  16. * Edna will receive the  message and print it in her window. Any number
  17. * of these tasks can be started, and any one can talk to any other.
  18. *
  19. * How it works: A message port is created and given the name that the user
  20. * supplies (the name in the window title). To send a message to another task,
  21. * its port is found with FindPort(), a message is sent to the port with
  22. * PutMsg(), and a reply is waited for with WaitPort(). Within the message is
  23. * a pointer to the text that the user wanted to send. The receiving task
  24. * uses GetMsg() in between waiting for the keypresses to receive the message.
  25. * All talking tasks also have access to a public port called "Joe's Cafe",
  26. * where they read a message saying how many talking tasks are running, and
  27. * update the message when they are started and ended. By talking at Joe"s
  28. * Cafe, the talking tasks can determine a good place to put their window so
  29. * that the user doesn't have to always move around overlapping windows. The
  30. * first task started creates the "Joe's Cafe" port and the first message
  31. * there, and the last task ended deletes them.
  32. *
  33. * compiled with Manx Aztec 3.40a, should work with Lattice as well.
  34. */
  35.  
  36. #include <exec/types.h>
  37. #include <exec/memory.h>
  38. #include <exec/ports.h>
  39. #include <libraries/dos.h>
  40.  
  41. /* Print macro used to send a string to the output window */
  42. #define Print(s) Write(IOfile,(s),(long)strlen(s))
  43.  
  44. #define BUFLEN 200 /* length of input buffer for user text entry */
  45.  
  46. /* this is the structure for the message we will be sending */
  47. struct MyMessage {
  48.    struct Message Msg;     /* for Exec message routines */
  49.    char *NameOfSender;     /* sender puts his name here */
  50.    char *text;             /* the text we want to send */
  51. };
  52.  
  53. /* this is the kind of message we will use to
  54.  * determine how many talking tasks are currently running
  55.  */
  56.  struct CountMsg {
  57.    struct Message Msg;
  58.       int Count;
  59. };
  60.  
  61. /* external function declarations */
  62. extern BPTR Open();
  63. extern ULONG Read();
  64. extern UBYTE *AllocMem();
  65. extern struct MsgPort *CreatePort(), *FindPort();
  66. extern struct MyMessage *GetMsg();
  67.  
  68. /* global variables */
  69. char *MyName;                   /* ptr to name given to this `talking task'*/ 
  70. struct MsgPort *MyPort = NULL;  /* message port for sending/receiving msgs */
  71. struct MsgPort *TTport;         /* port shared by all Talking Tasks        */
  72. char *TTportName="Joe's Cafe";  /* name of TTport, where they all hang out */
  73. struct CountMsg *TTmsg;         /* the message we'll leave at Joe's Cafe   */
  74. BPTR IOfile = NULL;             /* DOS file handle for the terminal window */
  75.  
  76.  
  77. /******** start of main  **************************************************/
  78. main(argc,argv)
  79. int argc;
  80. char **argv;
  81. {
  82. /* give user instructions and exit if invalid args passed */
  83.   if (argc!=2||strlen(argv[1])>30)
  84.   {
  85.     printf("Run me with a name, like `run %s Ernie'\n",argv[0]);
  86.     exit(0);
  87.   }
  88.   MyName = argv[1]; /* first argument is name given to this `talking task' */
  89.   /* open DOS window,create ports, etc. and return TRUE if successful */
  90.   if(OpenStuff())
  91.     HandleInput();  /* get input, send and read messages until user exits */
  92.   CloseStuff();
  93. }
  94.  
  95. /* OpenStuff() ************************************************************
  96. * create `MyPort' message port, call HowMany() and open DOS window
  97. */
  98. OpenStuff()
  99. {
  100. static char windowName[50]; /* holds filename for DOS `con' window */
  101. /* this array ia used to choose an appropriate window position */
  102. static char *conNames[] = {"con:0/0/319/65/","con:320/0/319/65/",
  103.                            "con:0/67/319/65/","con:320/67/319/65/",
  104.                            "con:0/134/319/65/","con:320/134/319/65/"
  105.                           };
  106. /* see if a message port with the given name already exists */
  107.   if(FindPort(MyName))
  108.   {
  109.     printf("Hey, there's already someone here called %s!\n",MyName);
  110.     return (int)FALSE;
  111.   }
  112. /* set up a message port with the given name and get a pointer to it */
  113.   MyPort = CreatePort(MyName,0L);
  114.   if(MyPort==NULL)
  115.   {
  116.     printf("can't open %s' port!\n",MyName);
  117.     return(int)FALSE;
  118.   }
  119.   /* the number of talking tasks running determines where to put the window */
  120.   strcpy(windowName,conNames[HowMany()%6]);
  121.   strcat(windowName,MyName); /* MyName is title for the DOS window */
  122.   IOfile = Open(windowName,MODE_NEWFILE); /* open DOS window for user I/O */
  123.   if(IOfile==NULL)    /* file didn't open for some reason */
  124.     return (int)FALSE;
  125.   /* print some instructions */
  126.   Print("(send message with <name,message...>)");
  127.   return (int)TRUE;     /* everything opened OK */
  128. }
  129.  
  130. /* CloseStuff() **********************************************************
  131. * Undo what OpenStuff() and HowMany() did
  132. */
  133. CloseStuff()
  134. {
  135.   if(IOfile)
  136.     Close(IOfile);      /* close DOS window if open */
  137.   /* decrease count in TTport message, remove port if count is zero */
  138.   if(TTport = FindPort(TTportName))
  139.   {
  140.     TTmsg = (struct CountMsg *)GetMsg(TTport);
  141.     if(TTmsg->Count--)  /* still more talking tasks, don't remove port */
  142.       PutMsg(TTport,TTmsg); /* put bacxk message with decreased count */
  143.     else
  144.     {  /* we're the last talking task, remove TTport and TTmsg */
  145.       RemPort(TTport);  /* remove the port */
  146.       FreeMem(TTmsg,(ULONG)sizeof(*TTmsg));
  147.       FreeMem(TTport->mp_Node.ln_Name,(ULONG)(strlen(TTportName)+1));
  148.       FreeMem(TTport,(ULONG)sizeof(*TTport));
  149.     }
  150.   }
  151.   if(MyPort)
  152.     DeletePort(MyPort);   /* delete our main message port */
  153. }
  154.  
  155.  
  156. /* HandleInput() *********************************************************
  157. * Get user input from window and any messages arriving at MyPort
  158. * Text from the user is passed to SendMessage().
  159. * Print text field of incloming messages, then reply to message.
  160. * Returns when user inputs a null text line.
  161. */
  162. HandleInput()
  163. {
  164. char InputBuffer[BUFLEN];
  165. BOOL exit_flag = FALSE;
  166. struct MyMessage *msg;
  167.  
  168. /* We want to get keyboard input from the user AND get messages arriving
  169. * at our message port, and we don't want to waste much CPU time.
  170. * So we WAitForChar() and if no character is received within 1/10
  171. * second, we read the message port, process any messages there, and try
  172. * again. This way we only GetMsg() every 1/10 second, which is cheap.
  173. */
  174.   while (exit_flag == FALSE)
  175.   {
  176.   if(WaitForChar(IOfile,100000))  /* wait for 1/10 second (in micros) */
  177.   {
  178.     /* read an input line and send the message */
  179.     if(Read(IOfile,InputBuffer,(long)BUFLEN)>1)
  180.       SendString(InputBuffer);
  181.     else
  182.       exit_flag = TRUE; /* newline by itself means user exit */
  183.     }
  184.     /* now handle any messages for us at the port */
  185.     while(msg=GetMsg(MyPort)) /* loop until all messages processed */
  186.     {
  187.       Print("A message from ");
  188.       Print(msg->NameOfSender);
  189.       Print(":\n\"");
  190.       Print(msg->text);
  191.       Print("\"\n");
  192.       /* We took care of the message, now reply to it */
  193.       ReplyMsg(msg);
  194.     }
  195.   }
  196. }
  197.  
  198. /* SendString(text) ****************************************************
  199. * Split the given screen into two strings at first comma
  200. * and call SendMessage() with the resultant strings.
  201. * Print error message if no comma found.
  202. */
  203. SendString(text)
  204. char *text;
  205. {
  206. int NamePos;
  207.   NamePos = SearchChar(text,',',BUFLEN);  /* check for comma */
  208.   if(NamePos==BUFLEN) /* no comma */
  209.     Print("(send message with <name,message...>)");
  210.   else
  211.   {   /* split strings into two and give strings to SendMessage() */
  212.     text[NamePos] = '\0';
  213.     text[SearchChar(text,'\n',BUFLEN)] = '\0';
  214.     SendMessage(text,text + NamePos +1);
  215.   }
  216. }
  217.  
  218.  
  219. /* SendMessage(name,msgstring) *****************************************
  220. * Given a port name and a text string, find the port and send a
  221. * message containing the string to it, and wait for a reply.
  222. */
  223. SendMessage(name,msgstring)
  224. char *name,*msgstring;
  225. {
  226. struct MsgPort *HisPort;
  227. struct MyMessage message;
  228.  
  229.   HisPort = FindPort(name); /* look for the other fellow's message port */
  230.   if(HisPort==NULL)  /* NULL means port couldn't be found */
  231.   {
  232.     Print("Can't find ");
  233.     Print(name);
  234.     Print("!\n");
  235.   }
  236.   /* error if message being sent to ourselves */
  237.   else if (strcmp(name,MyName)==0)
  238.     Print("Talking to myself...OK!\n");
  239.   else if(strcmp(name,TTportName)==0)
  240.   { /* don't send to Joe's cafe!! */
  241.     Print("Oh no you don't!\nHumans aren't allowed at ");
  242.     Print(TTportName);
  243.     Print(".\n");
  244.   }
  245.   else  /* everything's OK, prepare the message and send it to his port */
  246.   {
  247.     message.Msg.mn_Node.ln_Type = NT_MESSAGE; /* for Exec list handling */
  248.     message.Msg.mn_Length = sizeof(message);  /* number of bytes in msg */
  249.     message.Msg.mn_ReplyPort = MyPort;        /* so receiver can reply  */
  250.     message.NameOfSender = MyName;            /* tell him who sent it   */
  251.     message.text = msgstring;                 /* our text string to send*/
  252.     PutMsg(HisPort,&message);                 /* send the message       */
  253.     WaitPort(MyPort);                         /* wait for reply         */
  254.     GetMsg(MyPort);                           /* remove reply from port */
  255.     Print("<Got acknowledgement from ");      /* tell user we got reply */
  256.     Print(name);
  257.     Print(">\n");
  258.   }
  259. }
  260.  
  261.  
  262. /* SearchChar(string,chr,n) *********************************************
  263. * find character `chr' in `string', searching up to n characters
  264. * return n if character not found
  265. */
  266. SearchChar(string,chr,n)
  267. char *string;
  268. int chr, n;
  269. {
  270. int i;
  271.   for(i=0;i<n&&string[i]!=chr;i++)
  272.     ;
  273.   return(i);
  274. }
  275.  
  276.  
  277. /* HowMany() ***********************************************************
  278. * Determines how many `talking tasks' are currently in the system. Look for
  279. * aport named TTportName (Joe's Cafe). If it exists, get a `CountMsg'
  280. * message from it, read the count, increment it and put the message back. If
  281. * the port doesn't exist, create it and put a message there with the count
  282. * field set to zero. Return the value of the count.
  283. */
  284. HowMany()
  285. {
  286. int count;
  287.   if(TTport = FindPort(TTportName))
  288.   {
  289.     TTmsg = (struct CountMsg *)GetMsg(TTport);  /* get message... */
  290.     count = ++TTmsg->Count;                     /* bump count...  */
  291.     PutMsg(TTport,TTmsg);                       /* and put it back*/
  292.   }
  293.   else
  294.   { /* port not there, we are first talking task - create the port */
  295.     TTport=(struct MsgPort *)AllocMem((ULONG)sizeof(*TTport),MEMF_PUBLIC);
  296.     TTport->mp_Node.ln_Name = (char *)
  297.       AllocMem((ULONG)(strlen(TTportName)+1),MEMF_PUBLIC);
  298.     strcpy(TTport->mp_Node.ln_Name,TTportName);
  299.     TTport->mp_Node.ln_Pri = 0;
  300.     TTport->mp_Node.ln_Type = NT_MSGPORT;
  301.     TTport->mp_Flags = PA_IGNORE;
  302.     AddPort(TTport);  /* make the port public so all tasks have access */
  303.     
  304.     /* now create the message to put in the port (Joe's Cafe) */
  305.     TTmsg=(struct CountMsg *)AllocMem((ULONG)sizeof(*TTmsg),MEMF_PUBLIC);
  306.     TTmsg->Msg.mn_Node.ln_Type = NT_MESSAGE;  /* for Exec list handling */
  307.     TTmsg->Msg.mn_Length = sizeof(*TTmsg);    /* number of byte in msg  */
  308.     TTmsg->Msg.mn_ReplyPort = NULL;           /* no reply port required */
  309.     TTmsg->Count = count = 0;                 /* start count at zero    */
  310.     PutMsg(TTport,TTmsg); /* leave a message at Joe's Cafe for everyone */
  311.   }
  312.   return count;
  313. }
  314.  
  315. /*********  end of ttasks.c  ********************************************/
  316.