\begindata{text,538547204}
\textdsversion{12}
\template{default}
\define{global
}
\define{concat attr:[Script PreviousScriptMovement Point 6] attr:[FontSize PreviousFontSize Point 2]}
\define{footnote attr:[Flags OverBar Int Set] attr:[FontSize PreviousFontSize Point -2]}
\flushright{16 July 1993}
\majorheading{Ness Author's Reference Manual}
\center{by Wilfred J. Hansen}
\indent{\flushright{\smaller{_________________________________
Andrew Consortium
Carnegie Mellon University
__________________________________
}}
Ness is a programming language for the Andrew ToolKit. With it, documents may contain active elements controlled by Ness scripts. The language features an innovative substring algebra for string processing. \
This manual is intended for authors who want to write Ness programs or incorporate Ness scripts in documents or applications. For a description of all documents describing Ness, see the \bold{Ness User's Manual}.
Contents
1. Writing Ness
2. Writing stand-alone programs
3. Extending objects in embedded scripts}
\
\begindata{bp,538518464}
\enddata{bp,538518464}
\view{bpv,538518464,4,0,0}
Copyright IBM Corporation 1988, 1989 - All Rights Reserved
Copyright Carnegie Mellon University 1992, 1993 - All Rights
Reserved
\smaller{$Disclaimer:
Permission to use, copy, modify, and distribute this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice, this permission notice, and the following disclaimer appear in supporting documentation, and that the names of
IBM, Carnegie Mellon University, and other copyright holders, not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission.
IBM, CARNEGIE MELLON UNIVERSITY, AND THE OTHER COPYRIGHT HOLDERS
DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT
SHALL IBM, CARNEGIE MELLON UNIVERSITY, OR ANY OTHER COPYRIGHT HOLDER
BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
OF THIS SOFTWARE.
$
$Log: nessauth.doc,v $
Revision 1.9 1994/02/08 21:56:40 rr2b
typescript -> command
DOC
Revision 1.8 1993/07/17 04:31:45 wjh remove notes about future developments modernize layout, copyrights, etc.
}
\begindata{bp,538518528}
\enddata{bp,538518528}
\view{bpv,538518528,5,0,0}
Ness \italic{programs} reside in their own files and process other files.
Ness \italic{scripts} reside as insets within a document or application and extend and control the behavior of other insets. This manual describes how to write Ness programs or incorporate Ness scripts in documents or applications. For details of writing the language itself, see Ness
Language Reference Manual. For a full list of the Ness documentation, see the \bold{Ness User's Manual}.
Some of the early parts below describe Ness cultural conventions which are unenforcable. Warning, things you will need to know are embedded in the cultural stuff to give you incentive to wade through the culture.
\section{1. Writing Ness}
Several topics are of interest in writing Ness code, whether in standalone programs or scripts embedded in documents or applications.
\subsection{1.1 What a Ness script looks like}
Although the Ness compiler pays very little attention to program formatting and typography, you should keep in mind that the purpose of writing a program is to explain it to another human because humans have much lower tolerance for confusing programs than computers. In the Ness security scheme, users are encouraged to read Ness programs and to ignore any they do not understand. Not all users will avail themselves of this opportunity, but enough will that it well behooves you as author to take some care to produce a readable document.
Ness programs may contain typography, all of which is ignored except that within string constants. Typical uses of typography: highlight function names and the names of global variables use indentation styles instead of tabs
use headings and titles in comments put reserved words in italics (\italic{function, if, return,} ...)
A comment can be one long line with the comment mark (--) only at its beginning. \
Where useful, include diagrams, rasters, and tables in comments to explain the program.
Comments are important for every global entity, both variable and function.
The comments should indicate the purpose of the entity sufficiently well that a reader of can understand any given function having read only the comments describing the functions and global variables it uses. That is, without reading the contents of any other function. For a function the initial comment should describe the arguments, the return value, and any exceptional circumstances that affect the behavior. For instance if it is a string processing function what does it do differently at the ends of the string or in case it doesn't find what it is looking for.
Indentation should follow the examples or the indentation shown in the grammar in the \bold{Ness Language Reference Manual}. In particular, if a form beginning with a reserved word "\bold{xyz}" has an "\bold{end xyz}", the first line of the form should begin with the reserved word, the last line should begin with the matching "\bold{end xyz}" indented the same amount, and all lines between should be indented further by at least one tab stop. The reserved words \bold{else} and \bold{elif} are indented the same distance as their \bold{if}. (If indentation gets too deep, either restructure the algorithm or put the inner portion in a function.)
In general global variables should be longer words and capitalized. \
Put a space after a comma and around the assignment and append operators
(:= and \concat{~}\bold{:=} ). Very often there should be a space around plus (+) and minus(-). After a function name, the left parenthesis should follow without an intervening space.
In writing functions that process strings, it is best to write them so they process their argument, rather than assuming they will process an entire base string. In other words, searches should be limited by the end of the argument rather than by the end of the base.
\subsection{1.2 Ness version number}
The Ness system may evolve from time to time. This raises the possibility that a program may expect one language and the system may implement some other. As far as possible changes will be made in an upward compatible manner so old programs will continue to run with newer compilers. To prevent trying to run newer programs with older compilers, each program has associated with it a \italic{Ness version number}.
In a Ness object, the Ness version number is automatically recorded when the object is saved. In a Ness program created with an editor the version number is recorded with a line of the form
--$ness 1
(or what ever version number is appropriate). If the compiler is at a lower version number than the program, it will refuse to compile it.
\subsection{1.2 Errors}
The Ness processor indicates errors as precisely as possible: the exact piece of the program with the error is indicated. For standalone programs the location is indicated in terms of character position from the beginning of the file and also by printing the line containing the error. When editing the script you can get to character position \italic{N} by giving the command sequence ESC-<-control-U-\italic{N}-control-F; the ESC-< moves the cursor to the front of the file and the rest of the sequence moves the cursor forward \italic{N} positions. (The first position in the file is number zero.) For embedded Ness programs executing interactively, the error position is shown by moving the selection to the erroneous token or tokens and displaying the accompanying message in the message line. To get to the next error, choose the NextError option from the Ness menu card or type the sequence control-X-control-N.
Occasionally the item highlighted will be next to the error, rather than the error itself. For a syntax error, the highlight often indicates the token after the erroneous one because the error token would have been legal in some other program. A missing \bold{end} token will usually not be detected until the next \bold{end}; this is best detected by proper indentation. \
Errors during execution may sometimes fail to find the location of the error. In this case the error indication may be the empty string at the beginning of a function or the beginning of the entire script.
If an error occurs in a function compiled from the ness library (see section 6 of the \bold{Ness Function Reference Manual}), Ness does its best to show that error as well. For standalone execution, the error is indicated in the error list. For embedded execution another window, named
NessLibrary, is brought up and the error is highlighted there. The
NessLibrary window behaves a lot like most ez windows, but does have some differences; it is best when through with it to use ESC-D to discard it.
If the erroneous library function was not your own, you should contact its author and mention that the problem occurred.
The most imposing Ness error message is
\leftindent{! ! ! Disasterous Ness error in this function. Quit soon.
!!!!!!!!!!}
This is displayed whenever the interpreter detects a bus error or segmentation fault during execution. In general it is okay to continue with the same editor because, after all, the offending memory acces could not have done anything because there was no such address. Consider, however, that the offending address is pseudo-randow so on other executions of the same statement it might refer to and damage some part of the memory that was crucial. It is for this reason that the message is so strongly stated.
\subsection{1.3 Functions available}
There are five sources for functions to call from Ness programs.
\leftindent{1) Functions defined elsewhere in the same script
2) Ness builtin functions
3) Ness library functions
4) Proctable functions
5) Functions defined in C for object classes}
The first of these is described in the \bold{Ness Language Reference
Manual}, the last in the \bold{Ness Hacker's Manual}, and the rest in the
\bold{Ness Function Reference Manual}. Note that if you want to call functions for objects classes your Ness program text must earlier contain the comment:
--$enable class access spelled and spaced exactly as shown.
There are \italic{three} different places a Ness script may appear in the editor:
\leftindent{as an embedded script in a document or application as a Ness program in a file of its own in the NessLibrary window}
It is unlikely that one script would appear in all three places, but quite conceivable that it could be edited as a file and in a NessLibrary winodw simultaneously. Beware: these are two separate copies of the text; changes to one will not affect the other. \
\section{2. Writing stand-alone programs}
To write a program in Ness, create a file with the extension ".n" and write the script in it. Execute the script with nessrun, as shown in the
\bold{Ness User's Manual}.
Nessrun presents to the program the remainder of the command line after the program name, so the program can have any set of switches and arguments it wants. This text is passed to the program as the single argument to the function 'main', which is where execution begins. \
When executed with nessrun, a program may be non-interactive, or it can open a window and interact with the user.
\subsection{2.1 Example non-interactive program}
The next two pages give a sample program which reads a file, "processes" it line-by-line, and writes the revised file. In this case the processing is simply to make a copy of the contents of the line and create an identical line in the output file. As the program notes, the entire processing step could be written as \
return copy(text) but then it would not illustrate how to find the lines of the file.
Discussion continues after the program text.
\begindata{bp,538518592}
\enddata{bp,538518592}
\view{bpv,538518592,6,0,0}
\example{\smaller{-- process.n \
-- Read a file, process each line, and write the result to filename.doc
--
-- Usage: nessrun process.n filename
$ness 1
\italic{marker} destext := "doc" -- extension for destination file
\italic{marker} letters := "qwertyuiopasdfghjklzxcvbnm"
\leftindent{~ "QWERTYUIOPASDFGHJKLZXCVBNM"
~ "_"}
-- Process(text)
-- process the text and \
-- return the revised version
-- The text may be read-only, so we use ~:= to build new text.
-- In this example, the new text is just \
--
-- a concatenation of the lines of the old
\italic{function} \bold{Process}(text)\leftindent{
\italic{marker} new := newbase() -- the output text
\italic{marker} nl -- a newline in the original text
\italic{marker} line -- one line of the original text \
-- (without a newline at either end) nl := search(text, "\\n") -- find first newline line := extent(text, start(nl)) -- find first line
\italic{while} nl /= "" \italic{do}
-- "process" a line: new ~:= line ~ "\\n" \ line := finish(nl) -- start of next line nl := search(extent(line, text), "\\n") -- next newline line := extent(line, start(nl)) -- the entire next line
\italic{end} \italic{while}
-- At this point, 'line' refers to everything \
-- from the finish of the last newline to the finish of 'text'
\italic{if} line /= "" \italic{then}
-- there is more in 'text' after its last newline new ~:= line -- "process" the tail \ new ~:= "\\n"
\italic{end} \italic{if}
-- gratuitously add a final newline
\italic{return} new}
\italic{end} \italic{function}
\begindata{bp,538518656}
\enddata{bp,538518656}
\view{bpv,538518656,7,0,0}
\italic{function} \bold{main}(args)
\leftindent{\italic{marker} filename, outname, t filename := token(args, letters ~ "./0123456789") outname := search(filename, ".") t := search(finish(outname), ".")
\italic{while} t /= "" \italic{do} -- find the last "."
\leftindent{outname := t t := search(finish(outname), ".")}
\italic{end} \italic{while}
-- append "." ~ destext if there is no "." in the filename,
-- or there is a slash after the last ".",
-- or filename already ends in "."~destext
\italic{if} outname = "" \
\italic{or} search(finish(outname), "/") /= ""
\italic{or} extent(next(outname), filename) = destext
\italic{then}
\leftindent{outname := filename ~ "." ~ destext}
\italic{else} \
\leftindent{outname := extent(filename, outname) ~ destext}
\italic{end} \italic{if} printline("Process: " ~ filename ~ " -> " ~ outname) t := readfile(filename) -- t is read-only if the file is t := Process(t)
-- save: the old ouput: \ system("mv " ~ outname ~ " " \
~ outname ~ ".BAK 2> /dev/null") writefile(outname, t)}
\italic{end} \italic{function}}}
The main function first extracts the input filename from the arguments.
Note that as written it only recognizes names consisting of letters, digits, underline, dot, and slash. Next it uses a \bold{while} loop to find the last dot, checks the extension, and generates the name for the output file. After then printing a message it reads the old file, processes it, moves the old output file, and writes the new output file.
The function \bold{Process} advances through the text one line at a time, setting the variable 'line' to have the contents of each successive line,
without a newline at either end. The "processed" text is accumulated in
'new' by appending to its end. The loop is carefully written to process only the 'text' value passed in, even if it is a substring of some longer string.
It is instructive to see why the loop leaves 'line' referring to everything after the last newline. The essential cause is that when search() fails to find what it is looking for it returns finish() of its first argument.
In this case because the first argument ends at the end of the text, that location is returned for failure. And then 'line' is set to everything from finish() of the last newline to finish() of 'text'.
\subsection{2.2 Nessrun amenities}
Nessrun implements two switches which, if used, are inserted in the command line just after 'nessrun' and before the filename. \
\description{-d forces a dump of the code generated for the program.
(In most circumstances this is of little value to you as a Ness programmer.)
The code generated is that of a stack machine: operands are fetched to the stack with Load instructions, operators apply to the top elements of the stack, and results are put back in variables with store instructions.
For more information about the exact contents of the dump, you can try reading the source code of module atk/ness/objects/dump.c in the Ness source code.
\
-f causes the nessrun program to fork, thus freeing the command window for further command initiation. This switch is particularly of use when the application opens an interactive window.}
When writing a standalone program, you may wish to utilize the textview_ proctable functions. To allow this, nessrun provides a value for
'defaulttext'; the value is an empty text, so to use it you first copy the text with replace(base(currentselection(defaulttext)), the-text-to-be-processed).
The nessview inset provides some tools of use when editing Ness code.
Primarily this means you can compile the program without leaving the editor. To utilize the nessview inset to edit Ness programs, you can add the following to your ~/.atkinit file:
\leftindent{addfiletype .n ness "template=default"}
If you edit a new file with the extension .n, it will be editted with the nessview inset and saved with "\\begindata\{ness" so next time it will be read as Ness. Previously existing xyz.n files that have styles have already been written with "\\begindata\{text", so editing them will not use the nessview inset. Note also that the second time you edit a .n file with the ness inset, you will find the warning message wrapped around it. You can click on the Author Mode button near the end of the file. \
You can remove the warning from all your Nesses by adding to your preferences the line
*.NessUseDialogBoxInsteadOfWarning: on
Thereafter a dialog box will appear whenever you see a Ness script.
The \bold{Ness User's Manual} explains that a Ness script may begin with
\
#!/usr/andrew/bin/nessrun
If the file it is in is made executable with something like chmod +x filename.n then a user can execute the Ness program just by typing its name to the shell. What the User's Manual does not mention, however, is that the #! line must be the absolutely first thing in the file. If the file is originally created with styles or embedded objects, ez will expect the file to begin with "\\begindata" and will otherwise show it as plain ASCII.
It is easiest to simply create such programs without styles or embedded objects. However, if you are editting the Ness code with the ness inset, it will get read properly.
When errors are encountered for stand-alone compilation or execution, a message is printed like this:
\leftindent{\smaller{Compile error(s) in /tmp/test.n
at 2094 (len 8): the Ness library file for the given prefix, does not define this function
source text is: t := Process( >>> enum_foo <<< (t))
at 2221 (len 3): syntax error
source text is: >>> end <<< function}}
In each entry the first two numbers are the location of the error within the file. The first number is the position of the first character of the erroneous text and the second is its length. You can get to the indicated position as described above. After the first two numbers and colon comes the error message and then on the second line is the erroneous line from the source text with the error text indicated within >> and <<.
\subsection{2.3 Interactive Nessrun applications}
Although ATK applications can be written as documents with embedded Ness scripts, this has two disadvantages: the embedded Ness occupies screen space and the user must empower the embedded Ness each time the application is started. These problems can be avoided by writing the application as a standalone Ness program which opens a window and interacts with the user.
See the function launchApplication in nessfunc.d; note that this function does not return until the user exits from the application. In order to intercept events to an object named in the marker, the program may
"extend" those objects.
When an application is started from nessrun, it is appropriate that it should fork in order to release the command window. This is accomplished with the -f switch to nessrun.
A program design may require action when an object first beomes visible on the screen. To do so, the extend block for any named object can contain on event specification for event "BecameVisible"; the code within will be called whenever the object first is displayed on the screen.
\section{3. Extending objects in embedded scripts}
Ness scripts embedded as insets in documents can extend the behavior of insets appearing elsewhere in the document. You can insert a Ness inset just as any other inset: type ESC-TAB and respond to the prompt with
"ness". An embedded text will appear which differs in appearance from an ordinary text inset in that there is an additional "Ness" menu card.
The most direct way to take advantage of a Ness inset in a document is to insert within the inset a script which processes the document's text.
After Empowering the Ness, each time you select "Do main()" from the
Ness menu card, the function main() in the script will be called (with no arguments). For example, suppose you insert the following script in a
Ness inset within this document and then choose Do main() from the menu. The function counts the number of instances of "Ness" and shows the number in the message line. (As of 10:04:12 EDT 10 Oct 1989, the value displayed is
104.)
\smaller{
\example{\italic{function} \bold{main}()
-- count the occurrences of the string "Ness"
\italic{integer} count
\italic{marker} word count := 0 word := start(base(currentselection(defaulttext)))
\italic{while} \italic{True} \italic{do} word := search(finish(word), "Ness")
\italic{if} word = "" \italic{then}
TellUser(textimage(count))
\italic{exit} \italic{function}
\italic{end} \italic{if} count := count + 1
\italic{end} \italic{while}
\italic{end} \italic{function}}
}
The function currentselection() returns a marker for the text currently selected in the default text. Base() then computes a marker for the entire text containing that selection. Finally, start() computes an empty marker at the beginning of its argument. In this way, the search for "Ness" begins at the front of the document, no matter what portion of the document is currently selected. Each execution of search() within the loop finds a subsequent instance of "Ness" because it begins the search with the next() character after the current instance.
Warning: When I first wrote the above routine I omited the call to
finish(). As a result the function went into a loop because it continuously found the same instance of "Ness". As explained in the
NessUser's Manual, you can use control-G to exit an embedded Ness script that is caught in a loop .
When a run-time error occurs or even when control-G is pressed, the Ness script is disabled until recompiled. And the script will only recompile after you have changed its text. You may have to go into Author mode, add and remove a single character, and then request the recompilation.
\subsection{3.1 Embedding and naming}
When designing a document or application the first step is to design the appearance and behavior. Decide what buttons, fields, and other insets you desire and what will happen for user actions to each. For instance, you may want a click on a picture of a flower to scroll the document to a section on horticulture. The next two steps are to layout the images and build the Ness script.
By convention, when you enhance a document with a Ness script you should include in the design of the document a section which describes to the reader the ways in which the document is enhanced. That way the reader can decide whether or not to empower the script. \
There are some constraints on the placement of the description of the
Ness enhancements and the Ness script itself. The description should appear close to the Ness so the reader can find it easily while deciding whether to Empower the script. The script itself should appear close to the beginning of the document or close to the first inset controlled by the
Ness. Otherwise the user may not see the script and may thus not have a chance to empower it and enjoy its benefits.
When placing insets in the document or application they need to be given names so the Ness script can refer to them. The full description of creating and naming insets is covered by the documents in
/usr/andrew/doc/adew/; what follows is just one possible approach.
A name may be given to an inset by embedding it in a \italic{cel} inset, which is in turn embedded in the parent. The cel inset remembers a name given to it and registers that name with its parent. The name is passed up the parentage until it reaches an arbiter, which then remembers the name in conjunction with its cel. Ness asks the arbiter surrounding it for cels by names.
The user interface to all this is covered in the documents in
/usr/andre/doc/adew/. Here's one approach: use the \italic{arbcon} to create insets, paste them in your work, and finally use the arbcon again to give names to the insets.
If you have in your .atkinit the line "addkey ness-dostmt \\e\\e view" you can bring up an arbcon window by typing ESC-ESC and respond to the
"Ness:" prompt with "arbcon_create()". Create an inset with the arbcon by clicking one of the names in the list at the top middle. The act of clicking puts a new instance of that sort of object into the cut buffer; from thence you can paste it into your document or application. Whenever you click on an inset its name and attributes will be displayed in the lower portion of the arbcon window. Initially the name will be some non-descript identification like "value", "value-1", "value-2", ... .
Ness scripts refer to inset names in two ways. The inset() function takes as its argument a marker value and tries to find an inset with that name, returning an object value for the inset. The extend construct names an inset which will be the target for all the event specifiers within the extend. If we give the flower the name "rosebud", the script might say
\example{\smaller{\italic{extend} "\bold{rosebud}"
\leftindent{\italic{on} \italic{mouse} "any"
\leftindent{\italic{if} mouseaction = mouseleftup \italic{then}
\leftindent{\italic{marker} b := base(currentselection(defaulttext)) b := search(b, "\\n3.1 Horticulture")
\italic{if} b /= "" \italic{then}\leftindent{ setcurrentselection(defaulttext, b) textview_line_to_top(defaulttext)}
\italic{end} \italic{if}}
\italic{end} \italic{if}}
\italic{end} \italic{mouse}}
\italic{end} \italic{extend}}}
In this case when the mouse goes up in the flower the text will be searched for the header of the Horticulture section and that line will be moved tothe top of the window.
Within ATK, the names of various insets are managed by an arbiter object.
When a Ness is Empowered, it tells the arbiter it wants to know about named insets. As insets become visible the Ness is informed of them and extends them as described in its script.
An arbiter is an inset that can contain any other sort of inset. Thus you can insert an arbiter containin, say, a table. Thereafter named insets within the table only send their names to the locally enclosing arbiter and not to the outermost one. To extend these inner insets, a Ness must be inserted as one of the insets within the table. In this way, there may be multiple copies of the table in a document each with its own script and each with subordinate insets having the same names.xxx Discuss hierarchical name spaces by embedding arbiters.
\bold{3.2 User Interface to Ness}
The menu options for Ness are documented in the \bold{Ness User's
Manual}.
It is useful to point out that if you as author want to see what a script will look like to a user you can select the "Add Warning" option. To resume editting you will then have to scroll to the end of the script and click on the box labelled "Author mode - Let me edit the script".
The following keystrokes are also defined by a Ness inset:
\description{\bold{ctl-X ctl-N} - Display the next error or the next warning message. After the last the message line shows "No more errors".
Typing the keys again will restart with the first error.
\bold{ctl-U ctl-X ctl-N} - Display the previous error or warning message.
\bold{ESC ctl-N shift-C } - Compile the script.
\bold{ctl-X ctl-E} - Compile the script and execute beginning with function main() or the currently selected startup function (see the next entry).
\bold{ctl-U ctl-X ctl-E} - Prompts for a function name and sets that name to be the currently selected startup function. Then goes ahead and does everything like ctl-X ctl-E (just above).
\bold{ESC ctl-D shift-D} - Turn on Ness debugging. This is useful only
for debugging the Ness processor and inset. It is of no aid for debugging programs written in Ness.
\bold{Esc ~} - Switch between author and user modes. \{This is broken right now\}
}
\section{Appendix. Known bugs}
If the keys in the argument to a dokeys call a keysequence which is intercepted by \bold{on keys}, Ness crashes. parseint(), parsereal(), and firstobject() do not obey the search conventions for limiting the search.
Ness scripts modified in the NessLibrary window do not affect copies of the script in other windows.
\enddata{text,538547204}