Newsgroups: comp.sources.unix From: voodoo@hitl.washington.edu (Geoffery Coco) Subject: v26i197: veos-2.0 - The Virtual Environment Operating Shell, V2.0, Part14/16 Sender: unix-sources-moderator@vix.com Approved: paul@vix.com Submitted-By: voodoo@hitl.washington.edu (Geoffery Coco) Posting-Number: Volume 26, Issue 197 Archive-Name: veos-2.0/part14 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh 'docs/VEOS_The_Complete_Documentation' <<'END_OF_FILE' X X X X X X X X******************************************************************************* X X X X The VEOS project X Human Interface Technology Lab X University of Washington X Seattle, WA X X X X VEOS 2.0 X X Tool Builders Manual X X X X X Geoffrey P. Coco X May 4, 1992 X X X X X X******************************************************************************* X X X X X X X X X******************************************************************************* X X X X X X The VEOS Project Team: X X X William Bricken X Geoff Coco X Dav Lion X Andy MacDonald X X X X X X X X******************************************************************************* X X X X X X X******************************************************************************* X X X CONTENTS: X X X* VEOS License Agreement X X X* What is VEOS X X X* Fundamentals of VEOS X - Entities X - The Grouple X - Grouplespaces X - Pattern Matching X X X* Components of the VEOS Kernel X - Nancy X - Talk X - Shell X X X* Using VEOS from Lisp X - Design Methodology Restated X - VEOS Lisp Interface X - Nancy Pattern Matching Language X - How to Use the Kernel from Lisp X X X* Writing Software Tools in C X - Philosophy (please read this section) X - Building a Custom Entity with Lisp Interface X X X******************************************************************************* X X X X X X******************************************************************************* X* X* X* VEOS 2.0 Copyright (C) 1992 Geoffrey P. Coco, X* Human Interface Technology Laboratory X* X* X* Permission to use, copy, or modify these programs and their documentation X* without fee for educational and research purposes only is hereby granted, X* provided that this copyright notice appears on all copies and supporting X* documentation. For any other uses of this software, in original or modified X* form, including but not limited to distribution in whole or in part, specific X* prior permission must be obtained from HITL. These programs shall not be X* used, rewritten, or adapted as the basis of a commercial software or hardware X* product without first obtaining appropriate licenses from HITL. HITL makes no X* representations about the suitability of this software for any purpose. It is X* provided "as is" without express or implied warranty. X* X* HITL AND GEOFFREY COCO DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, X* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT X* SHALL HITL NOR GEOFFREY COCO BE LIABLE FOR ANY SPECIAL, INDIRECT OR X* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, X* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER X* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE X* OF THIS SOFTWARE. X* X* X* Questions about this software should be addressed to: X* X* Software Support X* Human Interface Technology Laboratory X* FJ-15, University of Washington X* Seattle, Washington 98195 USA X* X* or via email: X* X* veos-support@hitl.washington.edu X* X******************************************************************************* X X******************************************************************************* X X What is VEOS? X X******************************************************************************* X X XVEOS is an extendable environment for prototyping distributed applications for Xunix. The VEOS application programmer's interface is provided by XLISP 2.1 (by XDavid Betz). XLISP provides familiar program control; VEOS provides Xinterprocess message passing and content addressable database access. X XVEOS (The Virtual Environment Operating Shell) was developed for distributed XVirtual Reality applications at The Human Interface Technology Lab in Seattle Xand has been in use for two years. However, VEOS is by no means limited to Xthese types of applications. X XVEOS is ideal for applications where hardware resources are not physically Xproximal or where machine-dependent resources (e.g. software packages, interface Xdevices, etc..) are isolated because of their platform. X XVEOS is also ideal for prototyping programs which employ coarse grain Xparallellism. That is, VEOS uses heavyweight sequential processes, Xcorresponding roughly to unix processes. In this way, VEOS can be used to Xutilize a network of workstations as a virtual multiprocessor. X XC programmers can build custom VEOS tools which are accessable from XLISP and Xthus are immediately compatible with other VEOS tools. Lisp programmers can Xquickly design and run distributed programs utilizing diverse hardware and Xsoftware resources. X XVEOS is not an operating system. VEOS is a user-level framework for prototyping Xdistributed applications. Its primary focus is flexibility and ease of use. XThis design comes somewhat at the expense of real-time performance. This is not Xto say, however, that VEOS cannot achieve good performance with proper Xapplication structuring and tuning. X XRelying on only the most common unix interface, VEOS is platform independent. XVEOS 2.0 has been extensively tested on platforms such as DEC 5000, Sun 4, and XSilicon Graphics VGX and Indigo. X XVEOS, the Virtual Environment Operating Shell, is a software environment for Xprototyping distributed virtual world applications. X X******************************************************************************* X X******************************************************************************* X X Fundamentals of VEOS X X******************************************************************************* X X XWith VEOS, a programmer can specify how to accomplish the many computational Xtasks of a proposed virtual environment. VEOS allows a programmer to clump Xthese tasks into computational nodes of a distributed system. These clumps of Xcomputational tasks are known as 'entities'. X XPresently in VEOS, each entity is implemented as a distinct Unix process with Xthe following native capabilities: interpretation of a coded task description X(presently written in lisp), inter-entity communication, generalized data Xmanagement (akin to tuple architecture), and generic pattern matching over local Xdata space. X XWith VEOS, a designer can implement a virtual environment using a set of Xentities, each residing on the same or different Unix based machines (presumimg Xnetwork accessibility). Furthermore, because VEOS relies only on the most Xcommon Unix interface, one virtual environment application may utilize multiple Xhardware platforms. X XThe best method for utilizing VEOS entities as nodes in a distributed Xapplication greatly depends on the parameters of the applcation (e.g. the Xcomputational resources available, the topology of the network, the location and Xcompatibility of interface devices, etc..). Consequently, the VEOS design, Xwhereever possible, foregoes making policy decisions so that the programmer Xenjoys maximum flexibility in designing a distributed application. X XVEOS programmers have had mixed results with various distributed models (e.g. XThe Fern System). It should prove useful to study these prototypical models for Xsubtleties before attempting a full-scale distributed application with VEOS. X X X X Entities X ... X X XSince VEOS is intended as a software platform for distributed virtual Xenvironment applications, a primary design focus was the mechanism for Xspecifying the tasks and assigning computational resources in a distributed Xdesign. The resulting model is the following. X XA VEOS application is broken down into distinct processes which are as Xself-reliant as possible (the more self-reliant, the more efficient the whole Xsystem will be). Each process can be coded separately with provisions for Xcommunicating with the other processes in the system. Each process is Ximplemented by a single VEOS entity on any network accessible Unix workstation. X XA VEOS entity, then, is a stand-alone executable program that is equipped with Xthe same VEOS native capabilities: data management, process management, and Xinter-entity communication. X X X The Grouple X ... X XOne of VEOS's aims is to support a consistent and general format for program Xspecification, inter-entity communication and database management. X X XIndependently, these needs can be solved by some existing methods. For example, XLisp provides generalized data abstraction (i.e. lists), and useful program Xcontrol. Mathematica provides a generalized specification format and consistent Xtreatment of data and function. Linda provides generalized data management. X X XBut these tools do not share a common form. In addition, large components of Xthese systems are extraneous for most situations. Thus, intergrating such Xpackages would prove costly and wasteful. Moreover, tying together such varied Xsystems emphasizes the differences between their respective forms and Xexpressions rather than their commonalities. X XConsequently, we chose an enhancement to the tuple as the VEOS general format. XThis format is called the 'grouple'. Grouples can be seen as a nestable tuples. XGrouples are extrordinarily general for flexibility, yet the data they contain Xcan be accessed specifically for debugging and performance efficiency. The Xsubfields of a grouple are called 'elements'. As grouples can be nested, an Xelement can be a grouple. X XNancy, the VEOS data manager uses the grouple for it's standard data format. XTalk, the VEOS communications module, transports linearized grouple stuctures. X XVEOS now has a lisp interface. The Lisp language was chosen because there is a Xclear mapping from lisp lists to VEOS grouples. Furthermore, because lisp Xboasts program-data equivalence, programmers can store and pass fragments of Xentity specification using the VEOS kernel mechanisms. X X X Grouplespaces X ... X XTechnically, a grouplespace is an ordinary grouple. There are two grouplespaces Xassociated with an entity which partition the entity's data according to the Xfollowing semantics. X XThe grouplespaces are: the workspace, the programmer's runtime database. And Xthe inspace, where incoming inter-entity messages are placed. In VEOS 2.0, the Xinspace has been bypassed as an efficiency concern. X X X Pattern Matching X ... X XThe regime of pure algebraic reduction is well known to provide the ability to Xperform many kinds of computation (see prolog). This scheme, also known as the XMatch/Substitute/Execute paradigm (ex. in expert systems) can be implemented Xusing a pattern matching mechanism. X XNancy supports pattern matching over its grouplespaces. A pattern is a specific Xform that data can take. Patterns can contain specific data to match or Xwildcard symbols which can be used to bind variables to values. For specifics Xof the Nancy Pattern Matching Language, see the section Using VEOS from Lisp. X X X X******************************************************************************* X X Components of the VEOS Kernel X X******************************************************************************* X X X Nancy: The VEOS grouple manager X ... X XNancy is a homebrew database manager designed specifically for the VEOS project. XMuch like Linda systems manage data as tuples, Nancy mananges data as grouples. X XNancy performs all grouple manipulation within VEOS. This involves creation, Xdestruction, insertion, copying, etc.. Since Nancy grouplespaces are merely Xnamed grouples, these are also an entity's fundamental database operations. X XIn addition, Nancy provides a powerful semantic for data searching, inserting Xand replaceing within a grouplespace. This is the pattern matcher. It is a Xcomplete set of primitives to implement a match/substitute/execute engine as in Xan expert system. X XFrom lisp, programmers have access to three Nancy operations, vput, vcopy and Xvget. These are sufficient for all grouplespace operations. As lisp Xexpressions are passed to these nancy primitives, they are converted to grouple Xformat and then handled by nancy's standard C interface. X X X X Talk: The VEOS communications module X ... X XTalk is the only supported mechanism for entity communication. As VEOS entities Xprovide coarse grain parallelism though Unix processes, process (entity) Xsynchronization and shared memory is not practical. Thus VEOS supports message Xpassing as the only means of entity communication. X XTalk provides VEOS with two simple message passing primitives, vthrow and Xvcatch. From lisp, programmers can transmit a message *asynchronously* to Xanother entity. The receiving entity is then at leisure to receive the message, Xalso *asynchronously*. X XAsynchronous message passing means this: When an entity tranmits a message, the Xoperation succeeds *reliably*, whether the receiver is waiting for a message or Xnot. Likewise, an entity can always check for incoming messages without waiting Xindefinitely for a message to arrive. This is also called non-blocking Xcommunication. X XTalk passes messages between entities with a flat linearized grouple format. XThe lisp/veos interface module performs this translation. X X X X Shell: The VEOS kernel control module X ... X XThe shell is the administrative workings of the VEOS kernel. It dispatches Xinitializations, interrupt handling, manages kernel memory, etc.. X X X******************************************************************************* X X Using VEOS from LISP X X******************************************************************************* X X X ---------------- X veos methodology X---------------- X X Xthe veos kernel provides: X X 1. fast and powerful local database access. X - built-in pattern matching. X - internal grouple form converts to lisp lists. X X 2. clean and reliable message passing. X - utilizes Berkeley sockets. X - symbolic entity addressing. X X 3. well defined C interface. X - can be retrofit to any high-level language (like lisp). X X X X --------------------- X getting your feet wet X--------------------- X X X* Get an account on a Unix machine that supports VEOS (Suns, DECs, SGs). X X* Make sure /home/veos/bin/ is in your path. X X* You are ready to run a basic VEOS entity. The basic VEOS entity with is built X with an xlisp interface. What you get is complete xlisp plus the VEOS native X primitives described in the next section. X X You can run entities at least two ways: X X 1. Type 'entity' at the Unix command line. X X 2. Alternatively (and recommended), you can run entities from inside emacs. X X Within emacs, do meta-x eval-expression: X (setq inferior-lisp-program "/home/veos/bin/entity") X or put this line in your .emacs file. X X Then, do meta-x run-lisp. Once in this emacs mode, you can do meta-x X describe-mode to learn about fancy emacs features with respect to lisp X interaction. X X* To load a program into lisp, type (load "filename.lsp") to lisp. X X X X --------------------- X veos kernel interface X--------------------- X X Currently xlisp provides the abstract access to veos kernel capabilities. The X following describes the native priitives as of February 8, 1992. X X X startup veos kernel from lisp X ''''''''''''''''''''''''''''' X (vinit ) X ; initialize veos kernel, X ; establish network port for incoming messages. X ; if port number is not given, veos chooses an available port. X ; vinit returns uid of this entity upon success X X X takedown veos kernel from lisp X '''''''''''''''''''''''''''''' X (vclose) X ; takedown veos kernel, X ; cleanup network connections. X ; xlisp (exit) function will also perform necessary veos takedown. X X X kernel system tasking X ''''''''''''''''''''' X (vtask) X ; pass control to veos kernel to perform network activity. X ; for best performance, call vtask every time through X ; the entity's main loop, calling (vcatch) immediately X ; afterward. X X X local grouplespace access X ''''''''''''''''''''''''' X (vput :freq <"all"> ) X ; add data to local grouplespace. X ; data element can be a list. X ; pattern for vput may contain ^. X ; optional frequency key-argument ("all" is only value allowed) X ; requests exaustive matching. X X (vcopy :test-time :freq <"all"> ) X ; non-destructive local grouplespace query. X ; pattern for vcopy may not contain ^. X ; optional timestamp key-argument must be created by (vmintime) X ; given timestamp is modified in place. X X (vget :freq <"all"> ) X ; destructive local grouplespace query. X ; pattern for vget may not contain ^. X X (vmintime) X ; returns a guaranteed oldest time stamp. X X ; see below for nancy pattern language specification. X X X message passing X ''''''''''''''' X (vthrow (destination1 destination2 ...) (lisp expression) ) X ; send to a list of desinations. X ; list may contain zero or one destination, and X ; the same destination may appear more than once. X ; destination is lisp vector of hostname and port number, X ; ex. '#("vorpal" 7800) X ; message is appended to each desination's incoming grouplespace. X X (vcatch ) X ; perform standard nancy pattern match from incoming grouplespace. X ; acts like vget in all other ways. X ; since new messages are appended, oldest message is at top. X ; to simply retrieve oldest message, use: (vcatch '(> @ @@)). X X ; NOTE: currently, VEOS 2.0 does not support X ; the pattern argument for efficiency reasons. X ; (vcatch) simply returns the oldest available message. X X X ------------------------- X caveats of xlisp for veos X------------------------- X XThere are many types of VEOS data elements. The most common and useful element Xtypes to programmers are available from lisp. The VEOS types that are supported Xby lisp are: X X VEOS equivalent in Lisp X ------ -------------------- X X grouple list - NIL or () is the empty grouple X X integer integer - use a regular number X X float float - use a decimal point X X string string - use "" to make a string X X XLikewise, lisp supports many data element types. There is an equivalent data Xelement in VEOS for some of these. The data elements that VEOS supports are Xthose listed above and the following: X X Lisp equivalent in VEOS X ------ -------------------- X X symbol * prim type. X X vector special grouple X X X* A symbol in lisp can be used for a variable, function, or be unbound. When a X lisp symbol is passed to VEOS (for grouplespace storage of message passing), X VEOS retains the name of the symbol but not the bindings. Lisp normally retains X these symbol bindings. X XAll other lisp data types are unsupported by VEOS. This means that they cannot Xbe passed to Nancy for grouplespace storage. And they cannot be used within Xinter-entity messages. X X X ------------------------------- X nancy pattern matching language X------------------------------- X XNancy controls access to the grouplespaces through a pattern matching language. XThe goals of the language are to provide a succinct format to express the locale Xin the grouplespace you would like to work and what you would like to do there. X XThere are three fundamental grouplespace operations that Nancy provides: X X - find some location (specified by pattern), insert data there. X - find some data (specified by pattern), retrieve it. X - find some data (specified by pattern), retrieve it and replace it with X other data. X X X XThus, these are the rules of nancy pattern matching: X XTo find anything (called a site), specify a pattern. Patterns consist of Xinformation about where the site is and/or specific data that the site contains. X X The ^ (void) symbol specifies a location within a grouple for inserting. It X points to the void between data. Technically, the ^ always matches. X X The > (mark) symbol points to a piece of data within a grouple retrieval or X replacement operation. It designates the immediately following element of X the pattern as the site of action. The > does not itself match data. X X XFor a pattern to be meaningful, one of these symbols (^ or >) must appear Xsomewhere in the pattern. In other words, the pattern must always specify a Xsite of action. X XTo match data within a pattern, you can either specify actual data to compare, Xor wildcard symbols which are content-blind. X X The @ (this) symbol specifies a single element at a specific location within X a grouple. This will match any single element including a grouple. X X The @n (these) symbol specifies exactly n sequential elements within a X grouple. This will match the next n elements. @1 is equivalent to @. X X The @@ (these all) symbol specifies zero or more elements within a grouple. X This will match all the remaining elements in a grouple. This special form X is allowed only at the end of a pattern grouple. X X The ** (any) symbol specifies zero or more elements *anywhere* within a X grouple. This will match all the remaining unmatched elements in a grouple. X This special form is allowed only at the end of a pattern grouple. X X The ~ (touch) symbol specifies that the immediately following element be X 'touched' during a (vput ...) operation. That is, the data that matches X the pattern symbol following the ~ is marked as having been recently X modified. There can be any number of ~ in a pattern. X X Anything else is taken literally and compared with the actual data in the X grouplespace. X X Note that nancy patterns are recursive. That is, a pattern may X contain a grouple which may contain wildcards and data, some of which X are more grouples, etc.. X X XExamples. X XHere is an actual session with lisp. My comments are added. X X;; we begin with an empty grouplespace, ie (). X;; to vput, we match the grouplespace and point to the void within it. X;; thus, the (^) pattern. X;; this is literally where the given data is put. X X> (vput "first" '(^)) XT X X;; here, we reqeusted a simple insert operation. so vput vput return T or NIL X;; depending on the success of the match. during a replace vput operation, vput X;; returns what your action replaced in the grouplespace. in a moment, we'll X;; see when this comes into play. X X X X;; to see the entire contents of the grouplespace, we need to do a X;; nondestructive query. the most succinct way to do this is to match the X;; grouplespace and copy all of its elements: X X> (vcopy '(> @@)) X("first") X X;; note that the @@ can match a single element if there is only one, or it can X;; match many elements if there are more than one. in the latter case, the X;; results are conveniently returned in a list. in the interest of consistency, X;; all nancy results are returned in lists. X X X X;; let's now insert a list after the first element of the grouplespace: X X> (vput '("third") '(@ ^)) XNIL X X;; again, no data was removed in the process. X X X X;; the entire contents... X X> (vcopy '(> @@)) X("first" ("third")) X X X X;; let's now insert an element between the first element and all the rest of the X;; elements in the grouplespace. X X> (vput "second" '(@ ^ @@)) XNIL X X;; note that (@ ^ @) would have also worked anbd would have been more precise. X X X X;; inspect the entire contents X X> (vcopy '(> @@)) X("first" "second" ("third")) X X X X;; here, we are inserting a vector into the grouplespace. X;; this demonstrates two other features. the @2, in the given position in X;; the pattern matches the first two elements of the grouplespace. the "third" in X;; the pattern matches the actual data in the grouplespace. this, of course, is X;; unlike how an @ matches any element where no data is compared. X X> (vput '#(1.4 3.9 9.0) '(@2 ("third" ^))) XNIL X X X X;; the data now resides where the ^ was in the previous pattern. X X> (vcopy '(> @@)) X("first" "second" ("third" #(1.4 3.9 9))) X X X X;; sometimes it is useful to replace existing data in the grouplespace. X;; this can be done by removing, then inserting correct data. X;; or it can be done with a replacing vput. X;; here, we replace the first element of the grouplespace with the given data. X;; we must also match the remaining elements in the grouplespace to achieve a X;; successful match. X X> (vput "uno" '(> @ @@)) X("first") X X;; vput returns the removed data. X X X X;; and the first element has been replaced. X X> (vcopy '(> @@)) X("uno" "second" ("third" #(1.4 3.9 9))) X X X X;; now, let's look at the more subtle features of pattern matching. begin by X;; emptying the current contents of the grouplespace to begin a new session. X X> (vget '(> @@)) X("uno" "second" ("third" #(1.4 3.9 9))) X X X;; confirm that the grouplespace is empty X X> (vcopy '(> @@)) XNIL X X X;; here, we'll insert some new data X X> (vput '("animal" "giraffe") '(^)) XT X> (vput '("plant" "fern") '(^ @)) XT X> (vput '("animal" "lion") '(^ @2)) XT X> (vcopy '(> @@)) X(("animal" "lion") ("plant" "fern") ("animal" "giraffe")) X X X X;; now we can perform useful matches on the grouplespace. suppose we want to X;; find the tag associated with the "fern" data. we simply ask for the element X;; immediately preceding the "fern" element. note the use of the ** wildcard. X;; the ** pattern element has two functions in this pattern. first, like @@ it X;; matches all the reminaing elements in the grouple. second, it explicitly X;; makes the containing grouple an order-independent pattern. in other words, X;; when nancy sees a ** in a pattern grouple, it ignores the order of the source X;; (grouplespace) elements when matching; it matches purely by content. X X> (vcopy '((> @ "fern") **)) X("plant") X X;; note that although the marked element is "plant", but the result is contained X;; within an extra grouple. as explained above, all nancy results are contained X;; within a grouple. X X X X X;; if we want to find the data associated with the tag "animal", we can do a X;; similar match. X X> (vcopy '(("animal" > @) **)) X("lion") X X X X X;; but this is only a partial answer. because there is more than one instance X;; of the tag "animal" at that level of the grouplespace. we may want all the X;; possible matches of this form. X X> (vcopy '(("animal" > @) **) :freq "all") X("lion" "giraffe") X X X;; we can also use this feature with vput to do an exaustive replace. here, X;; xlisp allows the arguments to a function to appear on consecutive lines. X X> (vput "mammal" X '((> "animal" @) **) X :freq "all") X("animal" "animal") X X;; vput returns exactly what it replaced. X;; check that the replace was successful. X X> (vcopy '(> @@)) X(("mammal" "lion") ("plant" "fern") ("mammal" "giraffe")) X X Xnow let's look at the pattern matching features that correspond to the Xdynamic issues of maintaining the grouplespace. specifically, matching that Xis sensitive to the relative ages of the data can be used for so-called X'delta matching'. we can use the previous contents to illustrate. X Xfirst, we'll make a nancy time stamp. X X> (setq ts (vmintime)) X0 X X X;; we'll use this time stamp with vcopy. if you pass a time stamp to vcopy, it X;; perform the given match but only returns matched data that is *younger* than X;; the time stamp. vmintime returns a guaranteed oldest time-stamp. this means X;; that using it will guarantee seeing everything in the grouplespace. X X> (vcopy '(> @@) :test-time ts) X(("mammal" "lion") ("plant" "fern") ("mammal" "giraffe")) X X;; vcopy compared all the matched data against the time stamp, all of it had X;; been modified (with vput) after the time given by the time stamp. X X X X;; vcopy *modifies* your time stamp in place to reflect that you've matched with X;; that pattern. and as you can see, the time stamp has now been modified. X X> ts X1.4013e-44 X X X X;; if we make the same match again with the same time stamp, we see no data. X;; this corresponds to there being no change (or delta) in the data since we X;; last matched. X X> (vcopy '(> @@) :test-time ts) XNIL X X X X;; let's insert some new data to see how the delta will be shown. X X> (vput '("mammal" "fox") '(> (@ "lion") **)) X(("mammal" "lion")) X X X X;; when we match the entire grouplespace with our time stamp, we only get the X;; new data, since it was added since our last match. X X> (vcopy '(> @@) :test-time ts) X(("mammal" "fox")) X X X X;; again the time stamp has been modified in place to reflect a new matching. X;; here we inspect the time stamp only to show that is has been changed. the X;; actual value in the time stamp is irrelevant - it used internally by nancy. X X> ts X1.82169e-44 X X X Xnotice that above we replaced both the data and the tag ("mammal" "fox") in Xthe grouplespace. suppose that we want to replace only the data in the Xgrouplespace. X X> (vput "carrot" '((@ > "fern") **)) X("fern") X X> (vcopy '(> @@) :test-time ts) X(("carrot")) X X;; as expected, vcopy returns only the changed data. X X X X;; above, the changed data is ambiguous without its tag. but the tab was not X;; modified and so is not returned. we can use the 'touch' feature during a X;; vput to mark elements in the grouplespace as having also been modified. X X> (vput "palm" '((~ @ > "carrot") **)) X("carrot") X X;; note the ~ pattern modifier. if the pattern successfully matches, nancy X;; 'touches' the element following the ~ in the pattern as having been modified. X X X X> (vcopy '(> @@) :test-time ts) X(("plant" "palm")) X X;; and this is exactly what we wanted. X;; unlike the > or ^ symbols, you can any number of ~ in a vput pattern. X X X X;; it is important to remember that a single time stamp represents the most X;; recent match of a *particluar* pattern from a *particular* point of view. X;; for example, if you're writing program for a server entity to which many X;; entities make matching requests, the server should maintain a time stamp for X;; each entity and each pattern type. see the fx.lsp file of the Fern System X;; for examples of this strategy. X X X --------------------- X how to use the kernel X--------------------- X X - since all behavior description is specified in lisp, (and thus all X kernel primitive composition), lisp's native evaluation mechanism is X best suited to direct flow control. X X - it is an explicit goal of veos to provide program distribution X services to generic programming frameworks. that is, the language we X supplant above veos must be independent of the kernel X implementation. were process control a kernel resposibility, the X kernel would require language-specific maintenance and would directly X oppose the stated fundamental premise. X X - the mechanism in lisp for handling entity process management is available. X it consists of a main processing loop as described below. each pass X through the loop can be thought of as a 'frame'. that is, one complete X cycle through all an entity's responsibilities constitutes a quanta X of entity activity. X X X 1. invoke kernel maintenance. X X this entails polling network, garbage collection, etc.. X X X 2. gather waiting inter-entity messages. X X this process can be augmented by filtering. In VEOS 2.0, X this filtering feature has been disabled for performance reasons. X X X 3. evaluate messages from (2). X X implemented with lisp's eval. X X eval directs program control to the 'program stubs' contained X within the messages. thus, messages are single lisp X expressions. for example, the message: X (add-to-database (frog x1 y1) (bird x2 y2)) X is a program stub that when evaluated by lisp will invoke the X function 'add-to-database' with the arguments (frog x1 y1) X and (bird x2 y2). X X X 4. give processing burst to background tasks. X X remember that each entity is a single unix process. and in general, a X process is the smallest grain of parallelism that unix supports. X consequently, there is no explicit provision in veos for concurrency X (e.g. lightweight threads) *within* an entity. X X but sometimes it is conceptually easier to design a program with X concurrency in mind. this desire for parallelism can be fulfilled X with virtual processes. X X given this regime of processing 'frames', programmers may simulate X concurrent processes with discrete background tasks. these tasks can X be implemented as functions (program stubs) which perform a frame of X computation and quickly return. X X the process table is a lisp association list of program stubs. X program stubs are small fragments of lisp code that can compose an X entity's behavior program stubs should never block. X X - an entity's main processing loop can be expressed in lisp by: X X (defun go () X (loop X (do-frame))) X X (defun do-frame () X (progn X X ;; kernel maintenance X (vtask) X X ;; gather and evaluate waiting messages X (do ((msg (vcatch))) X ((null msg)) X X (eval msg) X (setq msg (vcatch)) X ) X X ;; give processing burst to background processes X (dolist (proc background-procs) X (eval (cadr proc))) X )) X X X - since VEOS is intended as a prototyping system, the design is based X less on performance considerations and more on reliable functionality. X you will notice that the above scheme ignores many real-time issues. X X for example, messages may arrive while an the entity is servicing X background processes. thus, messages must wait an average of half the X time of a processing frame before being evaluated. thus, when an X entity is heavily loaded, there may be significant latency in message X passing. this can be troublesome when attempting to sychronize X entities though message passing. X X likewise, important work may be waiting in the backgound processes while X the entity is servicing messages. this can be troublesome when X attempting to ensure reliable interface device update rates. X X these problems can be lessened through judicious use of inter-entity X messages (i.e. as few and small as possible) and through efficient and X sparing use of background tasks. X X X - The Fern System is a good example of how to use VEOS from lisp. It X is included with the VEOS distribution. X X******************************************************************************* X X Writing Software Tools in C X X******************************************************************************* X X X== Philosophy == X XAny software tool can be integrated with VEOS. However, certain features of Xsoftware tools make them easier to integrate. The process of VEOSifying a Xsoftware tool is writing custom lisp primitives (usually in C) which decode lisp Xarguments and pass control to the software tool. X XGiven that all control will be passed to a tool via lisp primitives, the XVEOSified tool will perform best if it is: X Xnon-blocking: X That is, primitives should always return after a reasonable slice of time X (depends on application). X Xinterrupt-driven is ok: X As long as primitive entry points appear to accomplish their tasks quickly X (use static caches, etc..). In fact, for polling type software tools (input X device drivers, etc..), interrupts are preferrable to timeout reads in some X situations. Especially when data arrival is infrequent. X Xmodular: X The tool should perform distinct, well-defined tasks. This assists the lisp X programmer with task specification. And it makes writing custom primitives X easy. X Xrobust: X Eg, can handle lags in data flow, can handle out-of-band data, etc.. X Remember, world designers will want to rely on these distributed services. X X X X X== Building a Custom Entity with Lisp Interface == X X XThe xlisp that is bound with with VEOS is a software library that anybody can Xuse. You can compile the xlisp library once, then link in user-defined lisp Xprimitives at runtime. Or, you can recompile xlisp by declaring user-defined Xprimitives in advance as the xlisp documentation describes. This section only Xdescribes the dynamic scheme for binding xlisp primitives. X XTo use this version of xlisp, you need to provide two functions that xlisp Xexpects. X XThe first function ( xlinclude_hybrid_prims() ) supplies xlisp with the function Xpointers of your user-defined primitives (also called hybrid primitives). If Xyou're not binding any user-defined primitives (ie. making basic xlisp w/o XVEOS), this function should have an empty body. See file X/home/xlisp/xexec/c/main.c for an example of the bare-bones main. X XThe second function ( xlhybrid_shutdown() ) gives user defined modules a chance Xto clean their respective environments become xlisp exits. xlisp will call this Xfunction just before a graceful exit. Again, if no special actions are to be Xtaken, give this function an empty body. X XLastly to use this version of xlisp, you need to provide a main() function. In Xyour main(), do any setup that is required, then call xlisp's main ( xmain() ). Xxmain() will never return. Notice that VEOS does not do any setup in main() X(see example file below). Instead, kernel setup is a lisp primitive. This Xpractice is encouraged since it allows users to decide when to use particular Xmodules. X XWhat follows are the step-by-step instructions to build a VEOS entity with xlisp Xand and other custom software tools: X X1. Create a main control file that minimally looks like this: X X X/*************************************************************************************** X * Copyright (C) 1992 Human Interface Technology Lab, Seattle * X ****************************************************************************************/ X X#include "world.h" Xextern xmain(); X X X/*************************************************************************************** X * main X * launchpad of any stand-alone program X ****************************************************************************************/ Xmain(argc, argv) X int argc; X char *argv[]; X{ X /** call the xlisp controller, never returns **/ X xmain(argc, argv); X } X X X/*************************************************************************************** X * xlinclude_hybrid_prims X * lisp calls this function to load user-defined lisp primitives X ****************************************************************************************/ Xxlinclude_hybrid_prims() X{ X /** load veos native lisp primitive entries. X ** this function lives in the xvnative_glue library X **/ X Shell_LoadNativePrims(); X X X /** here, make calls to other software tool setup functions **/ X MyModule_LoadMyPrims(); X } X X X X/*************************************************************************************** X * xlshutdown_hybrid X * lisp calls this function before graceful exit X ****************************************************************************************/ Xxlshutdown_hybrid() X{ X /** let the kernel unwind X ** this function lives in the kernel library X **/ X Kernel_Shutdown(); X X /** here, make calls to other software tools shutdown code **/ X } X X X2. Create a file that contains your primitives. Write C functions which handle X lisp arguments. These functions are the glue between your software and X lisp (ie. your primitives). See the kernel interface files, xv_native.c and X xv_glutils.c, for model code. You may use any of the utilities found in X these files. The functions themselves are compiled into the xvnative_glue X library. X X In this file, provide xlisp with the function pointers to your primitives. In X step 1, the function xlinclude_hybrid() loads all the user-defined prims. In X addition to loading the native kernel primitives, it should call a function like X this to load your primitives into lisp: X X X#include "xlisp.h" X X/*************************************************************************************** X * MyModule_LoadMyPrims X * load user-defined lisp primitives X ***************************************************************************************/ XTVeosErr MyModule_LoadMyPrims() X{ X DEFINE_SUBR( "ROLLOVER", Tricks1_RollOver ) X DEFINE_SUBR( "PLAYDEAD", Tricks2_PlayDead ) X DEFINE_SUBR( "FETCH", Tricks3_Fetch ) X DEFINE_SUBR( "GONUTS", Tricks4_GoNuts ) X X DEFINE_FSUBR( "REPEAT", Tricks5_Repeat ) X X /** NOTES: X ** X ** No semicolon is necessary after these macros. X ** This is to preserve compatibility with another xlisp X ** mechanism for including user-defined functions. X ** X ** First arg is name you want prim to be in lisp, use all CAPS. X ** Second arg is actual C function, must return an LVAL. X ** Use DEFINE_FSUBR for lisp special forms. X ** Most likely you wont need them. X **/ X X return(VEOS_SUCCESS); X } X/***************************************************************************************/ X X X3. Compile your main and primitives and link with the options: X X -L/home/veos/lib/ X -lxlisp -lxvnative_glue -lkernel X X See VEOS kernel makefile for example build sequence. X Don't forget to link to the software packages which contain included primitives. X Notice that the kernel and the kernel interface to lisp are separate libraries. X X X4. Now you have a stand-alone entity. This entity should behave just like the X base-level entity for application-nonspecific tasks, ie. standard lisp. END_OF_FILE if test 41783 -ne `wc -c <'docs/VEOS_The_Complete_Documentation'`; then echo shar: \"'docs/VEOS_The_Complete_Documentation'\" unpacked with wrong size! fi # end of 'docs/VEOS_The_Complete_Documentation' fi if test -f 'src/kernel_current/shell/xv_glutils.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'src/kernel_current/shell/xv_glutils.c'\" else echo shar: Extracting \"'src/kernel_current/shell/xv_glutils.c'\" \(43094 characters\) sed "s/^X//" >'src/kernel_current/shell/xv_glutils.c' <<'END_OF_FILE' X/**************************************************************************************** X * * X * file: xv_glutils.c * X * * X * Sundry utilities which serve as glue for xlisp veos primitives. * X * * X * creation: April 13, 1992 * X * * X * * X * by Geoffrey P. Coco at the HITLab, Seattle. * X * * X ****************************************************************************************/ X X X/**************************************************************************************** X * Copyright (C) 1992 Geoffrey P. Coco, Human Interface Technology Lab, Seattle * X ****************************************************************************************/ X X X X/**************************************************************************************** X * preliminaries */ X X#include X#include "xlisp.h" X X/* VEOS definitions: */ X#include "kernel.h" X X#define NATIVE_CODE X#include "xv_native.h" X#undef NATIVE_CODE X X/****************************************************************************************/ X Xextern LVAL xsendmsg0(); Xextern LVAL s_unbound; Xextern LVAL true; Xextern LVAL xlfatal(); X X/****************************************************************************************/ X Xboolean native_bSubstBeenMarked; Xboolean native_bVoidBeenMarked; Xboolean native_bDestruct; X X#define SUBST native_bSubstBeenMarked X#define VOID native_bVoidBeenMarked X#define MOD native_bDestruct X X/****************************************************************************************/ X XTVeosErr Native_PatVEltClerical(); Xextern LVAL ReverseList(); X X/****************************************************************************************/ X X X X X/**************************************************************************************** X Basic Xlisp <--> Nancy Conversion X ****************************************************************************************/ X X X/****************************************************************************************/ XTVeosErr Native_XEltToVElt(pXElt, pVElt) X LVAL pXElt; X TPElt pVElt; X{ X TVeosErr iErr; X X iErr = VEOS_FAILURE; X X X /** NIL is the empty grouple **/ X X if (null(pXElt)) { X iErr = Nancy_NewGrouple(&pVElt->u.pGr); X pVElt->iType = GR_grouple; X } X X X /** case-wise conversion to nancy format **/ X X else { X switch (ntype(pXElt)) { X X case CONS: X /** a list becomes a grouple **/ X iErr = Native_ListToGrouple(pXElt, &pVElt->u.pGr); X pVElt->iType = GR_grouple; X break; X X case VECTOR: X /** a vector becomes a special grouple **/ X iErr = Native_VectToGrouple(pXElt, &pVElt->u.pGr); X pVElt->iType = GR_vector; X break; X X case FIXNUM: X pVElt->iType = GR_int; X pVElt->u.iVal = getfixnum(pXElt); X break; X X case FLONUM: X pVElt->iType = GR_float; X pVElt->u.fVal = (float) getflonum(pXElt); X break; X X case STRING: X pVElt->iType = GR_string; X pVElt->u.pS = strdup((char *) getstring(pXElt)); X break; X X case SYMBOL: X pVElt->iType = GR_prim; X pVElt->u.pS = strdup(getstring(getpname(pXElt))); X break; X X default: X iErr = NATIVE_BADVTYPE; X break; X X } X } X X return(iErr); X X } /* Native_XEltToVElt */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XTVeosErr Native_ListToGrouple(pList, hGrouple) X LVAL pList; X THGrouple hGrouple; X{ X TVeosErr iErr; X LVAL pXFinger; X int iElt; X TPGrouple pGrouple; X TPElt pVFinger; X X X *hGrouple = nil; X X iErr = Nancy_NewGrouple(&pGrouple); X iElt = 0; X X /** convert each lisp sub-element **/ X X pXFinger = pList; X while (!null(pXFinger) && iErr == VEOS_SUCCESS) { X X X /** make room for another grouple element **/ X X Nancy_NewElementsInGrouple(pGrouple, iElt, 1, GR_unspecified, 0); X X X /** do actual element conversion **/ X X iErr = Native_XEltToVElt(car(pXFinger), &pGrouple->pEltList[iElt]); X X X /** advance element refs **/ X X iElt ++; X pXFinger = cdr(pXFinger); X X } /* while */ X X X if (iErr == VEOS_SUCCESS) X *hGrouple = pGrouple; X else X Nancy_DisposeGrouple(pGrouple); X X X return(iErr); X X } /* Native_ListToGrouple */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XTVeosErr Native_VectToGrouple(pVect, hGrouple) X LVAL pVect; X THGrouple hGrouple; X{ X TVeosErr iErr; X int iElts, iEltIndex; X TPGrouple pGrouple; X TPElt pVElt; X X *hGrouple = nil; X X iErr = Nancy_NewGrouple(&pGrouple); X X X iElts = getsz(pVect); X if (iElts > 0 && iErr == VEOS_SUCCESS) { X X /** make enough room for all impending elements **/ X X iErr = Nancy_NewElementsInGrouple(pGrouple, 0, iElts, GR_unspecified, 0); X X X X /** convert each lisp sub-element **/ X X iEltIndex = 0; pVElt = pGrouple->pEltList; X while (iEltIndex < iElts && iErr == VEOS_SUCCESS) { X X iErr = Native_XEltToVElt(getelement(pVect, iEltIndex), pVElt); X X iEltIndex ++; pVElt ++; X } X } X X if (iErr == VEOS_SUCCESS) X *hGrouple = pGrouple; X else X Nancy_DisposeGrouple(pGrouple); X X X return(iErr); X X } /* Native_VectToGrouple */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XTVeosErr Native_VEltToXElt(pVElt, hXElt) X TPElt pVElt; X LVAL *hXElt; X{ X TVeosErr iErr; X X X *hXElt = NIL; X X iErr = VEOS_SUCCESS; X X switch (pVElt->iType) { X X case GR_grouple: X iErr = Native_GroupleToList(pVElt->u.pGr, hXElt); X break; X X case GR_vector: X iErr = Native_GroupleToVect(pVElt->u.pGr, hXElt); X break; X X case GR_int: X *hXElt = cvfixnum(pVElt->u.iVal); X break; X X case GR_float: X *hXElt = cvflonum(pVElt->u.fVal); X break; X X case GR_string: X *hXElt = cvstring(pVElt->u.pS); X break; X X case GR_prim: X *hXElt = xlenter(pVElt->u.pS); X break; X X case GR_unspecified: X iErr = NATIVE_EMPTYELT; X break; X X default: X iErr = NATIVE_BADXTYPE; X break; X X } X X return(iErr); X X } /* Native_VEltToXElt */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XTVeosErr Native_GroupleToList(pGrouple, hList) X TPGrouple pGrouple; X LVAL *hList; X{ X TVeosErr iErr; X LVAL pNewXElt, pList; X int iElts, iElt; X X xlstkcheck(2); X xlsave(pNewXElt); X xlsave(pList); X X iErr = VEOS_SUCCESS; X iElts = pGrouple->iElts; X iElt = iElts - 1; X X while (iElt >= 0 && iErr == VEOS_SUCCESS) { X X iErr = Native_VEltToXElt(&pGrouple->pEltList[iElt], &pNewXElt); X if (iErr == VEOS_SUCCESS) X pList = cons(pNewXElt, pList); X X iElt --; X } X X *hList = pList; X X xlpopn(2); X X return(iErr); X X } /* Native_GroupleToList */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XTVeosErr Native_GroupleToVect(pGrouple, hVect) X TPGrouple pGrouple; X LVAL *hVect; X{ X TVeosErr iErr; X LVAL pNewXElt, pVect; X int iElts, iElt; X X xlstkcheck(2); X xlsave(pVect); X xlsave(pNewXElt); X X iErr = VEOS_SUCCESS; X iElts = pGrouple->iElts; X iElt = 0; X X pVect = newvector(iElts); X X while (iElt < iElts && iErr == VEOS_SUCCESS) { X X iErr = Native_VEltToXElt(&pGrouple->pEltList[iElt], &pNewXElt); X if (iErr == VEOS_SUCCESS) X setelement(pVect, iElt, pNewXElt); X X iElt ++; X } X X *hVect = pVect; X X xlpopn(2); X X return(iErr); X X } /* Native_GroupleToVect */ X/****************************************************************************************/ X X X X/**************************************************************************************** X Timestamped Xlisp <--> Nancy Conversion X ****************************************************************************************/ X X/****************************************************************************************/ XTVeosErr Native_NewVEltToXElt(pVElt, hXElt, time) X TPElt pVElt; X LVAL *hXElt; X TTimeStamp time; X{ X TVeosErr iErr; X X *hXElt = NIL; X iErr = NATIVE_STALE; X X if (TIME_LESS_THAN(pVElt->tLastMod, time)) { X X /** old data, retrieve only contents of containers X **/ X if (pVElt->iType == GR_grouple) X iErr = Native_NewGroupleToList(pVElt->u.pGr, hXElt, time); X X else if (pVElt->iType == GR_vector) X iErr = Native_NewGroupleToVect(pVElt->u.pGr, hXElt, time); X } X X else { X /** new data, retrieve completely **/ X X switch (pVElt->iType) { X X case GR_grouple: X iErr = Native_GroupleToList(pVElt->u.pGr, hXElt); X break; X X case GR_vector: X iErr = Native_GroupleToVect(pVElt->u.pGr, hXElt); X break; X X case GR_int: X *hXElt = cvfixnum(pVElt->u.iVal); X iErr = VEOS_SUCCESS; X break; X X case GR_float: X *hXElt = cvflonum(pVElt->u.fVal); X iErr = VEOS_SUCCESS; X break; X X case GR_string: X *hXElt = cvstring(pVElt->u.pS); X iErr = VEOS_SUCCESS; X break; X X case GR_prim: X *hXElt = xlenter(pVElt->u.pS); X iErr = VEOS_SUCCESS; X break; X X case GR_unspecified: X iErr = NATIVE_EMPTYELT; X break; X X default: X iErr = NATIVE_BADXTYPE; X break; X X } X } X X return(iErr); X X } /* Native_NewVEltToXElt */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XTVeosErr Native_NewGroupleToList(pGrouple, hList, time) X TPGrouple pGrouple; X LVAL *hList; X TTimeStamp time; X{ X TVeosErr iErr = VEOS_SUCCESS; X LVAL pNewXElt, pList; X int iElts, iElt; X TPElt pVElt; X boolean bStale = TRUE; X X xlsave1(pNewXElt); X xlsave1(pList); X X iElts = pGrouple->iElts; X iElt = iElts - 1; X X while (iElt >= 0) { X X /** determine if caller has already seen this data **/ X X iErr = Native_NewVEltToXElt(&pGrouple->pEltList[iElt], &pNewXElt, time); X if (iErr == VEOS_SUCCESS) { X /** assume caller has locked this ptr **/ X X pList = cons(pNewXElt, pList); X bStale = FALSE; X } X X else if (iErr == NATIVE_STALE) X iErr = VEOS_SUCCESS; X X else X break; X X iElt --; X } X X if (iErr == VEOS_SUCCESS) { X if (bStale) X iErr = NATIVE_STALE; X X *hList = pList; X } X X xlpopn(2); X X return(iErr); X X } /* Native_NewGroupleToList */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XTVeosErr Native_NewGroupleToVect(pGrouple, hVect, time) X TPGrouple pGrouple; X LVAL *hVect; X TTimeStamp time; X{ X TVeosErr iErr = VEOS_SUCCESS; X LVAL pNewXElt, pVect; X int iElts, iElt; X boolean bStale = TRUE; X X xlsave1(pNewXElt); X xlsave1(pVect); X X iElts = pGrouple->iElts; X pVect = newvector(iElts); X X iElt = 0; X X while (iElt < iElts) { X X iErr = Native_NewVEltToXElt(&pGrouple->pEltList[iElt], &pNewXElt, time); X if (iErr == VEOS_SUCCESS) { X X /** assume caller has locked this ptr **/ X X setelement(pVect, iElt, pNewXElt); X bStale = FALSE; X } X X else if (iErr == NATIVE_STALE) X iErr = VEOS_SUCCESS; X X else X break; X X iElt ++; X } X X if (iErr == VEOS_SUCCESS) { X if (bStale) X iErr = NATIVE_STALE; X X *hVect = pVect; X } X X xlpopn(2); X X return(iErr); X X } /* Native_NewGroupleToVect */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XTVeosErr Native_XEltToNewVElt(pXElt, pVElt, time) X LVAL pXElt; X TPElt pVElt; X TTimeStamp time; X{ X TVeosErr iErr; X X iErr = VEOS_SUCCESS; X X X /** NIL is the empty grouple **/ X X if (null(pXElt)) { X pVElt->iType = GR_grouple; X iErr = Nancy_NewGrouple(&pVElt->u.pGr); X } X X /** case-wise conversion to nancy format **/ X X else { X switch (ntype(pXElt)) { X X case CONS: X /** a list becomes a grouple **/ X iErr = Native_ListToNewGrouple(pXElt, &pVElt->u.pGr, time); X pVElt->iType = GR_grouple; X break; X X case VECTOR: X /** a vector becomes a special grouple **/ X iErr = Native_VectToNewGrouple(pXElt, &pVElt->u.pGr, time); X pVElt->iType = GR_vector; X break; X X case FIXNUM: X pVElt->iType = GR_int; X pVElt->u.iVal = getfixnum(pXElt); X break; X X case FLONUM: X pVElt->iType = GR_float; X pVElt->u.fVal = (float) getflonum(pXElt); X break; X X case STRING: X pVElt->iType = GR_string; X pVElt->u.pS = strdup((char *) getstring(pXElt)); X break; X X case SYMBOL: X pVElt->iType = GR_prim; X pVElt->u.pS = strdup(getstring(getpname(pXElt))); X break; X X default: X iErr = NATIVE_BADVTYPE; X break; X X } X } X X pVElt->tLastMod = time; X X return(iErr); X X } /* Native_XEltToNewVElt */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XTVeosErr Native_ListToNewGrouple(pList, hGrouple, time) X LVAL pList; X THGrouple hGrouple; X TTimeStamp time; X{ X TVeosErr iErr; X LVAL pXFinger; X int iElt; X TPGrouple pGrouple; X TPElt pVFinger; X X xlsave1(pXFinger); X X *hGrouple = nil; X X iErr = Nancy_NewGrouple(&pGrouple); X iElt = 0; X X X /** convert each lisp sub-element **/ X X pXFinger = pList; X while (!null(pXFinger) && iErr == VEOS_SUCCESS) { X X X /** make room for another grouple element **/ X X Nancy_NewElementsInGrouple(pGrouple, iElt, 1, GR_unspecified, 0); X X X /** do actual element conversion **/ X X iErr = Native_XEltToNewVElt(car(pXFinger), &pGrouple->pEltList[iElt], time); X X X /** advance element refs **/ X X iElt ++; X pXFinger = cdr(pXFinger); X X } /* while */ X X X if (iErr == VEOS_SUCCESS) X *hGrouple = pGrouple; X else X Nancy_DisposeGrouple(pGrouple); X X xlpop(); X X return(iErr); X X } /* Native_ListToNewGrouple */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XTVeosErr Native_VectToNewGrouple(pVect, hGrouple, time) X LVAL pVect; X THGrouple hGrouple; X TTimeStamp time; X{ X TVeosErr iErr; X int iElts, iEltIndex; X TPGrouple pGrouple; X X X *hGrouple = nil; X X iErr = Nancy_NewGrouple(&pGrouple); X X X iElts = getsz(pVect); X if (iElts > 0 && iErr == VEOS_SUCCESS) { X X /** make enough room for all impending elements **/ X X iErr = Nancy_NewElementsInGrouple(pGrouple, 0, iElts, GR_unspecified, 0); X X X X /** convert each lisp sub-element **/ X X iEltIndex = 0; X while (iEltIndex < iElts && iErr == VEOS_SUCCESS) { X X iErr = Native_XEltToNewVElt(getelement(pVect, iEltIndex), X &pGrouple->pEltList[iEltIndex], time); X iEltIndex ++; X } X } X X if (iErr == VEOS_SUCCESS) X *hGrouple = pGrouple; X else X Nancy_DisposeGrouple(pGrouple); X X X return(iErr); X X } /* Native_VectToNewGrouple */ X/****************************************************************************************/ X X X/**************************************************************************************** X Pattern Xlisp <--> Nancy Conversion X ****************************************************************************************/ X X X/****************************************************************************************/ XTVeosErr Native_GetPatternArg(hPattern, iMatchFlag) X THGrouple hPattern; X int iMatchFlag; X{ X LVAL pXElt; X TVeosErr iErr; X X X SUBST = FALSE; X VOID = FALSE; X MOD = (iMatchFlag == NANCY_ReplaceMatch); X X X /** get lisp pattern list **/ X X pXElt = xlgalist(); X X X /** dispatch lisp->veos conversion **/ X X iErr = Native_PatListToGrouple(pXElt, hPattern); X X#ifndef OPTIMAL X if (iErr == VEOS_SUCCESS) { X if (iMatchFlag == NANCY_ReplaceMatch) { X if (!SUBST && !VOID) X iErr = NATIVE_NOREPLACEMARK; X } X else { X if (VOID) X iErr = NATIVE_NOVOID; X else if (!SUBST) X iErr = NATIVE_NOFETCHMARK; X } X } X#endif X X return(iErr); X X } /* Native_GetPatternArg */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XTVeosErr Native_PatXEltToVElt(pXElt, pVElt) X LVAL pXElt; X TPElt pVElt; X{ X TVeosErr iErr; X X iErr = VEOS_SUCCESS; X X X /** NIL is the empty grouple **/ X X if (null(pXElt)) { X iErr = Nancy_NewGrouple(&pVElt->u.pGr); X pVElt->iType = GR_grouple; X } X X X /** case-wise conversion to nancy format **/ X X else { X switch (ntype(pXElt)) { X X case CONS: X /** a list becomes a grouple **/ X iErr = Native_PatListToGrouple(pXElt, &pVElt->u.pGr); X pVElt->iType = GR_grouple; X break; X X case VECTOR: X /** a vector becomes a special grouple **/ X iErr = Native_PatVectToGrouple(pXElt, &pVElt->u.pGr); X pVElt->iType = GR_vector; X break; X X case FIXNUM: X pVElt->iType = GR_int; X pVElt->u.iVal = getfixnum(pXElt); X break; X X case FLONUM: X pVElt->iType = GR_float; X pVElt->u.fVal = (float) getflonum(pXElt); X break; X X case STRING: X pVElt->iType = GR_string; X pVElt->u.pS = strdup((char *) getstring(pXElt)); X break; X X case SYMBOL: X iErr = Native_ConvertSymbol(pXElt, pVElt); X break; X X default: X iErr = NATIVE_BADVTYPE; X break; X } X } X X return(iErr); X X } /* Native_PatXEltToVElt */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XTVeosErr Native_PatListToGrouple(pList, hGrouple) X LVAL pList; X THGrouple hGrouple; X{ X TVeosErr iErr; X LVAL pXFinger; X int iElt; X TPGrouple pGrouple; X TPElt pVFinger; X TPatStatRec patPB; X TElt eltNew; X X X /****************** X ** setup locals ** X ******************/ X X *hGrouple = nil; X iErr = Nancy_NewGrouple(&pGrouple); X X /** by default, a grouple is literally an ordered list of elements. X ** in some cases, a pattern grouple can specifiy an order-blind element X ** collection. in other words, a content-dependent-pattern. X **/ X patPB.bOrdered = TRUE; X X /** prepare to check for pattern format inconsistencies **/ X X patPB.bExpContent = FALSE; X patPB.bExpOrder = FALSE; X patPB.bMarkedWithin = FALSE; X patPB.bTouchedWithin = FALSE; X X patPB.bMarkNextElt = FALSE; X patPB.bTouchNextElt = FALSE; X patPB.bMustEnd = FALSE; X patPB.bGetAnother = FALSE; X X X /*********************************** X ** convert each lisp sub-element ** X ***********************************/ X X pXFinger = pList; X while (!null(pXFinger)) { X X eltNew = NIL_ELT; X X /** do actual element conversion **/ X X iErr = Native_PatXEltToVElt(car(pXFinger), &eltNew); X if (iErr != VEOS_SUCCESS) X break; X X iErr = Native_PatVEltClerical(&eltNew, &patPB); X if (iErr != VEOS_SUCCESS) X break; X X if (patPB.bGetAnother) { X X /** this elt was actually a modifier elt for next one. X ** prepare for caller forgetting to pass next elt X **/ X iErr = NATIVE_NOTEND; X } X X else { X /** place converted nancy element into dest grouple **/ X X Nancy_NewElementsInGrouple(pGrouple, pGrouple->iElts, X 1, GR_unspecified, 0); X pGrouple->pEltList[pGrouple->iElts - 1] = eltNew; X } X X X /** advance element refs **/ X X pXFinger = cdr(pXFinger); X } /* while */ X X if (iErr != VEOS_SUCCESS) X Nancy_DisposeGrouple(pGrouple); X X else { X if (!patPB.bOrdered) X SETFLAG(NANCY_ContentMask, pGrouple->iFlags); X if (patPB.bMarkedWithin) X SETFLAG(NANCY_MarkWithinMask, pGrouple->iFlags); X if (patPB.bTouchedWithin) X SETFLAG(NANCY_TouchWithinMask, pGrouple->iFlags); X X *hGrouple = pGrouple; X } X X return(iErr); X X } /* Native_PatListToGrouple */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XTVeosErr Native_PatVectToGrouple(pVect, hGrouple) X LVAL pVect; X THGrouple hGrouple; X{ X TVeosErr iErr; X LVAL pXFinger; X int iXElts, iXEltIndex; X TPGrouple pGrouple; X TPatStatRec patPB; X TElt eltNew; X X /****************** X ** setup locals ** X ******************/ X X *hGrouple = nil; X iErr = Nancy_NewGrouple(&pGrouple); X X /** by default, a grouple is literally an ordered list of elements. X ** in some cases, a pattern grouple can specifiy an order-blind element X ** collection. in other words, a content-dependent-pattern. X **/ X patPB.bOrdered = TRUE; X X /** prepare to check for pattern format inconsistencies **/ X X patPB.bExpContent = FALSE; X patPB.bExpOrder = FALSE; X patPB.bMarkedWithin = FALSE; X patPB.bTouchedWithin = FALSE; X X patPB.bMarkNextElt = FALSE; X patPB.bTouchNextElt = FALSE; X patPB.bMustEnd = FALSE; X patPB.bGetAnother = FALSE; X X iXElts = getsz(pVect); X if (iXElts > 0 && iErr == VEOS_SUCCESS) { X X /*********************************** X ** convert each lisp sub-element ** X ***********************************/ X X iXEltIndex = 0; X while (iXEltIndex < iXElts) { X X X /** cache current vector element **/ X X pXFinger = getelement(pVect, iXEltIndex); X eltNew = NIL_ELT; X X /** do actual element conversion **/ X X iErr = Native_PatXEltToVElt(pXFinger, &eltNew); X if (iErr != VEOS_SUCCESS) X break; X X iErr = Native_PatVEltClerical(&eltNew, &patPB); X if (iErr != VEOS_SUCCESS) X break; X X if (patPB.bGetAnother) { X X /** this elt was actually a modifier elt for next one. X ** prepare for caller forgetting to pass next elt X **/ X iErr = NATIVE_NOTEND; X } X X else { X /** place converted nancy element into dest grouple **/ X X Nancy_NewElementsInGrouple(pGrouple, pGrouple->iElts, X 1, GR_unspecified, 0); X pGrouple->pEltList[pGrouple->iElts - 1] = eltNew; X } X X X /** advance element refs **/ X X iXEltIndex ++; X X } /* while */ X } X X if (iErr != VEOS_SUCCESS) X Nancy_DisposeGrouple(pGrouple); X X else { X if (!patPB.bOrdered) X SETFLAG(NANCY_ContentMask, pGrouple->iFlags); X if (patPB.bMarkedWithin) X SETFLAG(NANCY_MarkWithinMask, pGrouple->iFlags); X if (patPB.bTouchedWithin) X SETFLAG(NANCY_TouchWithinMask, pGrouple->iFlags); X X *hGrouple = pGrouple; X } X X return(iErr); X X } /* Native_PatVectToGrouple */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XTVeosErr Native_PatVEltClerical(pVElt, pStats) X TPElt pVElt; X TPPatStatRec pStats; X{ X TVeosErr iErr = VEOS_SUCCESS; X X#ifndef OPTIMAL X if (pStats->bMustEnd) X iErr = NATIVE_NOTEND; X X else { X /** catch possible undefined expressions **/ X X switch (pVElt->iType) { X X case GR_these: X if (pStats->bExpContent) X iErr = NATIVE_CANTMIX; X break; X X case GR_theseall: X if (pStats->bExpContent) X iErr = NATIVE_CANTMIX; X break; X X case GR_some: X iErr = NATIVE_NOSTARN; X break; X X case GR_any: X if (pStats->bExpOrder) X iErr = NATIVE_CANTMIX; X break; X X case GR_here: X if (SUBST || VOID) X iErr = NATIVE_TOOMANYMARKS; X else if (pStats->bGetAnother) X iErr = NATIVE_MODVOID; X break; X X case GR_mark: X if (SUBST || VOID) X iErr = NATIVE_TOOMANYMARKS; X else if (pStats->bGetAnother) X iErr = NATIVE_THISWHAT; X break; X X case GR_touch: X if (!MOD) X iErr = NATIVE_NOTOUCH; X else if (pStats->bGetAnother) X iErr = NATIVE_THISWHAT; X break; X X default: X break; X } /* switch */ X } X#endif X X if (iErr == VEOS_SUCCESS) { X X /** mark the element for nancy matcher **/ X X if (pStats->bMarkNextElt) { X SETFLAG(NANCY_EltMarkMask, pVElt->iFlags); X pStats->bMarkNextElt = FALSE; X pStats->bGetAnother = FALSE; X } X X if (pStats->bTouchNextElt) { X SETFLAG(NANCY_EltTouchMask, pVElt->iFlags); X pStats->bTouchNextElt = FALSE; X pStats->bGetAnother = FALSE; X } X X X switch (pVElt->iType) { X X case GR_these: X pStats->bExpOrder = TRUE; X break; X X case GR_any: X pStats->bOrdered = FALSE; X pStats->bExpContent = TRUE; X pStats->bMustEnd = TRUE; X break; X X case GR_theseall: X pStats->bExpOrder = TRUE; X pStats->bMustEnd = TRUE; X break; X X case GR_here: X VOID = TRUE; X SETFLAG(NANCY_EltMarkMask, pVElt->iFlags); X pStats->bMarkedWithin = TRUE; X break; X X case GR_mark: X SUBST = TRUE; X pStats->bMarkedWithin = TRUE; X pStats->bMarkNextElt = TRUE; X pStats->bGetAnother = TRUE; X break; X X case GR_touch: X pStats->bTouchedWithin = TRUE; X pStats->bTouchNextElt = TRUE; X pStats->bGetAnother = TRUE; X break; X X default: X break; X } /* switch */ X } X X return(iErr); X X } /* Native_PatVEltClerical */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XTVeosErr Native_ConvertSymbol(pXElt, pVElt) X LVAL pXElt; X TPElt pVElt; X{ X TVeosErr iErr = VEOS_SUCCESS; X char *sSrc; X boolean bParsed = FALSE; X X X sSrc = (char *) getstring(getpname(pXElt)); X X switch(sSrc[0]) { X X X case '^': /* '^' marks the void for insertion */ X if (sSrc[1] == '\0') { X pVElt->iType = GR_here; X bParsed = TRUE; X } X break; X X case '>': /* '>' is a mark for the next element */ X if (sSrc[1] == '\0') { X pVElt->iType = GR_mark; X bParsed = TRUE; X } X break; X X case '~': /* '~' touches the next element */ X if (sSrc[1] == '\0') { X pVElt->iType = GR_touch; X bParsed = TRUE; X } X break; X X case '@': /* '@' is wildcard for ordered elements **/ X X /** special form (@) means exactly one element **/ X if (sSrc[1] == '\0') { X pVElt->iType = GR_these; X pVElt->u.iVal = 1; X bParsed = TRUE; X } X X /** special form (@n) means exactly n elts **/ X else if (IsIntStr(&sSrc[1]) == VEOS_SUCCESS) { X if ((pVElt->u.iVal = atoi(&sSrc[1])) < 1) X iErr = NATIVE_CRAZYWILD; X else X pVElt->iType = GR_these; X bParsed = TRUE; X } X X /** special form (@@) means zero or more elts **/ X else if (sSrc[1] == '@' && sSrc[2] == '\0') { X pVElt->iType = GR_theseall; X bParsed = TRUE; X } X break; X X X case '*': /* '*' is wildcard for unordered elements */ X X /** special form (*) means exatly one element **/ X if (sSrc[1] == '\0') { X pVElt->iType = GR_some; X pVElt->u.iVal = 1; X bParsed = TRUE; X } X X /** special form (*n) means exactly n elts **/ X else if (IsIntStr(&sSrc[1]) == VEOS_SUCCESS) { X if ((pVElt->u.iVal = atoi(&sSrc[1])) < 1) X iErr = NATIVE_CRAZYWILD; X else X pVElt->iType = GR_some; X bParsed = TRUE; X } X X /** special form (**) means zero or more elts **/ X else if (sSrc[1] == '*' && sSrc[2] == '\0') { X pVElt->iType = GR_any; X bParsed = TRUE; X } X break; X X } /* switch */ X X X /** save symbol's name as veos prim type **/ X X if (!bParsed && iErr == VEOS_SUCCESS) { X pVElt->iType = GR_prim; X pVElt->u.pS = strdup(sSrc); X } X X X return(iErr); X X } /* Native_ConvertSymbol */ X/****************************************************************************************/ X X X X/**************************************************************************************** X Xlisp <--> Linearized Data Conversion X ****************************************************************************************/ X X X/****************************************************************************************/ XTVeosErr Native_XEltToMsgRec(pXData, pMsgRec) X LVAL pXData; X TPMsgRec pMsgRec; X{ X TVeosErr iErr; X X pMsgRec->iLen = 0; X pMsgRec->sMessage = TALK_BUFFER; X X X /** perform data conversion to flat network-friendly form **/ X X iErr = Native_XEltToMessage(pXData, pMsgRec->sMessage, &pMsgRec->iLen); X X if (iErr != VEOS_SUCCESS) X Native_TrapErr(iErr, pXData); X X X return(iErr); X X } /* Native_XEltToMsgRec */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XTVeosErr Native_XEltToMessage(pXElt, pBuffer, pLen) X LVAL pXElt; X char *pBuffer; X int *pLen; X{ X TVeosErr iErr; X int iLen; X TF2L fTrans; X X iErr = VEOS_SUCCESS; X X /** message element is: element type, then data (except for NIL) X ** assume pBuffer is aligned X **/ X X if (null(pXElt)) { X X /** nil element is empty grouple **/ X *(int *) pBuffer = htonl(GR_grouple); X pBuffer += 4; X X /** empty grouple has zero elements **/ X *(int *) pBuffer = htonl(0); X X iLen = 8; X } X else { X X switch (ntype(pXElt)) { X X case CONS: X *(int *) pBuffer = htonl(GR_grouple); X pBuffer += 4; X iLen = 4; X iErr = Native_ListToMessage(pXElt, pBuffer, &iLen); X break; X X case VECTOR: X *(int *) pBuffer = htonl(GR_vector); X pBuffer += 4; X iLen = 4; X iErr = Native_VectToMessage(pXElt, pBuffer, &iLen); X break; X X case FIXNUM: X *(int *) pBuffer = htonl(GR_int); X pBuffer += 4; X *(long *) pBuffer = htonl(getfixnum(pXElt)); X iLen = 8; X break; X X case FLONUM: X *(int *) pBuffer = htonl(GR_float); X pBuffer += 4; X fTrans.u.f = getflonum(pXElt); X *(long *) pBuffer = htonl(fTrans.u.l); X iLen = 8; X break; X X case STRING: X *(int *) pBuffer = htonl(GR_string); X pBuffer += 4; X strcpy(pBuffer, getstring(pXElt)); X iLen = 4 + MEMSIZE(strlen(getstring(pXElt)) + 1); X break; X X case SYMBOL: X *(int *) pBuffer = htonl(GR_prim); X pBuffer += 4; X strcpy(pBuffer, getstring(getpname(pXElt))); X iLen = 4 + MEMSIZE(strlen(getstring(getpname(pXElt))) + 1); X break; X X default: X iErr = NATIVE_BADVTYPE; X iLen = 0; X break; X X } /* switch */ X } X X *pLen += iLen; X X return(iErr); X X } /* Native_XEltToMessage */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XTVeosErr Native_ListToMessage(pList, pBuffer, pLen) X LVAL pList; X char *pBuffer; X int *pLen; X{ X TVeosErr iErr = VEOS_SUCCESS; X LVAL pXFinger; X int iLen, iElts = 0; X char *pListHead; X X X /** first code of protocol is number of elements, write later **/ X X pListHead = pBuffer; X pBuffer = pListHead + 4; X *pLen += 4; X X X /** convert each lisp sub-element **/ X X pXFinger = pList; X while (!null(pXFinger)) { X X /** invoke recursive translation **/ X X iLen = 0; X iErr = Native_XEltToMessage(car(pXFinger), pBuffer, &iLen); X X if (iErr != VEOS_SUCCESS) X break; X X else { X iElts ++; X X pBuffer += iLen; X *pLen += iLen; X } X X /** advance element ref **/ X X pXFinger = cdr(pXFinger); X X } /* while */ X X X /** write number of elements **/ X X *(int *) pListHead = htonl(iElts); X X return(iErr); X X } /* Native_ListToMessage */ X/****************************************************************************************/ X X X X X/****************************************************************************************/ XTVeosErr Native_VectToMessage(pVect, pBuffer, pLen) X LVAL pVect; X char *pBuffer; X int *pLen; X{ X TVeosErr iErr = VEOS_SUCCESS; X LVAL pXFinger; X int iLen, iEltIndex, iElts; X X iElts = getsz(pVect); X X /** first code of protocol is number of elements **/ X *(int *) pBuffer = htonl(iElts); X X pBuffer += 4; X *pLen += 4; X X X /** convert each lisp sub-element **/ X X iEltIndex = 0; X while(iEltIndex < iElts) { X X X /** invoke recursive translation **/ X X iLen = 0; X iErr = Native_XEltToMessage(getelement(pVect, iEltIndex), pBuffer, &iLen); X X if (iErr != VEOS_SUCCESS) X break; X X else { X pBuffer += iLen; X *pLen += iLen; X } X X X /** advance element ref **/ X X iEltIndex ++; X X } /* while */ X X X return(iErr); X X } /* Native_VectToMessage */ X/****************************************************************************************/ X X X X X/****************************************************************************************/ XTVeosErr Native_MessageToXElt(pBuffer, hXElt, pLen) X char *pBuffer; X LVAL *hXElt; X int *pLen; X{ X TVeosErr iErr = VEOS_SUCCESS; X int iLen, iType; X TF2L fTrans; X X *hXElt = NIL; X X iType = ntohl(*(int *) pBuffer); /** assume pBuffer is aligned **/ X X pBuffer += 4; X *pLen += 4; X X switch (iType) { X X case GR_grouple: X iLen = 0; X iErr = Native_MessageToList(pBuffer, hXElt, &iLen); X break; X X case GR_vector: X iLen = 0; X iErr = Native_MessageToVect(pBuffer, hXElt, &iLen); X break; X X case GR_int: X *hXElt = cvfixnum((int) ntohl(*(long *) pBuffer)); X iLen = 4; X break; X X case GR_float: X fTrans.u.l = ntohl(*(long *) pBuffer); X *hXElt = cvflonum(fTrans.u.f); X iLen = 4; X break; X X case GR_string: X *hXElt = cvstring(pBuffer); X iLen = MEMSIZE(strlen(pBuffer) + 1); X break; X X case GR_prim: X *hXElt = xlenter(pBuffer); X iLen = MEMSIZE(strlen(pBuffer) + 1); X break; X X case GR_unspecified: X default: X iLen = 0; X break; X X } /* switch */ X X *pLen += iLen; X X return(iErr); X X } /* Native_MessageToXElt */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XTVeosErr Native_MessageToList(pBuffer, hList, pLen) X char *pBuffer; X LVAL *hList; X int *pLen; X{ X TVeosErr iErr = VEOS_SUCCESS; X LVAL pXFinger; X int iLen, iElts, iEltIndex; X char *pListHead; X LVAL pList, pXElt; X X xlstkcheck(2); X xlsave(pList); X xlsave(pXElt); X X /** extract # of elements from first part of grouple data **/ X X iElts = ntohl(*(int *) pBuffer); X X pBuffer += 4; X *pLen += 4; X X X /** convert each element one at a time, 'talk msg format' -> list' **/ X X iEltIndex = 0; X while (iEltIndex < iElts) { X X iLen = 0; X X /** extract elt data, allocate specific elt mem, stuff it with data. **/ X X iErr = Native_MessageToXElt(pBuffer, &pXElt, &iLen); X X if (iErr != VEOS_SUCCESS) X break; X X else { X pBuffer += iLen; X *pLen += iLen; X X pList = cons(pXElt, pList); X } X X iEltIndex ++; X } X X if (iErr == VEOS_SUCCESS) { X X *hList = ReverseList(pList); X } X X xlpopn(2); X X return(iErr); X X } /* Native_MessageToList */ X/****************************************************************************************/ X X X X X/****************************************************************************************/ XTVeosErr Native_MessageToVect(pBuffer, hVect, pLen) X char *pBuffer; X LVAL *hVect; X int *pLen; X{ X TVeosErr iErr = VEOS_SUCCESS; X int iLen, iElts, iEltIndex; X LVAL pVect, pXElt; X X xlstkcheck(2); X xlsave(pVect); X xlsave(pXElt); X X /** extract # of elements from first part of grouple data **/ X X iElts = ntohl(*(int *) pBuffer); X X pBuffer += 4; X *pLen += 4; X X X /** create new lisp vector as container **/ X X pVect = newvector(iElts); X X X /** convert each element one at a time **/ X X iEltIndex = 0; X while (iEltIndex < iElts) { X X iLen = 0; X X /** extract elt data, allocate specific elt mem, stuff it with data. **/ X X iErr = Native_MessageToXElt(pBuffer, &pXElt, &iLen); X if (iErr != VEOS_SUCCESS) X break; X X else { X pBuffer += iLen; X *pLen += iLen; X X setelement(pVect, iEltIndex, pXElt); X } X X iEltIndex ++; X } X X X if (iErr == VEOS_SUCCESS) X *hVect = pVect; X X xlpopn(2); X X return(iErr); X X } /* Native_MessageToVect */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XTVeosErr Native_TrapErr(iErr, pXElt) X TVeosErr iErr; X LVAL pXElt; X{ X str63 sErr; X X switch(iErr) { X X case NATIVE_BADTYPE: X xlbadtype(pXElt); X break; X case NATIVE_NOKERNEL: X xlfail("veos kernel not initialized, use (vinit )"); X break; X case NATIVE_BADFREQ: X xlerror("'!' expected", pXElt); X break; X case NATIVE_2KERNELS: X xlfail("veos kernel already initialized"); X break; X case NATIVE_BADVTYPE: X xlerror("veos does not support that data type", pXElt == nil ? s_unbound : pXElt); X break; X case NATIVE_BADXTYPE: X xlerror("xlisp does not support that data type from veos", X pXElt == nil ? s_unbound : pXElt); X break; X case NATIVE_EMPTYELT: X xlerror("empty data element from veos, probably a memory error", X pXElt == nil ? s_unbound : pXElt); X break; X case NATIVE_NODATA: X xlerror("no veos data to match... only the void remains", s_unbound); X break; X case NATIVE_THISWHAT: X xlerror("pattern element modifier ('>' or '~') must be followed by a matchable element", pXElt == nil ? s_unbound : pXElt); X break; X case NATIVE_TOOMANYMARKS: X xlerror("patterns must contain exactly one '>' or '^'", X pXElt == nil ? s_unbound : pXElt); X break; X case NATIVE_CANTMIX: X xlerror("can't mix '@' and '*'", pXElt == nil ? s_unbound : pXElt); X break; X case NATIVE_NOTEND: X xlerror("indefinite wildcards (eg '@@' or '**') can only appear at end of grouple in pattern", X pXElt == nil ? s_unbound : pXElt); X break; X case NATIVE_NOREPLACEMARK: X xlerror("pattern must contain '>' or '^'", pXElt == nil ? s_unbound : pXElt); X break; X case NATIVE_NOFETCHMARK: X xlerror("pattern must contain '>'", pXElt == nil ? s_unbound : pXElt); X break; X case NATIVE_NOVOID: X xlerror("cannot get or copy from the void ('^')", X pXElt == nil ? s_unbound : pXElt); X break; X case NATIVE_BADPATSYMBOL: X xlerror("symbol not recognized", pXElt == nil ? s_unbound : pXElt); X break; X case NATIVE_CRAZYWILD: X xlerror("nonsensical number of wildcard elements", X pXElt == nil ? s_unbound : pXElt); X break; X case NATIVE_MATCHFAIL: X xlerror("match and/or replace did not succeed", X pXElt == nil ? s_unbound : pXElt); X break; X case NATIVE_NOSTARN: X xlerror("the '*n' feature is not supported", X pXElt == nil ? s_unbound : pXElt); X break; X case NATIVE_BADVOID: X xlerror("ambiguous void marker (can't use '^' in pattern grouple containing '*')", X pXElt == nil ? s_unbound : pXElt); X break; X case NATIVE_NOHOST: X xlerror("host not recognized", pXElt == nil ? s_unbound : pXElt); X break; X case NATIVE_NOTOUCH: X xlerror("can't touch (eg. '~') elements during nondestructive grouplespace access", pXElt == nil ? s_unbound : pXElt); X break; X case NATIVE_MODVOID: X xlerror("can't use element modifiers ('>' or '~') with the void ('^')", pXElt == nil ? s_unbound : pXElt); X break; X case VEOS_SUCCESS: X break; X default: X sprintf(sErr, "unexpected error %d", iErr); X xlerror(sErr, pXElt == nil ? s_unbound : pXElt); X break; X } X X return(VEOS_SUCCESS); X X } /* Native_TrapErr */ X/****************************************************************************************/ X X X X/****************************************************************************************/ Xboolean IsUidElt(pXElt) X LVAL pXElt; X{ X return(vectorp(pXElt) && X getsz(pXElt) == 2 && X stringp(getelement(pXElt, 0)) && X fixp(getelement(pXElt, 1))); X X } /* IsUidElt */ X/****************************************************************************************/ X X X/****************************************************************************************/ XTVeosErr XVect2Uid(pXElt, pUid) X LVAL pXElt; X TPUid pUid; X{ X TVeosErr iErr; X X /** assume sanity is checked **/ X X iErr = Sock_ResolveHost(getstring(getelement(pXElt, 0)), &pUid->lHost); X if (iErr == VEOS_SUCCESS) X pUid->iPort = getfixnum(getelement(pXElt, 1)); X else X iErr = NATIVE_NOHOST; X X return(iErr); X X } /* XVect2Uid */ X/****************************************************************************************/ X X X/****************************************************************************************/ XTVeosErr Uid2XVect(pUid, hXElt) X TPUid pUid; X LVAL *hXElt; X{ X str255 sTemp; X X /** assume sanity is checked **/ X X if (Sock_IP2StrHost(pUid->lHost, sTemp) == VEOS_SUCCESS || X Sock_IP2StrAddr(pUid->lHost, sTemp) == VEOS_SUCCESS) { X X /** assume caller locked *hXElt **/ X X *hXElt = newvector(2); X setelement(*hXElt, 0, cvstring(sTemp)); X setelement(*hXElt, 1, cvfixnum(pUid->iPort)); X } X X return(VEOS_SUCCESS); X X } /* Uid2XVect */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XTVeosErr Native_XVectsToUids(pList, hDests) X LVAL pList; X THUidNode hDests; X{ X TVeosErr iErr = VEOS_SUCCESS; X TPUidNode pDests, pNode; X LVAL pXFinger; X X /** convert lisp 'uid' vectors to nancy uids **/ X X pDests = nil; X pXFinger = pList; X while (!null(pXFinger)) { X X#ifndef OPTIMAL X if (!IsUidElt(car(pXFinger))) { X iErr = NATIVE_BADTYPE; X break; X } X#endif X iErr = Shell_NewBlock(sizeof(TUidNode), &pNode, "uid-node"); X X if (iErr != VEOS_SUCCESS) X break; X X else{ X /** add new node to list **/ X X pNode->pNext = pDests; X pDests = pNode; X X X /** convert addr to internal format **/ X X iErr = XVect2Uid(car(pXFinger), &pNode->addr); X } X X pXFinger = cdr(pXFinger); X X } /* while */ X X if (iErr == VEOS_SUCCESS) X *hDests = pDests; X else X Native_DisposeUids(pDests); X X return(iErr); X X } /* Native_XVectsToUids */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XTVeosErr Native_DisposeUids(pDests) X TPUidNode pDests; X{ X TPUidNode pSave; X X while (pDests) { X X pSave = pDests->pNext; X Shell_ReturnBlock(pDests, sizeof(TUidNode), "uid-node"); X pDests = pSave; X } X X return(VEOS_SUCCESS); X X } /* Native_DisposeUids */ X/****************************************************************************************/ X X X/****************************************************************************************/ XTVeosErr IsIntStr(sSrc) X char *sSrc; X{ X TVeosErr iErr; X X iErr = VEOS_FAILURE; X if (sSrc) { X X for (iErr = VEOS_SUCCESS; X sSrc[0] != '\0' && iErr == VEOS_SUCCESS; X sSrc ++) X X if (!isdigit(sSrc[0])) X iErr = VEOS_FAILURE; X } X X return(iErr); X X } /* IsIntStr */ X/****************************************************************************************/ X X END_OF_FILE if test 43094 -ne `wc -c <'src/kernel_current/shell/xv_glutils.c'`; then echo shar: \"'src/kernel_current/shell/xv_glutils.c'\" unpacked with wrong size! fi # end of 'src/kernel_current/shell/xv_glutils.c' fi echo shar: End of archive 14 \(of 16\). cp /dev/null ark14isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 16 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0