Example #1
0
        public override PacketType NextPacket()
        {
            // Code here is not just a simple call to impl.nextPacket(). For a KernelLink, nextPacket() returns a
            // wider set of packet constants than the MathLink C API itself. We want nextPacket() to work on the
            // non-packet types of heads the kernel and FE send back and forth.
            // Because for some branches below we seek back to the start before returning, it is not guaranteed
            // that when nextPacket() returns, the current packet has been "opened". Thus it is not safe to write
            // a J/Link program that loops calling nextPacket()/newPacket(). You need to call handlePacket() after
            // nextPacket() to ensure that newPacket() will throw away the curent "packet".

            // createMark will fail on an unconnected link, and the user might call this
            // before any reading that would connect the link.
            if (!linkConnected)
            {
                Connect();
                linkConnected = true;
            }

            PacketType pkt;
            ILinkMark  mark = CreateMark();

            try {
                pkt = impl.NextPacket();
            } catch (MathLinkException e) {
                if (e.ErrCode == 23 /* MLEUNKNOWNPACKET */)
                {
                    ClearError();
                    SeekMark(mark);
                    int    argCount;
                    string f = GetFunction(out argCount);
                    if (f == "ExpressionPacket")
                    {
                        pkt = PacketType.Expression;
                    }
                    else if (f == "BoxData")
                    {
                        // Probably more than just BoxData will need to join this group. I thought that kernel
                        // always sent cell contents (e.g. Print output) wrapped in ExpressionPacket, but not so.
                        // "Un-wrapped" BoxData is also possible, perhaps others. We need to treat this case
                        // specially, since there is no packet wrapper.
                        SeekMark(mark);
                        pkt = PacketType.Expression;
                    }
                    else
                    {
                        // Note that all other non-recognized functions get labelled as PacketType.FrontEnd. I could perhaps be
                        // more discriminating, but then I risk not recognizing a legitimate communication
                        // intended for the front end. This means that PacketType.FrontEnd is not a specific indication that
                        // a front-end-related packet is on the link. Because there is no diagnostic packet head,
                        // we need to seek back to before the function was read. That way, when programs call
                        // methods to read the "contents" of the packet, they will in fact get the whole thing.
                        SeekMark(mark);
                        pkt = PacketType.FrontEnd;
                    }
                }
                else
                {
                    // The other MathLink error from MLNextPacket is MLENEXTPACKET, which is a common one saying
                    // that you have called MLNextPacket when more data is in the current packet.
                    throw e;
                }
            } finally {
                DestroyMark(mark);
            }
            return(pkt);
        }