home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_disks / 200-299 / ff290.lzh / IPC / Sources / FormatServer.c < prev    next >
C/C++ Source or Header  |  1989-12-11  |  23KB  |  751 lines

  1. /************************************************************
  2.  *                                                          *
  3.  *         Print Formatting Server (demo) for IPC           *
  4.  *                                                          *
  5.  *          -- Shared Library Version --                    *
  6.  *                                                          *
  7.  *                Pete Goodeve 89:3:29                      *
  8.  *                                                          *
  9.  *  [This module has only been compiled under Lattice;      *
  10.  *   it will need some modification for Manx/Aztec;         *
  11.  *   ... I'd be very grateful if someone would do the       *
  12.  *   conversion...]                                         *
  13.  *                                                          *
  14.  *                                                          *
  15.  *  This is a server to handle 'printf' conversion of       *
  16.  *  int, float, string, and char valued message items.      *
  17.  *  This saves space in other IPC modules that have a       *
  18.  *  need for text output.  A single message results in      *
  19.  *  a single output string, but there can be any number     *
  20.  *  of items in the message, converted in sequence to       *
  21.  *  ASCII -- either under the control of format specifier   *
  22.  *  items, or in default format if these are omitted.       *
  23.  *                                                          *
  24.  *  The output string will by default be displayed in       *
  25.  *  the server's window (thus other modules need not have   *
  26.  *  their own).  Optional message items will redirect       *
  27.  *  the output either to a supplied file handle (FILH) or   *
  28.  *  to be returned as an item in the reply message (RETS).  *
  29.  *                                                          *
  30.  *  Only one message ID (aside from QUIT) is recognized     *
  31.  *  by this server: CNVA ("CoNVert to Ascii").  See below   *
  32.  *  for item IDs.  The program will terminate when it       *
  33.  *  receives a QUIT message (items ignored), or when        *
  34.  *  the number of clients drops from non-zero to zero       *
  35.  *  (in other words it will not exit if there are initially *
  36.  *  no clients).  It will also quit if it is sent a         *
  37.  *  cntrl-C break.                                          *
  38.  *                                                          *
  39.  *                                                          *
  40.  *  This is currently a completely "synchronous" server;    *
  41.  *  it processes each message completely before returning   *
  42.  *  it, and doesn't attempt to handle more than one at a    *
  43.  *  time.  It doesn't send out any messages of its own      *
  44.  *  either (i.e. it isn't a "manager"), but for the         *
  45.  *  purpose of illustration some dummy manager type code    *
  46.  *  has been included in the main loop, so you can see      *
  47.  *  the sort of extensions that would be needed for that.   *
  48.  *  The procreply() procedure -- here a dummy -- would      *
  49.  *  have to dispatch each reply message that arrived to     *
  50.  *  a suitable close-out procedure, then dispose of the     *
  51.  *  message and any associated memory.                      *
  52.  *                                                          *
  53.  ************************************************************/
  54.  
  55. #ifdef DEBUG /* set this to show messages being received and so on */
  56. #include "stdio.h"
  57. #endif
  58.  
  59. #ifdef LATTICE
  60. #if LATTICE_40 | LATTICE_50
  61. #include "IPC_proto.h"
  62. /* ...else (not recent Lattice) will need library linkage stubs (IPC.o) */
  63. #endif
  64. #endif
  65.  
  66. #include "IPC.h"
  67.  
  68. #include "exec/memory.h"
  69. #include "libraries/dos.h"
  70.  
  71. /*
  72.  *  Define the ID codes recognized by the print format server
  73.  *
  74.  *  (MAKE_ID is defined in IPC.h)
  75.  */
  76.  
  77. /* Message IDs: */
  78. #define CNVA  MAKE_ID('C','N','V','A')
  79.     /* CoNVert to Ascii */
  80. #define QUIT  MAKE_ID('Q','U','I','T')
  81.  
  82. /* Item IDs: */
  83. #define RETS  MAKE_ID('R','E','T','S')
  84.     /* RETurn String */
  85.  
  86. #define FILH  MAKE_ID('F','I','L','H')
  87.     /* FILe Handle */
  88.  
  89.  
  90. #define PATS  MAKE_ID('P','A','T','S')
  91.     /* PATtern String */
  92.     /* NOTE: the total formatted length for a PATS item
  93.        must not be longer than 255 characters, to avoid crashing! */
  94.  
  95. #define PAT1  MAKE_ID('P','A','T','1')
  96.     /* PATtern -- 1 item */
  97.     /* NOTE: the total formatted length for a single PAT1 item
  98.        must not be longer than 65 characters, to avoid crashing! */
  99.  
  100. #define LINE  MAKE_ID('L','I','N','E')
  101.     /* indicates a complete line of text -- omitting newline */
  102.  
  103. #define TEXT  MAKE_ID('T','E','X','T')
  104.     /* Text block -- may include newlines */
  105.  
  106. #define STRG  MAKE_ID('S','T','R','G')
  107.     /* general non-specific ASCII STRinG */
  108.  
  109.     /* The above three categories are treated identically by Pserver
  110.        -- they may have distinct meanings to other servers */
  111.  
  112. #define CHAR  MAKE_ID('C','H','A','R')
  113.     /* A single character in L.S byte of ii_Ptr */
  114.  
  115. #define INTG  MAKE_ID('I','N','T','G')
  116.     /* A 32-bit INTeGer in ii_Ptr */
  117.  
  118. #define REAL  MAKE_ID('R','E','A','L')
  119.     /* A 32-bit floating point value in ii_Ptr (care in conversion!) */
  120.  
  121.  
  122. /*******************
  123. rather than the above if you prefer, with Lattice 4.0 you can simply
  124. use 4-character constants as in the following (compile with the -cm option):
  125.  
  126. #define CNVA 'CNVA'
  127. #define QUIT 'QUIT'
  128.  
  129. #define RETS 'RETS'
  130. #define FILH 'FILH'
  131.  
  132. #define PATS 'PATS'
  133. #define PAT1 'PAT1'
  134. #define LINE 'LINE'
  135. #define TEXT 'TEXT'
  136. #define STRG 'STRG'
  137. #define CHAR 'CHAR'
  138. #define INTG 'INTG'
  139. #define REAL 'REAL'
  140. *********************/
  141.  
  142. APTR IPCBase = NULL;
  143.  
  144.  
  145.  
  146. struct IPCPort *import=NULL; /* this is the port we serve */
  147.  
  148. struct IPCMessage *imsg=NULL; /* we only handle one message at a time,
  149.                                  so a global pointer is useful */
  150.  
  151. struct MsgPort *report=NULL; /* reply port: not actually  used here
  152.                                 -- skeleton code is shown */
  153.  
  154. /* should really include proto.h now for system procedures (next time...) */
  155. char * AllocMem(int, ULONG);
  156. void FreeMem(char *, int);
  157. struct MsgPort * CreatePort(char *, int);
  158. struct Message * Getmsg(struct MsgPort *);
  159.  
  160. void Cleanup();
  161. void clearmarkers();
  162. void outputstr(char *);
  163. void procline();
  164. void baditem(struct IPCItem *, ULONG);
  165.  
  166.  
  167. int active = TRUE, /* when this goes FALSE, it's time to quit */
  168.     replies = 0; /* number of replies to get back (...if we got replies!) */
  169.  
  170. ULONG reportsig = 0,  /* signal masks for ports */
  171.       importsig = 0;
  172.  
  173. ULONG outputhnd; /* file handle from message (if any) will be held here */
  174. struct IPCItem *retitem; /* item to contain return string (if any) */
  175.  
  176. int total_length, /* length computed for output string in pre-scan */
  177.     alloc_length; /* length of allocated block (if any)  -- acts as flag */
  178.  
  179. char *linebuf, *bufptr; /* pointers (fixed and moveable) to output string */
  180.  
  181. int mesg_bad; /* flag to prevent further processing if a bad item found */
  182.               /* (note that extraneous items are mostly just ignored) */
  183.  
  184.  
  185. /***************************
  186.  *
  187.  *  Main program entry point:
  188.  *
  189.  *  -- Note that to save overhead we use '_main'; you should also compile
  190.  *  (under Lattice) using the -v switch, to suppress stack checking and
  191.  *  the associated baggage.
  192.  *
  193.  *  We avoid using any C level I/O also -- just AmigaDOS calls, so we
  194.  *  dont need <stdio.h>.
  195.  */
  196.  
  197. void _main()
  198. {
  199.     int clients, oldclients = 0;
  200.                    /* keeps track of number of current clients */
  201.     ULONG sigset;  /* set to signals that woke up Wait() */
  202.  
  203. #ifdef TRACKCLIENTS /* define this to display current number of clients */
  204.     char clrepstr[16];
  205. #endif
  206.  
  207.     /* Before anything else, we need the IPC Library: */
  208.     IPCBase = (APTR)OpenLibrary("ppipc.library",0);
  209.     if (!IPCBase) {
  210.         outputstr(
  211.         "Couldn't find ppipc.library!\nHave you installed it in LIBS: ?\n");
  212.         _exit(20);
  213.     }
  214.  
  215.     report = CreatePort(NULL,0); /* I repeat... this is just a dummy here */
  216.     if (!report) {
  217.         outputstr("no space!!");
  218.         Cleanup();
  219.         return;
  220.     }
  221.     import = ServeIPCPort("Print_Format");
  222.     if (!import) {
  223.         outputstr("Print Server already exists ... exiting");
  224.         Cleanup();
  225.         return;
  226.     }
  227.     /* Get the signal bits for each port for later convenience: */
  228.     /* (Note that, because we did not include IPCPorts.h, IPCPorts
  229.         are identical to MsgPorts as far as the user is concerned;
  230.         if we DID need IPCPorts.h, these statements would have to
  231.         be changed appropriately.) */
  232.     reportsig = 1<<report->mp_SigBit;
  233.     importsig = 1<<import->mp_SigBit;
  234.  
  235. #ifdef DEBUG
  236.     setnbf(stdout); /* so we can see output! (unbuffered) */
  237. #endif
  238.  
  239.  
  240.     /*
  241.      *  The main loop:
  242.      *  -- first we process any outstanding messages, looping until
  243.      *  no more are found (procreply() always fails -- there are no
  244.      *  replies in this program!).
  245.      *  -- then we check the number of current clients: if they have
  246.      *  all gone, we will exit.
  247.      */
  248.     do {
  249.         while ( procimsg() || procreply()) ;  /* loop to satisfy messages */
  250.  
  251.         /*
  252.          *  look at the number of clients (optional code included to display
  253.          *  this).  The number returned by CheckIPCPort includes the server,
  254.          *  so for convenience we subtract 1.
  255.          *  Note that we set IPP_NOTIFY, so the process gets woken up each
  256.          *  time the number of clients changes.
  257.          */
  258.         if ((clients = CheckIPCPort(import, IPP_NOTIFY) - 1)
  259.                    != oldclients) {
  260. #ifdef TRACKCLIENTS /* for demonstration purposes... */
  261.             sprintf(clrepstr,
  262.                     (clients == 1? "1 client\n" : "%d clients\n"), clients);
  263.             outputstr(clrepstr);
  264. #endif
  265.             if (!clients) {
  266.                 active = FALSE; /* quit if everyone gone */
  267.                 ShutIPCPort(import); /* note: multiple calls don't hurt! */
  268.                 continue; /* so we clear out any messages that sneak in */
  269.             }
  270.             oldclients = clients;
  271.         }
  272.  
  273.         /*
  274.          *  Now wait for further messages, unless 'active' is FALSE
  275.          *  ('replies' is always FALSE in this program).
  276.          */
  277.         if (active | replies) {
  278.             /* Note that Wait() must be used rather than WaitPort()
  279.                if we want to wake up on IPP_NOTIFY as well as messages */
  280.             sigset = Wait(importsig | reportsig | SIGBREAKF_CTRL_C);
  281.             if (sigset & SIGBREAKF_CTRL_C) {
  282.                 active = FALSE;
  283.                 ShutIPCPort(import); /* note: multiple calls don't hurt! */
  284.                 continue; /* so we clear out any messages that sneak in */
  285.             }
  286.         }
  287.     } while (active | replies);
  288.     /*** end of main loop ***/
  289.  
  290.     outputstr("Pserver terminating...\n");
  291.  
  292.     Cleanup();
  293. }
  294. /*** end of _main ***/
  295.  
  296.  
  297. void Cleanup()
  298. {
  299.     if (import) LeaveIPCPort(import);
  300.     if (report) DeletePort(report);
  301.     CloseLibrary(IPCBase);
  302. }
  303.  
  304.  
  305. int itemn;  /* global item counter */
  306. struct IPCItem *curitem; /* global item pointer */
  307.  
  308.  
  309. /*
  310.  *  Process incoming messages
  311.  *  -- returns FALSE if there are none, otherwise TRUE.
  312.  *  It recognizes the message ID and invokes the appropriate
  313.  *  handling procedures.
  314.  */
  315. procimsg()
  316. {
  317.     if (!(imsg = (struct IPCMessage *) GetMsg(import))) return FALSE;
  318. #ifdef DEBUG
  319.     printf("item count = %d\n", imsg->ipc_ItemCount);
  320. #endif
  321.     switch (imsg->ipc_Id) {
  322.        case CNVA:
  323.                /*
  324.                 *   First do a scan of the message to determine how
  325.                 *   big a string space will be needed
  326.                 *   (and check for bad items):
  327.                 */
  328.                curitem = imsg->ipc_Items; /* initialize the item pointer */
  329.                for (itemn=imsg->ipc_ItemCount;
  330.                     itemn && scanitem(); curitem++, itemn-- ) /* loop */;
  331.  
  332.                if (mesg_bad) break;
  333.  
  334.                /*
  335.                 *   Allocate the space needed:
  336.                 */
  337.                if (!allocline()) break;
  338.  
  339.                /*
  340.                 *   Now actually process the items in the message:
  341.                 */
  342.                curitem = imsg->ipc_Items; /* reset again */
  343.                for (itemn=imsg->ipc_ItemCount;
  344.                     itemn && procitem(); curitem++, itemn-- ) /* loop */;
  345.  
  346.                /*
  347.                 *   Finally terminate the output string and handle
  348.                 *   it as directed:
  349.                 */
  350.                procline();
  351.                break; /* end of CNVA processing */
  352.  
  353.        case QUIT:
  354.                active = FALSE;
  355.                ShutIPCPort(import);
  356.                outputstr("Pserver got QUIT message...");
  357.                break;
  358.  
  359.        default:
  360. #ifdef DEBUG
  361.                outputstr("got bad message");
  362. #endif
  363.                imsg->ipc_Flags |= IPC_NOTKNOWN;
  364.                break;
  365.     }
  366.  
  367.     if (mesg_bad)
  368.         imsg->ipc_Flags |= IPC_NOTKNOWN | IPC_FAILED;
  369.     ReplyMsg(imsg);
  370.     clearmarkers(); /* reset things for the next message */
  371.     return TRUE;
  372. }
  373.  
  374.  
  375. /*
  376.  *  Skeleton procedure for handling replies (of which there are none
  377.  *  in this program...).
  378.  */
  379. procreply()
  380. {
  381.     struct IPCMessage *rpmsg;
  382.     struct IPCItem *item;
  383.  
  384.     if (!(rpmsg = (struct IPCMessage *)GetMsg(report))) return FALSE;
  385.     if (rpmsg->ipc_Flags & IPC_NOTKNOWN) {
  386. #ifdef DEBUG
  387.         outputstr("\nServer didn't like this message...");
  388. #endif
  389.     }
  390.     item = rpmsg->ipc_Items;
  391.     /* message deletion and so on would go here... */
  392.     replies--; /* This variable is incremented for each original message
  393.                   generated by this program; the program will not exit
  394.                   as long as it is non-zero */
  395.     return TRUE;
  396. }
  397.  
  398.  
  399. /*
  400.  *  Reset all global variables ready for next incoming message
  401.  */
  402. void clearmarkers()
  403. {
  404.     if (alloc_length) FreeMem(linebuf, alloc_length);
  405.     linebuf = NULL;
  406.     alloc_length = 0;
  407.     total_length = 0;
  408.     retitem = NULL;
  409.     outputhnd = NULL;
  410.     mesg_bad = FALSE;
  411. }
  412.  
  413.  
  414. /*
  415.  *  Scan the current item to determine length of string it will generate.
  416.  *  It also recognizes disposition control items (RETS, FILH) and sets up
  417.  *  the required pointers.
  418.  *  Subprocedures called may also check validity of item to be formatted
  419.  *  (extraneous items not following a format specifier are simply ignored.)
  420.  */
  421. scanitem()
  422. {
  423.     char dummy[66]; /* this should be enough (!) */
  424.  
  425. #ifdef DEBUG
  426.     debugitem(curitem,"scanitem:");
  427. #endif
  428.  
  429.             switch (curitem->ii_Id) {
  430.         case RETS:
  431.                 retitem = curitem;
  432.                 break;
  433.         case FILH:
  434.                 outputhnd = (ULONG)curitem->ii_Ptr;
  435.                 break;
  436.         case PATS:
  437.                 total_length += scanpatstring();
  438.                 return FALSE;   /* stop here */
  439.         case PAT1:
  440.                 total_length += patternitem(dummy);
  441.                 break;
  442.         case LINE:
  443.         case TEXT:
  444.         case STRG:
  445.                 total_length += strlen(curitem->ii_Ptr);
  446.                 break;
  447.         case CHAR:
  448.                 total_length++;
  449.                 break;
  450.         case INTG:
  451.                 total_length += cnvtitem(dummy, "%ld", curitem);
  452.                 break;
  453.         case REAL:
  454.                 total_length += cnvtitem(dummy, "%g", curitem);
  455.                 break;
  456.  
  457.         default:
  458. #ifdef DEBUG
  459.                 outputstr("got unknown item");
  460. #endif
  461.                 /* ignore extraneous stuff */
  462.                 break;
  463.             }
  464.         return (!mesg_bad); /* stops here if message has failed */
  465. }
  466.  
  467.  
  468. /*
  469.  *  Allocate space for complete output string.
  470.  *  -- if the message has supplied a NON-NULL ii_Ptr in a RETS item,
  471.  *  this will be used as the buffer, as long as the associated ii_Size
  472.  *  is large enough (if it is not, the message will fail).  Otherwise
  473.  *  space is allocated for the buffer.  If a NULL RETS item has been
  474.  *  supplied, the buffer pointer will be returned there (otherwise the
  475.  *  buffer will be freed again after output).
  476.  *  It will of course also fail if there is no space for a buffer.
  477.  *  Any failure returns FALSE, otherwise TRUE.
  478.  */
  479. allocline()
  480. {
  481.     int adj_length = total_length + 1; /* allow for terminator */
  482.     if (retitem) { /* check for a RETS item first */
  483.         if (retitem->ii_Ptr) { /* buffer supplied? */
  484.             if (retitem->ii_Size > total_length) { /* big enough ? */
  485.                 linebuf = (char *)retitem->ii_Ptr; /* yes -- use it */
  486.             }
  487.             else { /* too small */
  488.                 baditem(retitem, IPC_FAILED);
  489.                 return FALSE;
  490.             }
  491.         }
  492.         else { /* NULL pointer, so create some space */
  493.             linebuf = AllocMem(adj_length, MEMF_PUBLIC);
  494.             if (!linebuf) {
  495.                 baditem(retitem, IPC_FAILED);
  496.                 return FALSE;
  497.             }
  498.             else {
  499.                 retitem->ii_Ptr = (void *)linebuf;
  500.                 retitem->ii_Size = adj_length;
  501.                 retitem->ii_Flags = IPC_TRANSFER | IPC_MODIFIED;
  502.                     /* flags are set to indicate client must dispose
  503.                        of this block */
  504.             }
  505.         }
  506.     }
  507.     else { /* no RETS item, so use local buffer */
  508.         linebuf = AllocMem(adj_length, MEMF_PUBLIC);
  509.         if (!linebuf) {
  510.             imsg->ipc_Flags |= IPC_NOTKNOWN | IPC_FAILED;
  511.             return FALSE;
  512.         }
  513.         alloc_length = adj_length; /* used to free the message afterward */
  514.     }
  515.     bufptr = linebuf; /* initialize the output pointer */
  516.     return TRUE;
  517. }
  518.  
  519.  
  520. /*
  521.  *  Write the ASCII string for the current item to the output buffer.
  522.  *  A suitable default format is used for items with no preceding
  523.  *  format specifier.
  524.  */
  525. procitem()
  526. {
  527.  
  528. #ifdef DEBUG
  529.     debugitem(curitem,"procitem:");
  530. #endif
  531.             switch (curitem->ii_Id) {
  532.         case RETS:
  533.         case FILH:
  534.                 break;
  535.         case PATS:
  536.                 bufptr +=cnvtpatstring(bufptr);
  537.                 return FALSE;  /* no further items allowed */
  538.         case PAT1:
  539.                 bufptr += patternitem(bufptr);
  540.                 break;
  541.         case LINE:
  542.         case TEXT:
  543.         case STRG:
  544.                 strcpy(bufptr, curitem->ii_Ptr);
  545.                 bufptr += strlen(curitem->ii_Ptr);
  546.                 break;
  547.         case CHAR:
  548.                 *bufptr++ = (char) (curitem->ii_Ptr);
  549.                     /* Lattice gives a warning here but does it OK */
  550.                 break;
  551.         case INTG:
  552.                 bufptr += cnvtitem(bufptr, "%ld", curitem);
  553.                 break;
  554.         case REAL:
  555.                 bufptr += cnvtitem(bufptr, "%g", curitem);
  556.                 break;
  557.  
  558.         default:
  559.                 /* ignore */
  560.                 break;
  561.             }
  562.         return TRUE;
  563. }
  564.  
  565.  
  566. /*
  567.  *  Determine length (and validity) of multi-item format specifier
  568.  */
  569. scanpatstring()
  570. {
  571.     char *dummy;
  572.     int len;
  573.     dummy = AllocMem(256, 0L); /* temporary local storage */
  574.     if (!dummy)
  575.         return 256;  /* let allocline fail instead ! */
  576.     len = cnvtpatstring(dummy);
  577.     FreeMem(dummy, 256);
  578.     return len;
  579. }
  580.  
  581.  
  582. /*
  583.  *  Use the format in a PAT1 item to convert the following item.
  584.  *  (Simply calls cnvtitem with suitable arguments.)
  585.  */
  586. patternitem(destptr)
  587. char *destptr;
  588. {
  589.     char *fmtp;
  590.     if (--itemn) {
  591.         fmtp = (char *)curitem->ii_Ptr;
  592.         return cnvtitem(destptr, fmtp, ++curitem);
  593.     }
  594.     else {
  595.         baditem(curitem, IPC_FAILED);
  596.         mesg_bad = TRUE;
  597.         return 0;
  598.     }
  599. }
  600.  
  601.  
  602. /*
  603.  *  Convert a single value (in the current item) according to the
  604.  *  format specified.  Output is to destptr; the size of the resulting
  605.  *  string is returned.
  606.  */
  607. cnvtitem(destptr, fmtstr, item)
  608. char *destptr, *fmtstr;
  609. struct IPCItem *item;
  610. {
  611.     double doubleval;
  612.     int len;
  613.  
  614. #ifdef DEBUG
  615.     debugitem(item,"cnvtitem:");
  616. #endif
  617.  
  618.             switch (item->ii_Id) { /* handle according to type */
  619.         case LINE:
  620.         case TEXT:
  621.         case STRG:
  622.                 len = sprintf(destptr, fmtstr, item->ii_Ptr);
  623.                 break;
  624.         case CHAR:
  625.                 len = sprintf(destptr, fmtstr, item->ii_Ptr);
  626.                 break;
  627.         case INTG:
  628.                 len = sprintf(destptr, fmtstr, item->ii_Ptr);
  629.                 break;
  630.         case REAL:
  631.                 doubleval = *(float *) &item->ii_Ptr;
  632.                 len = sprintf(destptr, fmtstr, doubleval);
  633.                 break;
  634.  
  635.         default:
  636.                 baditem(item, IPC_FAILED);
  637.                 mesg_bad = TRUE;
  638.             }
  639.         return len;
  640. }
  641.  
  642.  
  643. /*
  644.  *  Convert items to ASCII according to format pattern in the current item.
  645.  *  All the remaining items in the message must be values to satisfy the
  646.  *  pattern.  (Note that REAL items aren't allowed, because they can't be
  647.  *  passed to sprintf as 32-bit values).  Up to 10 items can be handled.
  648.  *  The total length of the formatted string is returned.
  649.  */
  650. cnvtpatstring(destptr)
  651. char *destptr; /* destination string buffer */
  652. {
  653.     char *fmtp;
  654.     int i;
  655.      ULONG p[10]; /* Storage for 10 values */
  656.  
  657.     fmtp = (char *)curitem->ii_Ptr; /* hold pointer to pattern string */
  658.     for (i=0; i<10 && --itemn; i++ ) { /* process all the remaining items */
  659.         ++curitem;
  660. #ifdef DEBUG
  661.     debugitem(curitem,"patstring:");
  662. #endif
  663.         switch (curitem->ii_Id) { /* everything the same except REAL */
  664.         case LINE:
  665.         case TEXT:
  666.         case STRG:
  667.         case CHAR:
  668.         case INTG:
  669.                 p[i] = (ULONG)curitem->ii_Ptr; /* local copy */
  670.                 break;
  671.         case REAL: /* can't pass a double this way!! */
  672.         default:
  673.                 baditem(curitem, IPC_FAILED);
  674.                 mesg_bad = TRUE; /* can't continue */
  675.                 return 0;
  676.         }
  677.     }
  678.     if (itemn) { /* more than 10 items found */
  679.         baditem(++curitem, IPC_FAILED);
  680.         mesg_bad = TRUE;
  681.         return 0;
  682.     }
  683.     while (i<10) p[i++] = (ULONG) "\0"; /* not very adequate protection */
  684.  
  685.     /* Fortunately C allows us to pass unused arguments: */
  686.     return sprintf(destptr, fmtp,
  687.            p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9]);
  688. }
  689.  
  690.  
  691. /*
  692.  *  Process the assembled output string
  693.  *  -- if the output handle has been supplied, the string will be sent there;
  694.  *  if neither handle nor return slot has been supplied, the string will
  695.  *  be output to the server's window.
  696.  *  (If a return slot is present in the message, the string will be returned
  697.  *  there in any case.)
  698.  */
  699. void procline()
  700. {
  701.     *bufptr = '\0'; /* Terminate the string first */
  702.     if (outputhnd) Write(outputhnd, linebuf, total_length);
  703.     else if (!retitem)
  704.          Write(Output(), linebuf, total_length);
  705. }
  706.  
  707.  
  708. /*
  709.  * Set error flags in an item and the message
  710.  * (Note that this doesn't abort processing -- if this is needed,
  711.  * the mesg_bad flag should also be set)
  712.  */
  713. void baditem(item, extraflags)
  714.     struct IPCItem *item;
  715.     ULONG extraflags;
  716. {
  717.     imsg->ipc_Flags |= IPC_CHECKITEM;
  718.     item->ii_Flags |= IPC_NOTKNOWN | extraflags;
  719. #ifdef DEBUG
  720.     debugitem(item, "BAD:");
  721. #endif
  722. }
  723.  
  724.  
  725. /* procedure to display string in window (avoids C I/O overhead) */
  726.  
  727. void outputstr(str) char *str;
  728. {
  729.     Write(Output(), str, strlen(str));
  730. }
  731.  
  732. /************************************************************?
  733.  
  734. /* the following is only included if you want debugging output: */
  735. #ifdef DEBUG
  736. debugitem(item, str)
  737.     struct IPCItem *item;
  738.     char *str;
  739. {
  740.     ULONG icode[2];
  741.     icode[0] = item->ii_Id;
  742.     icode[1] = 0;
  743.     printf("%s item %d code %s [%x] ptr %x flagged %x\n",
  744.            str, item - imsg->ipc_Items,
  745.            icode, *icode,
  746.            item->ii_Ptr, item->ii_Flags);
  747. }
  748. #endif
  749.  
  750.  
  751.