home *** CD-ROM | disk | FTP | other *** search
-
- /* `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 ********************************************/
-