[alt.sources.amiga] ipc.demosrc -- Source to Lattice IPC demo program.

amiga-sources@sugar.uu.net (alt.sources.amiga) (09/11/88)

Archive: uunet!~uucp/amiga-sources/ipc.demosrc.Z

:
#! /bin/sh
# This is a shell archive, created on Sugar Land Unix (..!uunet!sugar)
# by amiga-sources (alt.sources.amiga) on Sun Sep 11 08:21:57 1988
# Remove anything before the "#! /bin/sh" line, then unpack it by saving
# it into a file and typing "sh file".  If you do not have sh, you need 
# unshar, a dearchiving program which is widely available.  In the absolute
# wost case, you can crack the files out by hand.
# If the archive is complete, you will see the message "End of archive."
# at the end.
# This archive contains the following files...
# 'READ_ME'
# 'Pserver.doc'
# 'Pserver.c'
# 'MinClient.doc'
# 'MinClient.c'
# 'IPC.h'
# 'Pserver.lnk'
# 'MinClient.lnk'
# To extract them, run the following through /bin/sh
echo x - READ_ME
sed 's/^X//' > READ_ME << '//END_OF_FILE'
X
X                            IPC Demo Sources
X                            ================
X
XThis directory contains source files for a Print Formatting Server
X("Pserver"), and a very dumb Client program to test it ("MinClient").
XBoth of these sources are heavily commented, and are intended as
Xdemonstrations of how to use the IPC protocols.
X
XInclude header file:
X
X    IPC.h   -- a copy of the file from IPC_Sources, for convenience.
X
X
XSource Files:
X
X    Pserver.c
X    MinClient.c
X
X
XLink Files (for BLink):
X
X    Pserver.lnk
X    MinClient.lnk
X
XDocumentation:
X
X    Pserver.doc --  A detailed description of the message format accepted
X                    by Pserver, and the requirements for using it.
X
X    MinClient.doc   --  A short description of the test program and its
X                        commands.
X
X
X                            ++++++++++++++
X
XCompatibility:
X
X    These programs have only been tested under Lattice 4.0.  They will need
X    some conversion (ensuring LONGS are used where necessary, and so on)
X    for compilation under Manx.
X
X
XNotes:
X
X    These programs have been written to reduce space as much as possible:
X    they use '_main()' rather than main(), for instance, and don't use
X    C level I/O -- just AmigaDOS calls.  They should be compiled using the
X    Lattice -v switch, to reduce space a little more, and there may be
X    other measures that could be taken.
X
X    This means that they CANNOT be invoked directly from an icon in their
X    present form -- only from a CLI.  AS they need to run simultaneously
X    (!) they must either be started from their own CLI, or with the RUN
X    command (remembering that they both can generate console output).
X
X    You can use an Xicon script to set them both going in a suitable
X    environment (as in the demo icon on this disk), but there are TRAPS!
X    These seem to be due to a bug in RUN, which has problems when it is
X    invoked from an AmigaDOS Execute() call: you MUST redirect the output
X    of RUN ITSELF to NIL: to avoid Guruing.  For example:
X
X        RUN >NIL: Pserver >"CON:100/50/450/100/Pserver Output"
X
X    [This is nothing to do with IPC -- it is a general problem Xicon has
X    with AmigaDOS -- as far as I can tell, it's the systems fault (:-))]
X    See the script for the demo for more details.
X
X
//END_OF_FILE
echo x - Pserver.doc
sed 's/^X//' > Pserver.doc << '//END_OF_FILE'
X
X                              Pserver
X                              _______
X
X                 Formatted output IPC Server Module
X
X
XThis program is a Server for IPC that both provides a demonstration of
Xtechnique and has a useful function.  It accepts a message containing
Xnumeric, character and string items, together with appropriate
Xformat-specifying items, and generates a formatted output string.  This
Xstring may be sent to the server's own console window, or may be returned
Xto the client, or may be written to a supplied file handle.
X
XThis server avoids each module having to have its own output mechanisms.
XIn a lot of cases -- error messages and so on -- it will probably  be
Xconvenient to send reports (suitably tagged with an identifying string) to
Xthe common Pserver window.  Where a module does need its own window it
Xstill does not have to be burdened with the space needed for 'printf' if it
Xuses this server.
X
XThe IPCPort served by this module is named "Print_Format".  Only one
XIPCMessage ID ('CNVA'), as described below, is handled by this version
X(except for 'QUIT'), but there can be many variations on the items
Xincluded, to determine the contents, format, and destination of the output
Xstring.
X
XThe server will run until either it is sent a 'QUIT' message by any client,
Xor the number of current clients drops to zero (from non-zero, so that it
Xdoesn't terminate if there are initially no clients).  It will also
Xterminate immediately if the user gives the process a ctrl-C break.
X
X
XMessage Format:
X
XThe IPCMessage Type ID accepted by Pserver is 'CNVA' ("CoNVert to Ascii").
XIt may contain an arbitrary number of items.  Optionally, the first may be
Xa "disposition control" item (see below); if it is absent, the formatted
Xstring will be displayed in the Pserver console window.
X
XItems to be formatted may be of the following types:
X
X    INTG    -- ii_Ptr contains a 32-bit integer value to be converted to
X               its ASCII representation (ii_Size = 0).
X
X    REAL    -- ii_Ptr contains a 32-bit floating-point value to be
X               converted (ii_Size = 0).  (Note -- care will be needed
X               when inserting the original 'float' value into ii_Ptr, to
X               make sure that the compiler doesn't apply an unintended
X               conversion!  Pserver converts the supplied value to 'double'
X               and uses the "%g" format to output it.)
X
X    STRG
X    LINE
X    TEXT    -- equivalent IDs representing ASCII strings to be inserted in
X               the output.  (Although Pserver treats them equivalently,
X               they may have different meanings in other environments: in
X               particular, LINE is a conplete single line of text without its
X               terminating newline, TEXT is an arbitrary block of text that
X               may contain newline characters, and STRG is possibly a
X               partial line.)
X
X    CHAR    -- A single ASCII character (in the least-significant byte of
X               ii_Ptr; ii_Size = 0).
X
X
XIf no format-specifying items are supplied, default formats are used ("%ld"
Xfor integer, "%g" for floats (cast to double by Pserver), "%s" for strings,
Xand "%c" for characters).  For further control, you can either prefix an
Xitem with a single-item format string, or include a multi-item format
Xspecification.
X
X    PAT1    -- ii_Ptr points to a "printf" type format string containing
X               exactly one conversion specifier, which must be appropriate
X               for the immediately following item.  Aside from the single
X               specifier that must be present, the contents of the string
X               are arbitrary.
X
X    PATS    -- ii_Ptr points to a format string that contains conversion
X               specifiers for ALL the remaining items in the message; no
X               other format or extraneous item may appear after this. There
X               is no check that the number of items matches the number of
X               specifiers; any unmatched items won't be converted; extra
X               specifiers will produce garbage.
X               There is one restriction on this form: REAL items cannot
X               be included (because there is no easy way to do the
X               conversion to double on individual items of a set -- all
X               other types are passed as 32-bit quantities); use PAT1
X               instead, which does not have this restriction.
X
XAs stated earlier, by default the converted string is displayed in the
XPserver window, but if the first item is one of the following the
Xdestination will be changed appropriately.
X
X    RETS    -- (RETurn String) When the message is replied to the client
X               (successfully), this item will contain a pointer to a data
X               block containing the converted string.  The client can
X               select one of two possible options for the source of this
X               data block: a) if the original message contains a non-NULL
X               ii_Ptr value, the converted string will be placed at that
X               address, PROVIDED that the supplied value of ii_Size is
X               large enough to hold it; otherwise the item will be flagged
X               IPC_FAILED | IPC_NOTKNOWN and no conversion will be done;
X               b) if the supplied ii_Ptr value is NULL, a suitably large
X               block of memory will be allocated for the string; the item
X               will be flagged IPC_TRANSFER to indicate that the Client
X               MUST dispose of the memory block when done.
X
X
X    FILH    -- (FILe Handle) If present, this must have a valid AmigaDOS
X               file handle in ii_Ptr (ii_Size = 0).  The converted string
X               will be written to this file (which might for instance be
X               the Client's Output() console or file).  (Note that under
X               AmigaDOS multiple processes can write to a single file
X               handle without problems; the system takes care of locking.)
X
XIt is possible for both RETS and FILH itmes to be included in the message,
Xin which case both paths will be used; if either is present, no output ever
Xis sent to the Pserver window. There cannot be more than one of each kind
Xof item, though.  It is actually not necessary that they be the first
Xitems, but that is the preferred position for clarity.
X
XAny item Ids other than those mentioned above will be ignored, UNLESS they
Xappear in positions following a format item (PAT1 or PATS) where a value is
Xexpected, in which case an error will be flagged and no conversion will be
Xperformed.
X
X
XExample:
X
XA message sent to Pserver containing
X
X    ipc_Id          CNVA
X    ipc_ItemCount   4
X
X    item 1  ii_Id       RETS
X            ii_Size     0       (will be set to block size on return)
X            ii_Ptr      NULL    (will point to data block on return)
X
X    item 2  ii_Id       PAT1
X            ii_Size     0       (indicates MYOB to server)
X            ii_Ptr      pointer to string "Test line #%3d "
X
X    item 3  ii_Id       INTG
X            ii_Size     0
X            ii_Ptr      1       (some integer value)
X
X    item 4  ii_Id       STRG
X            ii_Size     0
X            ii_Ptr      pointer to string "...that's it\n"
X
Xwould return
X
X    "Test line #  1 ...that's it"
X
Xto the client.
X
XNote the use of 0 values for string sizes; this is permissible where the
Xpointer is to a client-owned area of memory that the server must not alter;
Xthe size field WOULD be necessary if the item was being passed to a more
Xgeneral server, or the server was to take over management of the item --
Xthen of course the block would also have to be in public memory.  The
Xii_Size field in any case does NOT represent the length of the string
Xitself: if non-zero it would represent the data-block containing the
Xstring, which could be considerably bigger that the string.
X
X
//END_OF_FILE
echo x - Pserver.c
sed 's/^X//' > Pserver.c << '//END_OF_FILE'
X/************************************************************
X *                                                          *
X *         Print Formatting Server (demo) for IPC           *
X *                                                          *
X *               Pete Goodeve 88:7:25                       *
X *                                                          *
X *  [This module has only been compiled under Lattice;      *
X *   it will need some modification for Manx/Aztec]         *
X *                                                          *
X *                                                          *
X *  This is a server to handle 'printf' conversion of       *
X *  int, float, string, and char valued message items.      *
X *  This saves space in other IPC modules that have a       *
X *  need for text output.  A single message results in      *
X *  a single output string, but there can be any number     *
X *  of items in the message, converted in sequence to       *
X *  ASCII -- either under the control of format specifier   *
X *  items, or in default format if these are omitted.       *
X *                                                          *
X *  The output string will by default be displayed in       *
X *  the server's window (thus other modules need not have   *
X *  their own).  Optional message items will redirect       *
X *  the output either to a supplied file handle (FILH) or   *
X *  to be returned as an item in the reply message (RETS).  *
X *                                                          *
X *  Only one message ID (aside from QUIT) is recognized     *
X *  by this server: CNVA ("CoNVert to Ascii").  See below   *
X *  for item IDs.  The program will terminate when it       *
X *  receives a QUIT message (items ignored), or when        *
X *  the number of clients drops from non-zero to zero       *
X *  (in other words it will not exit if there are initially *
X *  no clients).  It will also quit if it is sent a         *
X *  cntrl-C break.                                          *
X *                                                          *
X *                                                          *
X *  This is currently a completely "synchronous" server;    *
X *  it processes each message completely before returning   *
X *  it, and doesn't attempt to handle more than one at a    *
X *  time.  It doesn't send out any messages of its own      *
X *  either (i.e. it isn't a "manager"), but for the         *
X *  purpose of illustration some dummy manager type code    *
X *  has been included in the main loop, so you can see      *
X *  the sort of extensions that would be needed for that.   *
X *  The procreply() procedure -- here a dummy -- would      *
X *  have to dispatch each reply message that arrived to     *
X *  a suitable close-out procedure, then dispose of the     *
X *  message and any associated memory.                      *
X *                                                          *
X ************************************************************/
X
X#ifdef DEBUG /* set this to show messages being received and so on */
X#include "stdio.h"
X#endif
X
X#include "IPC.h"
X
X#include "exec/memory.h"
X#include "libraries/dos.h"
X
X/*
X *  Define the ID codes recognized by the print format server
X *
X *  (MAKE_ID is defined in IPC.h)
X */
X
X/* Message IDs: */
X#define CNVA  MAKE_ID('C','N','V','A')
X    /* CoNVert to Ascii */
X#define QUIT  MAKE_ID('Q','U','I','T')
X
X/* Item IDs: */
X#define RETS  MAKE_ID('R','E','T','S')
X    /* RETurn String */
X
X#define FILH  MAKE_ID('F','I','L','H')
X    /* FILe Handle */
X
X
X#define PATS  MAKE_ID('P','A','T','S')
X    /* PATtern String */
X    /* NOTE: the total formatted length for a PATS item
X       must not be longer than 255 characters, to avoid crashing! */
X
X#define PAT1  MAKE_ID('P','A','T','1')
X    /* PATtern -- 1 item */
X    /* NOTE: the total formatted length for a single PAT1 item
X       must not be longer than 65 characters, to avoid crashing! */
X
X#define LINE  MAKE_ID('L','I','N','E')
X    /* indicates a complete line of text -- omitting newline */
X
X#define TEXT  MAKE_ID('T','E','X','T')
X    /* Text block -- may include newlines */
X
X#define STRG  MAKE_ID('S','T','R','G')
X    /* general non-specific ASCII STRinG */
X
X    /* The above three categories are treated identically by Pserver
X       -- they may have distinct meanings to other servers */
X
X#define CHAR  MAKE_ID('C','H','A','R')
X    /* A single character in L.S byte of ii_Ptr */
X
X#define INTG  MAKE_ID('I','N','T','G')
X    /* A 32-bit INTeGer in ii_Ptr */
X
X#define REAL  MAKE_ID('R','E','A','L')
X    /* A 32-bit floating point value in ii_Ptr (care in conversion!) */
X
X
X/*******************
Xrather than the above if you prefer, with Lattice 4.0 you can simply
Xuse 4-character constants as in the following (compile with the -cm option):
X
X#define CNVA 'CNVA'
X#define QUIT 'QUIT'
X
X#define RETS 'RETS'
X#define FILH 'FILH'
X
X#define PATS 'PATS'
X#define PAT1 'PAT1'
X#define LINE 'LINE'
X#define TEXT 'TEXT'
X#define STRG 'STRG'
X#define CHAR 'CHAR'
X#define INTG 'INTG'
X#define REAL 'REAL'
X*********************/
X
X
X
Xstruct IPCPort *import=NULL; /* this is the port we serve */
X
Xstruct IPCMessage *imsg=NULL; /* we only handle one message at a time,
X                                 so a global pointer is useful */
X
Xstruct MsgPort *report=NULL; /* reply port: not actually  used here
X                                -- skeleton code is shown */
X
X/* should really include proto.h now for system procedures (next time...) */
Xchar * AllocMem(int, ULONG);
Xvoid FreeMem(char *, int);
Xstruct MsgPort * CreatePort(char *, int);
Xstruct Message * Getmsg(struct MsgPort *);
X
Xvoid Cleanup();
Xvoid clearmarkers();
Xvoid outputstr(char *);
Xvoid procline();
Xvoid baditem(struct IPCItem *, ULONG);
X
X
Xint active = TRUE, /* when this goes FALSE, it's time to quit */
X    replies = 0; /* number of replies to get back (...if we got replies!) */
X
XULONG reportsig = 0,  /* signal masks for ports */
X      importsig = 0;
X
XULONG outputhnd; /* file handle from message (if any) will be held here */
Xstruct IPCItem *retitem; /* item to contain return string (if any) */
X
Xint total_length, /* length computed for output string in pre-scan */
X    alloc_length; /* length of allocated block (if any)  -- acts as flag */
X
Xchar *linebuf, *bufptr; /* pointers (fixed and moveable) to output string */
X
Xint mesg_bad; /* flag to prevent further processing if a bad item found */
X              /* (note that extraneous items are mostly just ignored) */
X
X
X/***************************
X *
X *  Main program entry point:
X *
X *  -- Note that to save overhead we use '_main'; you should also compile
X *  (under Lattice) using the -v switch, to suppress stack checking and
X *  the associated baggage.
X *
X *  We avoid using any C level I/O also -- just AmigaDOS calls, so we
X *  dont need <stdio.h>.
X */
X
Xvoid _main()
X{
X    int clients, oldclients = 0;
X                   /* keeps track of number of current clients */
X    ULONG sigset;  /* set to signals that woke up Wait() */
X
X#ifdef TRACKCLIENTS /* define this to display current number of clients */
X    char clrepstr[16];
X#endif
X
X    report = CreatePort(NULL,0); /* I repeat... this is just a dummy here */
X    if (!report) {
X        outputstr("no space!!");
X        Cleanup();
X        return;
X    }
X    import = ServeIPCPort("Print_Format");
X    if (!import) {
X        outputstr("Print Server already exists ... exiting");
X        Cleanup();
X        return;
X    }
X    /* Get the signal bits for each port for later convenience: */
X    /* (Note that, because we did not include IPCPorts.h, IPCPorts
X        are identical to MsgPorts as far as the user is concerned;
X        if we DID need IPCPorts.h, these statements would have to
X        be changed appropriately.) */
X    reportsig = 1<<report->mp_SigBit;
X    importsig = 1<<import->mp_SigBit;
X
X#ifdef DEBUG
X    setnbf(stdout); /* so we can see output! (unbuffered) */
X#endif
X
X
X    /*
X     *  The main loop:
X     *  -- first we process any outstanding messages, looping until
X     *  no more are found (procreply() always fails -- there are no
X     *  replies in this program!).
X     *  -- then we check the number of current clients: if they have
X     *  all gone, we will exit.
X     */
X    do {
X        while ( procimsg() || procreply()) ;  /* loop to satisfy messages */
X
X        /*
X         *  look at the number of clients (optional code included to display
X         *  this).  The number returned by CheckIPCPort includes the server,
X         *  so for convenience we subtract 1.
X         *  Note that we set IPP_NOTIFY, so the process gets woken up each
X         *  time the number of clients changes.
X         */
X        if ((clients = CheckIPCPort(import, IPP_NOTIFY) - 1)
X                   != oldclients) {
X#ifdef TRACKCLIENTS /* for demonstration purposes... */
X            sprintf(clrepstr,
X                    (clients == 1? "1 client\n" : "%d clients\n"), clients);
X            outputstr(clrepstr);
X#endif
X            if (!clients) {
X                active = FALSE; /* quit if everyone gone */
X                ShutIPCPort(import); /* note: multiple calls don't hurt! */
X                continue; /* so we clear out any messages that sneak in */
X            }
X            oldclients = clients;
X        }
X
X        /*
X         *  Now wait for further messages, unless 'active' is FALSE
X         *  ('replies' is always FALSE in this program).
X         */
X        if (active | replies) {
X            /* Note that Wait() must be used rather than WaitPort()
X               if we want to wake up on IPP_NOTIFY as well as messages */
X            sigset = Wait(importsig | reportsig | SIGBREAKF_CTRL_C);
X            if (sigset & SIGBREAKF_CTRL_C) {
X                active = FALSE;
X                ShutIPCPort(import); /* note: multiple calls don't hurt! */
X                continue; /* so we clear out any messages that sneak in */
X            }
X        }
X    } while (active | replies);
X    /*** end of main loop ***/
X
X    outputstr("Pserver terminating...\n");
X
X    Cleanup();
X}
X/*** end of _main ***/
X
X
Xvoid Cleanup()
X{
X    if (import) LeaveIPCPort(import);
X    if (report) DeletePort(report);
X}
X
X
Xint itemn;  /* global item counter */
Xstruct IPCItem *curitem; /* global item pointer */
X
X
X/*
X *  Process incoming messages
X *  -- returns FALSE if there are none, otherwise TRUE.
X *  It recognizes the message ID and invokes the appropriate
X *  handling procedures.
X */
Xprocimsg()
X{
X    if (!(imsg = (struct IPCMessage *) GetMsg(import))) return FALSE;
X#ifdef DEBUG
X    printf("item count = %d\n", imsg->ipc_ItemCount);
X#endif
X    switch (imsg->ipc_Id) {
X       case CNVA:
X               /*
X                *   First do a scan of the message to determine how
X                *   big a string space will be needed
X                *   (and check for bad items):
X                */
X               curitem = imsg->ipc_Items; /* initialize the item pointer */
X               for (itemn=imsg->ipc_ItemCount;
X                    itemn && scanitem(); curitem++, itemn-- ) /* loop */;
X
X               if (mesg_bad) break;
X
X               /*
X                *   Allocate the space needed:
X                */
X               if (!allocline()) break;
X
X               /*
X                *   Now actually process the items in the message:
X                */
X               curitem = imsg->ipc_Items; /* reset again */
X               for (itemn=imsg->ipc_ItemCount;
X                    itemn && procitem(); curitem++, itemn-- ) /* loop */;
X
X               /*
X                *   Finally terminate the output string and handle
X                *   it as directed:
X                */
X               procline();
X               break; /* end of CNVA processing */
X
X       case QUIT:
X               active = FALSE;
X               ShutIPCPort(import);
X               outputstr("Pserver got QUIT message...");
X               break;
X
X       default:
X#ifdef DEBUG
X               outputstr("got bad message");
X#endif
X               imsg->ipc_Flags |= IPC_NOTKNOWN;
X               break;
X    }
X
X    if (mesg_bad)
X        imsg->ipc_Flags |= IPC_NOTKNOWN | IPC_FAILED;
X    ReplyMsg(imsg);
X    clearmarkers(); /* reset things for the next message */
X    return TRUE;
X}
X
X
X/*
X *  Skeleton procedure for handling replies (of which there are none
X *  in this program...).
X */
Xprocreply()
X{
X    struct IPCMessage *rpmsg;
X    struct IPCItem *item;
X
X    if (!(rpmsg = (struct IPCMessage *)GetMsg(report))) return FALSE;
X    if (rpmsg->ipc_Flags & IPC_NOTKNOWN) {
X#ifdef DEBUG
X        outputstr("\nServer didn't like this message...");
X#endif
X    }
X    item = rpmsg->ipc_Items;
X    /* message deletion and so on would go here... */
X    replies--; /* This variable is incremented for each original message
X                  generated by this program; the program will not exit
X                  as long as it is non-zero */
X    return TRUE;
X}
X
X
X/*
X *  Reset all global variables ready for next incoming message
X */
Xvoid clearmarkers()
X{
X    if (alloc_length) FreeMem(linebuf, alloc_length);
X    linebuf = NULL;
X    alloc_length = 0;
X    total_length = 0;
X    retitem = NULL;
X    outputhnd = NULL;
X    mesg_bad = FALSE;
X}
X
X
X/*
X *  Scan the current item to determine length of string it will generate.
X *  It also recognizes disposition control items (RETS, FILH) and sets up
X *  the required pointers.
X *  Subprocedures called may also check validity of item to be formatted
X *  (extraneous items not following a format specifier are simply ignored.)
X */
Xscanitem()
X{
X    char dummy[66]; /* this should be enough (!) */
X
X#ifdef DEBUG
X    debugitem(curitem,"scanitem:");
X#endif
X
X            switch (curitem->ii_Id) {
X        case RETS:
X                retitem = curitem;
X                break;
X        case FILH:
X                outputhnd = (ULONG)curitem->ii_Ptr;
X                break;
X        case PATS:
X                total_length += scanpatstring();
X                return FALSE;   /* stop here */
X        case PAT1:
X                total_length += patternitem(dummy);
X                break;
X        case LINE:
X        case TEXT:
X        case STRG:
X                total_length += strlen(curitem->ii_Ptr);
X                break;
X        case CHAR:
X                total_length++;
X                break;
X        case INTG:
X                total_length += cnvtitem(dummy, "%ld", curitem);
X                break;
X        case REAL:
X                total_length += cnvtitem(dummy, "%g", curitem);
X                break;
X
X        default:
X#ifdef DEBUG
X                outputstr("got unknown item");
X#endif
X                /* ignore extraneous stuff */
X            }
X        return (!mesg_bad); /* stops here if message has failed */
X}
X
X
X/*
X *  Allocate space for complete output string.
X *  -- if the message has supplied a NON-NULL ii_Ptr in a RETS item,
X *  this will be used as the buffer, as long as the associated ii_Size
X *  is large enough (if it is not, the message will fail).  Otherwise
X *  space is allocated for the buffer.  If a NULL RETS item has been
X *  supplied, the buffer pointer will be returned there (otherwise the
X *  buffer will be freed again after output).
X *  It will of course also fail if there is no space for a buffer.
X *  Any failure returns FALSE, otherwise TRUE.
X */
Xallocline()
X{
X    int adj_length = total_length + 1; /* allow for terminator */
X    if (retitem) { /* check for a RETS item first */
X        if (retitem->ii_Ptr) { /* buffer supplied? */
X            if (retitem->ii_Size > total_length) { /* big enough ? */
X                linebuf = (char *)retitem->ii_Ptr; /* yes -- use it */
X            }
X            else { /* too small */
X                baditem(retitem, IPC_FAILED);
X                return FALSE;
X            }
X        }
X        else { /* NULL pointer, so create some space */
X            linebuf = AllocMem(adj_length, MEMF_PUBLIC);
X            if (!linebuf) {
X                baditem(retitem, IPC_FAILED);
X                return FALSE;
X            }
X            else {
X                retitem->ii_Ptr = (void *)linebuf;
X                retitem->ii_Size = adj_length;
X                retitem->ii_Flags = IPC_TRANSFER | IPC_MODIFIED;
X                    /* flags are set to indicate client must dispose
X                       of this block */
X            }
X        }
X    }
X    else { /* no RETS item, so use local buffer */
X        linebuf = AllocMem(adj_length, MEMF_PUBLIC);
X        if (!linebuf) {
X            imsg->ipc_Flags |= IPC_NOTKNOWN | IPC_FAILED;
X            return FALSE;
X        }
X        alloc_length = adj_length; /* used to free the message afterward */
X    }
X    bufptr = linebuf; /* initialize the output pointer */
X    return TRUE;
X}
X
X
X/*
X *  Write the ASCII string for the current item to the output buffer.
X *  A suitable default format is used for items with no preceding
X *  format specifier.
X */
Xprocitem()
X{
X
X#ifdef DEBUG
X    debugitem(curitem,"procitem:");
X#endif
X            switch (curitem->ii_Id) {
X        case RETS:
X        case FILH:
X                break;
X        case PATS:
X                bufptr +=cnvtpatstring(bufptr);
X                return FALSE;  /* no further items allowed */
X        case PAT1:
X                bufptr += patternitem(bufptr);
X                break;
X        case LINE:
X        case TEXT:
X        case STRG:
X                strcpy(bufptr, curitem->ii_Ptr);
X                bufptr += strlen(curitem->ii_Ptr);
X                break;
X        case CHAR:
X                *bufptr++ = (char) (curitem->ii_Ptr);
X                    /* Lattice gives a warning here but does it OK */
X                break;
X        case INTG:
X                bufptr += cnvtitem(bufptr, "%ld", curitem);
X                break;
X        case REAL:
X                bufptr += cnvtitem(bufptr, "%g", curitem);
X                break;
X
X        default:
X                /* ignore */
X            }
X        return TRUE;
X}
X
X
X/*
X *  Determine length (and validity) of multi-item format specifier
X */
Xscanpatstring()
X{
X    char *dummy;
X    int len;
X    dummy = AllocMem(256, 0L); /* temporary local storage */
X    if (!dummy)
X        return 256;  /* let allocline fail instead ! */
X    len = cnvtpatstring(dummy);
X    FreeMem(dummy, 256);
X    return len;
X}
X
X
X/*
X *  Use the format in a PAT1 item to convert the following item.
X *  (Simply calls cnvtitem with suitable arguments.)
X */
Xpatternitem(destptr)
Xchar *destptr;
X{
X    char *fmtp;
X    if (--itemn) {
X        fmtp = (char *)curitem->ii_Ptr;
X        return cnvtitem(destptr, fmtp, ++curitem);
X    }
X    else {
X        baditem(curitem, IPC_FAILED);
X        mesg_bad = TRUE;
X        return 0;
X    }
X}
X
X
X/*
X *  Convert a single value (in the current item) according to the
X *  format specified.  Output is to destptr; the size of the resulting
X *  string is returned.
X */
Xcnvtitem(destptr, fmtstr, item)
Xchar *destptr, *fmtstr;
Xstruct IPCItem *item;
X{
X    double doubleval;
X    int len;
X
X#ifdef DEBUG
X    debugitem(item,"cnvtitem:");
X#endif
X
X            switch (item->ii_Id) { /* handle according to type */
X        case LINE:
X        case TEXT:
X        case STRG:
X                len = sprintf(destptr, fmtstr, item->ii_Ptr);
X                break;
X        case CHAR:
X                len = sprintf(destptr, fmtstr, item->ii_Ptr);
X                break;
X        case INTG:
X                len = sprintf(destptr, fmtstr, item->ii_Ptr);
X                break;
X        case REAL:
X                doubleval = *(float *) &item->ii_Ptr;
X                len = sprintf(destptr, fmtstr, doubleval);
X                break;
X
X        default:
X                baditem(item, IPC_FAILED);
X                mesg_bad = TRUE;
X            }
X        return len;
X}
X
X
X/*
X *  Convert items to ASCII according to format pattern in the current item.
X *  All the remaining items in the message must be values to satisfy the
X *  pattern.  (Note that REAL items aren't allowed, because they can't be
X *  passed to sprintf as 32-bit values).  Up to 10 items can be handled.
X *  The total length of the formatted string is returned.
X */
Xcnvtpatstring(destptr)
Xchar *destptr; /* destination string buffer */
X{
X    char *fmtp;
X    int i;
X     ULONG p[10]; /* Storage for 10 values */
X
X    fmtp = (char *)curitem->ii_Ptr; /* hold pointer to pattern string */
X    for (i=0; i<10 && --itemn; i++ ) { /* process all the remaining items */
X        ++curitem;
X#ifdef DEBUG
X    debugitem(curitem,"patstring:");
X#endif
X        switch (curitem->ii_Id) { /* everything the same except REAL */
X        case LINE:
X        case TEXT:
X        case STRG:
X        case CHAR:
X        case INTG:
X                p[i] = (ULONG)curitem->ii_Ptr; /* local copy */
X                break;
X        case REAL: /* can't pass a double this way!! */
X        default:
X                baditem(curitem, IPC_FAILED);
X                mesg_bad = TRUE; /* can't continue */
X                return 0;
X        }
X    }
X    if (itemn) { /* more than 10 items found */
X        baditem(++curitem, IPC_FAILED);
X        mesg_bad = TRUE;
X        return 0;
X    }
X    while (i<10) p[i++] = (ULONG) "\0"; /* not very adequate protection */
X
X    /* Fortunately C allows us to pass unused arguments: */
X    return sprintf(destptr, fmtp,
X           p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9]);
X}
X
X
X/*
X *  Process the assembled output string
X *  -- if the output handle has been supplied, the string will be sent there;
X *  if neither handle nor return slot has been supplied, the string will
X *  be output to the server's window.
X *  (If a return slot is present in the message, the string will be returned
X *  there in any case.)
X */
Xvoid procline()
X{
X    *bufptr = '\0'; /* Terminate the string first */
X    if (outputhnd) Write(outputhnd, linebuf, total_length);
X    else if (!retitem)
X         Write(Output(), linebuf, total_length);
X}
X
X
X/*
X * Set error flags in an item and the message
X * (Note that this doesn't abort processing -- if this is needed,
X * the mesg_bad flag should also be set)
X */
Xvoid baditem(item, extraflags)
X    struct IPCItem *item;
X    ULONG extraflags;
X{
X    imsg->ipc_Flags |= IPC_CHECKITEM;
X    item->ii_Flags |= IPC_NOTKNOWN | extraflags;
X#ifdef DEBUG
X    debugitem(item, "BAD:");
X#endif
X}
X
X
X/* procedure to display string in window (avoids C I/O overhead) */
X
Xvoid outputstr(str) char *str;
X{
X    Write(Output(), str, strlen(str));
X}
X
X/************************************************************?
X
X/* the following is only included if you want debugging output: */
X#ifdef DEBUG
Xdebugitem(item, str)
X    struct IPCItem *item;
X    char *str;
X{
X    ULONG icode[2];
X    icode[0] = item->ii_Id;
X    icode[1] = 0;
X    printf("%s item %d code %s [%x] ptr %x flagged %x\n",
X           str, item - imsg->ipc_Items,
X           icode, *icode,
X           item->ii_Ptr, item->ii_Flags);
X}
X#endif
X
X
//END_OF_FILE
echo x - MinClient.doc
sed 's/^X//' > MinClient.doc << '//END_OF_FILE'
X
X                     Minimal Test Client for Pserver
X                     ===============================
X
XThis is a really stupid little test and demonstration program that sends
Xmessages packed with different kinds of data to Pserver for formatting.
XThese is little variety to the messages -- they just increment a count or
Xtwo each time -- and you have no control over their content.  I expect
Xthere to be more satisfying uses of Pserver than this.
X
XThe program requires a console for both input and output, so it is probably
Xbest started in a CLI of its own (or you can use separate redirected
Xwindows for input and output).  For proper operation of course you must
Xalso have Pserver running (with its own output window) before you try to
Xsend a message.  (MinClient will inform you if it isn't.)  Of course there
Xis no problem in running several copies of MinClient.
X
XEach time you type the return key in its console, MinClient sends a message
Xto Pserver for formatting.  If you just type a return, the output will
Xappear in the server's window, but you can redirect it back to your own via
Xtwo paths, by typing a selection character before the return.  If you type
X"f<return>" ("File"), Pserver will be passed the file handle of MinClient's
XOWN console, and the output will appear there instead.  If you type
X"m<return>" ("Message"), it will be requested to pass the output string
Xback to MinClient -- to do with as it will.  What it actually does is just
Xdisplay it in this case.  (Other characters will do the same job -- see the
Xsource; this is simply because I was used to them from another context.)
X
XYou can send a 'QUIT' message to Pserver by "q<return>" (leaving MinClient
Xrunning).  Pserver will also quit if all copies of MinClient (or any other
Xclients using port "Print_Format") exit.  (You can start Pserver first,
Xthough, and it WILL wait around until a client shows up.)
X
XFor more details on the workings of Pserver and MinClient, please refer
Xdirectly to the sources.  Their operation is heavily commented.
X
X                            ++++++++++++++++
X
//END_OF_FILE
echo x - MinClient.c
sed 's/^X//' > MinClient.c << '//END_OF_FILE'
X/************************************************************
X *                                                          *
X *        Minimal Print server Client Demo for IPC          *
X *                                                          *
X *                Pete Goodeve 88:7:25                      *
X *                                                          *
X *  [This module has only been compiled under Lattice;      *
X *   it will need some modification for Manx/Aztec]         *
X *                                                          *
X *                                                          *
X *  This is a simple test module for the "Print Format"     *
X *  server.  When you type the return key, it generates     *
X *  a message with a set of items in various formats,       *
X *  and sends it to the print server. (For test purposes    *
X *  the items are fixed.)  If you simply type a return,     *
X *  the formatted string generated from the message is      *
X *  displayed in the print server's own window; if you      *
X *  type an 'F' before the return, a file handle to this    *
X *  Client program's console window is passed in the        *
X *  message and the string will be output to this instead;  *
X *  if you type an 'M' before the return, the string will   *
X *  be passed back in the reply message and again shown     *
X *  in the Client's console window.                         *
X *                                                          *
X *  Typing 'Q' will send a 'QUIT' message to the server     *
X *  instead of a print request.  To exit the client         *
X *  program type an 'end-of-file' (cntrl-'\'); the          *
X *  print server is currently programmed to exit also       *
X *  when there are no running clients left.                 *
X *                                                          *
X *  It is a simple "synchronous" client: when it sends a    *
X *  message it waits for the reply before continuing        *
X *  (unlike others that may continue with other activities  *
X *  while the server is processing a message).  The main    *
X *  loop is simple:                                         *
X *                                                          *
X *          Wait for keyboard command                       *
X *          Send message                                    *
X *          Wait for reply                                  *
X *          Display string from reply if supplied           *
X *          Loop to wait for keyboard again.                *
X *                                                          *
X *                                                          *
X ************************************************************/
X
X#include "IPC.h"
X#include "exec/memory.h"
X
X#define LINESZ 120
X#define SHOWREAL 1
X
X/*
X *  Define the ID codes recognized by the print format server
X *
X *  (MAKE_ID is defined in IPC.h)
X */
X
X/* Message IDs: */
X#define CNVA  MAKE_ID('C','N','V','A')
X    /* CoNVert to Ascii */
X#define QUIT  MAKE_ID('Q','U','I','T')
X
X/* Item IDs: */
X#define RETS  MAKE_ID('R','E','T','S')
X    /* RETurn String */
X
X#define FILH  MAKE_ID('F','I','L','H')
X    /* FILe Handle */
X
X
X#define PATS  MAKE_ID('P','A','T','S')
X    /* PATtern String */
X
X#define PAT1  MAKE_ID('P','A','T','1')
X    /* PATtern -- 1 item */
X
X#define LINE  MAKE_ID('L','I','N','E')
X    /* indicates a complete line of text -- omitting newline */
X
X#define TEXT  MAKE_ID('T','E','X','T')
X    /* Text block -- may include newlines */
X
X#define STRG  MAKE_ID('S','T','R','G')
X    /* general non-specific ASCII STRinG */
X
X    /* The above three categories are treated identically by Pserver
X       -- they may have distinct meanings to other servers */
X
X#define CHAR  MAKE_ID('C','H','A','R')
X    /* A single character in L.S byte of ii_Ptr */
X
X#define INTG  MAKE_ID('I','N','T','G')
X    /* A 32-bit INTeGer in ii_Ptr */
X
X#define REAL  MAKE_ID('R','E','A','L')
X    /* A 32-bit floating point value in ii_Ptr (care in conversion!) */
X
X
X/*******************
Xrather than the above if you prefer, with Lattice 4.0 you can simply
Xuse 4-character constants as in the following (compile with the -cm option):
X
X#define CNVA 'CNVA'
X#define QUIT 'QUIT'
X
X#define RETS 'RETS'
X#define FILH 'FILH'
X
X#define PATS 'PATS'
X#define PAT1 'PAT1'
X#define LINE 'LINE'
X#define TEXT 'TEXT'
X#define STRG 'STRG'
X#define CHAR 'CHAR'
X#define INTG 'INTG'
X#define REAL 'REAL'
X*********************/
X
X
Xstruct IPCPort *port=NULL; /* will point to server port */
Xstruct MsgPort *rport=NULL; /* where we get our replies */
Xstruct IPCMessage *imsg=NULL; /* this one message is used repeatedly */
X
Xstruct MsgPort * CreatePort(char *, int);
XULONG Output();
X
Xvoid Cleanup();
Xvoid outputstr(char *);
X
X
X/***************************
X *
X *  Main program entry point:
X *
X *  -- Note that to save overhead we use '_main'; you should also compile
X *  (under Lattice) using the -v switch, to suppress stack checking and
X *  the associated baggage.
X *
X *  We avoid using any C level I/O also -- just AmigaDOS calls, so we
X *  dont need <stdio.h>.
X */
X
Xvoid _main()
X{
X    struct IPCItem *item, *item0; /* pointers to access message items */
X
X    int count=0; /* dummy value used to stuff into message */
X    float realcount=0.0; /* -- ditto */
X
X    char tbuf[22]; /* keyboard input dumped in here */
X
X
X    /* First we set up our ports: */
X
X    port = GetIPCPort("Print_Format");
X    if (!port) _exit(20);
X
X    rport = CreatePort(NULL,0);
X    if (!rport) {Cleanup(); _exit(21);}
X
X    /* ... then make a message block */
X    imsg = CreateIPCMsg(20,0,rport); /* large enough for playing with... */
X    if (!imsg) {Cleanup(); _exit(22);}
X
X    item0 = &imsg->ipc_Items[0]; /* a convenient permanent reference */
X
X
X    /* The main program loop:
X     * -- continues until told to quit by end-of-file (ctrl-\)
X     */
X    while (1) {
X        item = item0; /* reset item pointer */
X        imsg->ipc_Id = CNVA; /* only message ID needed (except QUIT) */
X            /*
X             * Initially we assume that the first item will be a slot
X             * in which the server will return the formatted string.
X             * This will be overwritten if another option is chosen
X             */
X        item->ii_Id = RETS;
X        item->ii_Ptr = NULL; /* The server will provide the data block */
X        item->ii_Size = 0;
X        item->ii_Flags = imsg->ipc_Flags = 0;
X
X        /* get keyboard input (terminated by return): */
X        /* E-O-F returns a length of zero, causing break from loop */
X        if (Read(Input(), tbuf, 21) <= 0) break;
X
X        /*
X         * decode first character of input to decide action
X         *  (sorry about the crudity... but it suffices)
X         */
X        switch(*tbuf) {
X        case 'Q':   /* Send a QUIT message */
X        case 'q':
X        case '.':   imsg->ipc_Id = QUIT; /* all items are ignored */
X                    break;
X
X        case 'm':   /* Request string in reply Message */
X        case 'M':
X        case '?':   item++; /* leave default RETS in place */
X                    item->ii_Id = STRG; /* Add in a string item to
X                                           distinguish displayed line */
X                    item->ii_Ptr = (void *)("Returned: ");
X                    item++;
X                    break;
X
X        case 'F':   /* Pass File handle to this console */
X        case 'f':
X        case '^':   item->ii_Id = FILH; /* overwrites RETS */
X                    item++->ii_Ptr = (void *)Output(); /* the file handle */
X                    break;
X
X        default:    /* anything else just overwrites RETS with output
X                       items, so string appears on Pserver window */
X                    break;
X        }
X
X        /*
X         * The rest of the setup code simply stuffs a few values of
X         * different types into successive items -- rearrange to your
X         * own satisfaction...
X         * NOTE that we haven't bothered to put the strings into public
X         * memory, contrary to the suggestions of the IPC standard
X         *  [For shame, Peter!] but this is really only a restriction
X         * that needs to be observed for general messages that may have
X         * a destination outside the ken of the sender (or for a future
X         * machine that has process-private memory).  This isn't relevant
X         * to such a simple test program, so we've simplified things.
X         * At the same time, the ii_Size field for the string items is
X         * set to ZERO, indicating that the "data block" is Read-Only
X         * as far as the server is concerned.
X         */
X        item->ii_Id = STRG; /* A short string to start out with */
X        item->ii_Ptr = (void *)("Test line...");
X        item++;
X        item->ii_Id = PAT1; /* then a format specifier for a value */
X        item->ii_Ptr = (void *)(" #%3d");
X        item++;
X        item->ii_Id = INTG; /* the integer value to be formatted */
X        item->ii_Ptr = (void *)(count++); /* (just a sequential count...) */
X        item++;
X        item->ii_Id = STRG; /* another string... */
X        item->ii_Ptr = (void *)("... value=");
X        item++;
X        item->ii_Id = REAL; /* A float value in default format */
X            /* note the messy conversion to get it into the ii_Ptr field */
X        *(float *) &item->ii_Ptr = (realcount += 1.234);
X        item++;
X        item->ii_Id = CHAR; /* and a newline character to end the section */
X        item->ii_Ptr = (void *)('\n');
X        item++;
X        item->ii_Id = PATS; /* Multi item format specifier */
X        item->ii_Ptr = (void *)("formatted line #%2d %s\n");
X        item++;
X        item->ii_Id = INTG;
X        item->ii_Ptr = (void *)(count++);
X        item++;
X        item->ii_Id = STRG;
X        item->ii_Ptr = (void *)((count & 3) ? "..." : "tick...");
X        /* no more items allowed after PATS is satisfied */
X
X        /* set actual ItemCount into message: */
X        imsg->ipc_ItemCount = item - item0 + 1;
X
X        /* Send the message (if possible) */
X        if (!PutIPCMsg(port, imsg)) {
X                outputstr("No server!\n");
X                continue; /* don't wait for a reply that won't come! */
X        }
X        /* Wait at the reply port: */
X        WaitPort(rport);
X        GetMsg(rport);  /* we assume we know what's there! */
X        if (imsg->ipc_Flags & IPC_NOTKNOWN)
X            outputstr("Server barfed\n");
X        /*
X         * If we asked for a return string, display it in our
X         * window, then dispose of the block of memory passed to us
X         * by the server:
X         */
X        if (item0->ii_Id == RETS) {
X            Write(Output(), item0->ii_Ptr, strlen(item0->ii_Ptr));
X            /* note that we DON'T use the ii_Size value above!
X               There is no guarantee that it is exactly the size of
X               the string. */
X            FreeMem(item0->ii_Ptr, item0->ii_Size);
X        }
X    }
X    /*** end of main loop ***/
X
X    Cleanup();
X}
X
X
Xvoid Cleanup()
X{
X    if (port) DropIPCPort(port);
X    if (rport) DeletePort(rport);
X    if (imsg) DeleteIPCMsg(imsg);
X}
X
X
Xvoid outputstr(str) char *str;
X{
X    Write(Output(), str, strlen(str));
X}
X
//END_OF_FILE
echo x - IPC.h
sed 's/^X//' > IPC.h << '//END_OF_FILE'
X/*******************************************************************
X *                                                                 *
X *                           IPC.h                                 *
X *                                                                 *
X *           Inter-Process-Communication Message Format            *
X *                                                                 *
X *              Revision 1.2.1 -- 1988 July 31                     *
X *                                                                 *
X *         Copyright 1988 Peter da Silva & Peter Goodeve           *
X *                      All Rights reserved                        *
X *                                                                 *
X *  This source is freely distributable, but should not be         *
X *  modified without prior consultation with the authors.          *
X *                                                                 *
X *******************************************************************/
X
X#ifdef AZTEC_C
X/* can't use prototyping */
X#define NARGS 1
X/* (if NARGS is undefined, prototyping is enabled) */
X#endif
X
X#ifndef EXEC_TYPES_H
X#include "exec/types.h"
X#endif
X
X#ifndef EXEC_PORTS_H
X#include "exec/ports.h"
X#endif
X
X/*** Item Reference block -- an arbitrary number of these may be
X   put in an IPCMessage ***/
X
Xstruct IPCItem {
X    ULONG   ii_Id;      /* four character ID (normally);
X                           determines exact meaning of IPCItem IDs */
X    ULONG   ii_Flags;   /* upper 16 bits have standard meaning;
X                           lower 16 bits are message dependent */
X    ULONG   ii_Size;    /* size of data structure (zero if ii_Ptr is not
X                           actually a pointer to data) */
X    void   *ii_Ptr;     /* points to defined data structure (could be within
X                           message block if IE_Flags says so) -- also may be
X                           recast to other 32-bit value (e.g. Lock) */
X    };
X
X
X
X/*** The basic IPCMessage block ***/
X
Xstruct IPCMessage {
X    struct Message  ipc_Msg;
X        /* ..ln_Name field should be NULL
X            mn_Length will include IPC_Items array and any in-line data
X        */
X    ULONG   ipc_Id,                /* four character (or other) ID */
X            ipc_Flags;
X    UWORD   ipc_ItemCount;         /* number of items in array */
X    struct  IPCItem ipc_Items[1];  /* .. actual size as needed */
X    };
X
X
X/*************************************************************/
X
X/* Flags set by client (tentative...): */
X/* -- may appear in either IPCItem or IPCMessage Flags field */
X
X#define IPC_TRANSFER   0x08000000
X    /* Data block ownership is to be transferred to receiver. */
X#define IPC_NETWORK    0x04000000
X    /* The data in this block/message may be transmitted to
X       another machine */
X#define IPC_INMESSAGE  0x02000000
X    /* The data in this block/message is included in the message length */
X
X/* Flags returned by server (ditto): */
X
X#define IPC_NOTKNOWN   0x80000000
X    /* The server could not handle this block/message
X       (either because it did not understand the ID or
X       was unable to process it -- see the secondary flags */
X#define IPC_MODIFIED   0x40000000
X    /* The server modified the data, either within the
X       supplied data block(s) or -- if permitted -- by
X       replacing/removing the block pointer; again maybe
X       other flag bits should indicate the nature of
X       the modification */
X
X/* valid for Item only: */
X#define IPC_SERVER_OWNED 0x10000000
X    /* The server owns this data Item -- either because it has
X       created it or because it took it over from the client
X       (in which case it clears IPC_TRANSFER, which must have
X       been set) */
X
X
X/* secondary flag bits (more to come...): */
X
X#define IPC_CHECKITEM 0x00800000
X    /* associated with IPC_NOTKNOWN -- indicates that one or more
X       particular items caused the flag to be set */
X#define IPC_FAILED 0x00400000
X    /* IPC_NOTKNOWN flag was set because the server failed to
X       handle an ID that it is designed to (rather than just
X       not recognizing the block) */
X
X/*************************************************************/
X
X
X/*** IPC Ports and Procedures ***/
X
X
X/* -- see IPCPorts.h for actual structure definitions */
X#ifndef IPC_PORTS_H
X/* Normal user doesn't need access to port components,
X   so just use a convenient define.  Note that an IPC port
X   is NEVER in private data space -- or in the public port
X   list -- it is created and managed by the package routines
X   only. */
X#define IPCPort MsgPort
X#endif
X
X
X/* IPC Port Handling function prototypes: */
X
X#ifndef NARGS /* define this to SUPPRESS function argument prototyping */
X
Xstruct IPCPort * FindIPCPort(char *);
X    /* returns pointer to port if it exists -- null otherwise;
X       registers a new connection to the port */
X
Xstruct IPCPort * GetIPCPort(char *);
X    /* returns pointer to port -- it is created if it doesn't exist;
X       registers a new connection to the port */
X
X
Xvoid UseIPCPort(struct IPCPort *);
X    /* adds a connection to a port (passed by pointer from another
X       process) */
X
X
Xvoid DropIPCPort(struct IPCPort *);
X    /* disconnect from port -- port will be destroyed if there are
X       no other connections left */
X
X
Xstruct IPCPort * ServeIPCPort(char *);
X    /* become a server for the named port (created if it doesn't exist);
X       null is returned if the port already has a server, otherwise a
X       pointer to it is returned */
X
Xvoid ShutIPCPort(struct IPCPort *);
X    /* (server only) prevent more messages being sent to this port, but
X       do not end server connection; remaining messages can be dealt
X       with before Leaving */
X
Xvoid LeaveIPCPort(struct IPCPort *);
X    /* cease to be a server for this port; another process can then
X       become a server if it desires */
X
XCheckIPCPort(struct IPCPort *, UWORD);
X    /* returns number of current connections to this port (including
X       server); a call by the server (only) will also set the (user
X       settable) port flags to the value in the second argument --
X       currently the only valid flag is IPP_NOTIFY */
X
X
XPutIPCMsg(struct IPCPort *, struct IPCMessage *);
X    /* sends an IPCMessage to an IPCPort; if the port has no server or
X       is shut, the message is not sent and the function returns FALSE;
X       otherwise it returns TRUE. (Other port flags to be added later
X       may affect these actions.) */
X
Xstruct IPCMessage * CreateIPCMsg(int, int, struct MsgPort *);
X    /* creates a standard IPCMessage block (in MEMF_PUBLIC) with the
X       number of IPCItems supplied as first argument;  the second
X       argument is the number of bytes -- if any -- to reserve beyond
X       that required for the items; the third is a pointer to the
X       ReplyPort (may be NULL -- note that it's a standard MsgPort,
X       not an IPCPort). (You always have to manage any data
X       blocks yourself). */
X
X
Xvoid DeleteIPCMsg(struct IPCMessage *);
X    /* deletes a standard IPCMessage block;  you must first have disposed
X       of any attached data as appropriate */
X
X/*************************************************************/
X#else NARGS defined
X
Xstruct IPCPort * FindIPCPort ();
Xstruct IPCPort * GetIPCPort ();
Xvoid             UseIPCPort ();
Xvoid             DropIPCPort ();
Xstruct IPCPort * ServeIPCPort ();
Xvoid             ShutIPCPort ();
Xvoid             LeaveIPCPort ();
Xint              CheckIPCPort ();
Xint              PutIPCMsg ();
Xstruct IPCMessage * CreateIPCMsg ();
Xvoid             DeleteIPCMsg ();
X
X/*************************************************************/
X#endif NARGS
X
X
X/* System IPCPort flags: */
X
X#define IPP_SERVED 0x8000
X    /* port currently has a server */
X#define IPP_SHUT 0x4000
X    /* port is no longer open for new messages (server still attached) */
X#define IPP_REOPEN 0x2000
X    /* set (by "Port Broker") to request that server reopen service
X       to this port after it has completed Shut/Leave sequence
X       in progress */
X#define IPP_LOADING 0x1000
X    /* set (by "Port Broker") to indicate that a server is being loaded
X       for this port (cleared by ServeIPCPort()) */
X
X
X/* Server settable Port flags: */
X
X#define IPP_NOTIFY 0x0001
X    /* server wants to be signalled if connection is added or
X       dropped (the port sigbit is used to signal the task,
X       but no message is sent) */
X
X/*************************************************************/
X
X/*
X *  Some useful Macros:
X */
X
X#define GetIPCMessage(port) ((struct IPCMessage *)GetMsg((struct MsgPort *)port))
X
X#define ReplyIPCMessage(msg)  ReplyMsg((struct Message *)msg)
X
X#define SigBitIPCPort(port) (1<<((struct MsgPort *)port)->mp_SigBit)
X    /* note: this will work whether or not IPCPorts.h has been included */
X
X
X/*
X   For convenience in creating IDs:
X    (Alternatively, your compiler may have multi-character constants,
X     which you may find more convenient (but less portable...))
X*/
X
X#define MAKE_ID(a,b,c,d) ((a)<<24L | (b)<<16L | (c)<<8 | (d))
X
X
//END_OF_FILE
echo x - Pserver.lnk
sed 's/^X//' > Pserver.lnk << '//END_OF_FILE'
XFROM LIB:c.o,Pserver.o,IPC.o
XTO Pserver
XLIBRARY LIB:lcm.lib,LIB:lc.lib,LIB:amiga.lib
XMAP Pserver.map,f,h,,s,x
X
X
X
//END_OF_FILE
echo x - MinClient.lnk
sed 's/^X//' > MinClient.lnk << '//END_OF_FILE'
XFROM LIB:c.o,MinClient.o,IPC.o
XTO MinClient
XLIBRARY LIB:lcm.lib,LIB:lc.lib,LIB:amiga.lib
XMAP MinClient.map,f,h,,s,x
X
X
X
//END_OF_FILE
echo "End of archive."
# end of archive.
exit 0