home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Club Amiga de Montreal - CAM
/
CAM_CD_1.iso
/
files
/
066.lha
/
ttasks.c
< prev
next >
Wrap
C/C++ Source or Header
|
1986-11-20
|
12KB
|
316 lines
/* `TTalk' - Talking Tasks
* -programming example using messages and ports
* (C)1987 Transactor Publishing Inc.
* From Transactor Magazine, written by Chris Zamara, May 1987
* ---->>This program may be freely distributed<<----
*
* This code shows you how to create and find message ports, and how
* to send, receive, and reply to messages.
*
* This program, `TTalk', lets you create several named DOS windows, and send
* messages between them. Just give each task its name when you run it
* from the CLI, e.g. "run TTalk Fred". If you start another task,
* like "run TTalk Edna", you can send Edna a message from Fred by typing
* into Fred's window something like, "Edna, you look lovely today!"
* Edna will receive the message and print it in her window. Any number
* of these tasks can be started, and any one can talk to any other.
*
* How it works: A message port is created and given the name that the user
* supplies (the name in the window title). To send a message to another task,
* its port is found with FindPort(), a message is sent to the port with
* PutMsg(), and a reply is waited for with WaitPort(). Within the message is
* a pointer to the text that the user wanted to send. The receiving task
* uses GetMsg() in between waiting for the keypresses to receive the message.
* All talking tasks also have access to a public port called "Joe's Cafe",
* where they read a message saying how many talking tasks are running, and
* update the message when they are started and ended. By talking at Joe"s
* Cafe, the talking tasks can determine a good place to put their window so
* that the user doesn't have to always move around overlapping windows. The
* first task started creates the "Joe's Cafe" port and the first message
* there, and the last task ended deletes them.
*
* compiled with Manx Aztec 3.40a, should work with Lattice as well.
*/
#include <exec/types.h>
#include <exec/memory.h>
#include <exec/ports.h>
#include <libraries/dos.h>
/* Print macro used to send a string to the output window */
#define Print(s) Write(IOfile,(s),(long)strlen(s))
#define BUFLEN 200 /* length of input buffer for user text entry */
/* this is the structure for the message we will be sending */
struct MyMessage {
struct Message Msg; /* for Exec message routines */
char *NameOfSender; /* sender puts his name here */
char *text; /* the text we want to send */
};
/* this is the kind of message we will use to
* determine how many talking tasks are currently running
*/
struct CountMsg {
struct Message Msg;
int Count;
};
/* external function declarations */
extern BPTR Open();
extern ULONG Read();
extern UBYTE *AllocMem();
extern struct MsgPort *CreatePort(), *FindPort();
extern struct MyMessage *GetMsg();
/* global variables */
char *MyName; /* ptr to name given to this `talking task'*/
struct MsgPort *MyPort = NULL; /* message port for sending/receiving msgs */
struct MsgPort *TTport; /* port shared by all Talking Tasks */
char *TTportName="Joe's Cafe"; /* name of TTport, where they all hang out */
struct CountMsg *TTmsg; /* the message we'll leave at Joe's Cafe */
BPTR IOfile = NULL; /* DOS file handle for the terminal window */
/******** start of main **************************************************/
main(argc,argv)
int argc;
char **argv;
{
/* give user instructions and exit if invalid args passed */
if (argc!=2||strlen(argv[1])>30)
{
printf("Run me with a name, like `run %s Ernie'\n",argv[0]);
exit(0);
}
MyName = argv[1]; /* first argument is name given to this `talking task' */
/* open DOS window,create ports, etc. and return TRUE if successful */
if(OpenStuff())
HandleInput(); /* get input, send and read messages until user exits */
CloseStuff();
}
/* OpenStuff() ************************************************************
* create `MyPort' message port, call HowMany() and open DOS window
*/
OpenStuff()
{
static char windowName[50]; /* holds filename for DOS `con' window */
/* this array ia used to choose an appropriate window position */
static char *conNames[] = {"con:0/0/319/65/","con:320/0/319/65/",
"con:0/67/319/65/","con:320/67/319/65/",
"con:0/134/319/65/","con:320/134/319/65/"
};
/* see if a message port with the given name already exists */
if(FindPort(MyName))
{
printf("Hey, there's already someone here called %s!\n",MyName);
return (int)FALSE;
}
/* set up a message port with the given name and get a pointer to it */
MyPort = CreatePort(MyName,0L);
if(MyPort==NULL)
{
printf("can't open %s' port!\n",MyName);
return(int)FALSE;
}
/* the number of talking tasks running determines where to put the window */
strcpy(windowName,conNames[HowMany()%6]);
strcat(windowName,MyName); /* MyName is title for the DOS window */
IOfile = Open(windowName,MODE_NEWFILE); /* open DOS window for user I/O */
if(IOfile==NULL) /* file didn't open for some reason */
return (int)FALSE;
/* print some instructions */
Print("(send message with <name,message...>)");
return (int)TRUE; /* everything opened OK */
}
/* CloseStuff() **********************************************************
* Undo what OpenStuff() and HowMany() did
*/
CloseStuff()
{
if(IOfile)
Close(IOfile); /* close DOS window if open */
/* decrease count in TTport message, remove port if count is zero */
if(TTport = FindPort(TTportName))
{
TTmsg = (struct CountMsg *)GetMsg(TTport);
if(TTmsg->Count--) /* still more talking tasks, don't remove port */
PutMsg(TTport,TTmsg); /* put bacxk message with decreased count */
else
{ /* we're the last talking task, remove TTport and TTmsg */
RemPort(TTport); /* remove the port */
FreeMem(TTmsg,(ULONG)sizeof(*TTmsg));
FreeMem(TTport->mp_Node.ln_Name,(ULONG)(strlen(TTportName)+1));
FreeMem(TTport,(ULONG)sizeof(*TTport));
}
}
if(MyPort)
DeletePort(MyPort); /* delete our main message port */
}
/* HandleInput() *********************************************************
* Get user input from window and any messages arriving at MyPort
* Text from the user is passed to SendMessage().
* Print text field of incloming messages, then reply to message.
* Returns when user inputs a null text line.
*/
HandleInput()
{
char InputBuffer[BUFLEN];
BOOL exit_flag = FALSE;
struct MyMessage *msg;
/* We want to get keyboard input from the user AND get messages arriving
* at our message port, and we don't want to waste much CPU time.
* So we WAitForChar() and if no character is received within 1/10
* second, we read the message port, process any messages there, and try
* again. This way we only GetMsg() every 1/10 second, which is cheap.
*/
while (exit_flag == FALSE)
{
if(WaitForChar(IOfile,100000)) /* wait for 1/10 second (in micros) */
{
/* read an input line and send the message */
if(Read(IOfile,InputBuffer,(long)BUFLEN)>1)
SendString(InputBuffer);
else
exit_flag = TRUE; /* newline by itself means user exit */
}
/* now handle any messages for us at the port */
while(msg=GetMsg(MyPort)) /* loop until all messages processed */
{
Print("A message from ");
Print(msg->NameOfSender);
Print(":\n\"");
Print(msg->text);
Print("\"\n");
/* We took care of the message, now reply to it */
ReplyMsg(msg);
}
}
}
/* SendString(text) ****************************************************
* Split the given screen into two strings at first comma
* and call SendMessage() with the resultant strings.
* Print error message if no comma found.
*/
SendString(text)
char *text;
{
int NamePos;
NamePos = SearchChar(text,',',BUFLEN); /* check for comma */
if(NamePos==BUFLEN) /* no comma */
Print("(send message with <name,message...>)");
else
{ /* split strings into two and give strings to SendMessage() */
text[NamePos] = '\0';
text[SearchChar(text,'\n',BUFLEN)] = '\0';
SendMessage(text,text + NamePos +1);
}
}
/* SendMessage(name,msgstring) *****************************************
* Given a port name and a text string, find the port and send a
* message containing the string to it, and wait for a reply.
*/
SendMessage(name,msgstring)
char *name,*msgstring;
{
struct MsgPort *HisPort;
struct MyMessage message;
HisPort = FindPort(name); /* look for the other fellow's message port */
if(HisPort==NULL) /* NULL means port couldn't be found */
{
Print("Can't find ");
Print(name);
Print("!\n");
}
/* error if message being sent to ourselves */
else if (strcmp(name,MyName)==0)
Print("Talking to myself...OK!\n");
else if(strcmp(name,TTportName)==0)
{ /* don't send to Joe's cafe!! */
Print("Oh no you don't!\nHumans aren't allowed at ");
Print(TTportName);
Print(".\n");
}
else /* everything's OK, prepare the message and send it to his port */
{
message.Msg.mn_Node.ln_Type = NT_MESSAGE; /* for Exec list handling */
message.Msg.mn_Length = sizeof(message); /* number of bytes in msg */
message.Msg.mn_ReplyPort = MyPort; /* so receiver can reply */
message.NameOfSender = MyName; /* tell him who sent it */
message.text = msgstring; /* our text string to send*/
PutMsg(HisPort,&message); /* send the message */
WaitPort(MyPort); /* wait for reply */
GetMsg(MyPort); /* remove reply from port */
Print("<Got acknowledgement from "); /* tell user we got reply */
Print(name);
Print(">\n");
}
}
/* SearchChar(string,chr,n) *********************************************
* find character `chr' in `string', searching up to n characters
* return n if character not found
*/
SearchChar(string,chr,n)
char *string;
int chr, n;
{
int i;
for(i=0;i<n&&string[i]!=chr;i++)
;
return(i);
}
/* HowMany() ***********************************************************
* Determines how many `talking tasks' are currently in the system. Look for
* aport named TTportName (Joe's Cafe). If it exists, get a `CountMsg'
* message from it, read the count, increment it and put the message back. If
* the port doesn't exist, create it and put a message there with the count
* field set to zero. Return the value of the count.
*/
HowMany()
{
int count;
if(TTport = FindPort(TTportName))
{
TTmsg = (struct CountMsg *)GetMsg(TTport); /* get message... */
count = ++TTmsg->Count; /* bump count... */
PutMsg(TTport,TTmsg); /* and put it back*/
}
else
{ /* port not there, we are first talking task - create the port */
TTport=(struct MsgPort *)AllocMem((ULONG)sizeof(*TTport),MEMF_PUBLIC);
TTport->mp_Node.ln_Name = (char *)
AllocMem((ULONG)(strlen(TTportName)+1),MEMF_PUBLIC);
strcpy(TTport->mp_Node.ln_Name,TTportName);
TTport->mp_Node.ln_Pri = 0;
TTport->mp_Node.ln_Type = NT_MSGPORT;
TTport->mp_Flags = PA_IGNORE;
AddPort(TTport); /* make the port public so all tasks have access */
/* now create the message to put in the port (Joe's Cafe) */
TTmsg=(struct CountMsg *)AllocMem((ULONG)sizeof(*TTmsg),MEMF_PUBLIC);
TTmsg->Msg.mn_Node.ln_Type = NT_MESSAGE; /* for Exec list handling */
TTmsg->Msg.mn_Length = sizeof(*TTmsg); /* number of byte in msg */
TTmsg->Msg.mn_ReplyPort = NULL; /* no reply port required */
TTmsg->Count = count = 0; /* start count at zero */
PutMsg(TTport,TTmsg); /* leave a message at Joe's Cafe for everyone */
}
return count;
}
/********* end of ttasks.c ********************************************/