newLISPtm

For LINUX, FreeBSD, Mac OSX, Solaris and Win32

Users Manual and Reference v.8.6.0






Copyright © 1991-2005 Lutz Mueller.  www.nuevatec.com. All rights reserved.

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License,
Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts,
and no Back-Cover Texts. A copy of the license is included in the section entitled GNU Free Documentation License.

The accompanying software is protected by the GNU General Public License V.2, June 1991.

newLISP is a trademark of Lutz Mueller.



Contents

Users Manual

  1. Introduction
  2. Deprecated functions and future changes
  3. Command line options, startup and directories
  4. Shared library module for Linux/BSD
  5. DLL module for Win32 versions
  6. Evaluating newLISP expressions
  7. Lambda expressions in newLISP
  8. nil, true, cons and () in newLISP
  9. Arrays
  10. Hash tables
  11. Indexing elements of strings, lists and arrays
  12. Destructive versus non-destructive functions
  13. Dynamic and lexical scoping
  14. Early return from functions, loops, blocks
  15. Contexts
  16. Programming with context objects
  17. XML, SXML and XML-RPC
  18. Customization, localization and UTF-8
  19. Commas in parameter lists
  20. purelisp.lsp, the consistency of newLISP
  21. Linking newLISP source and executable

Function Reference

  1. Syntax of symbol variables and numbers
  2. Data types and names in the reference
  3. Functions in groups

Functions in alphabetical order

!  +-*/%  Ab  Ap  B  Ca  Co  Da  Di  Em  Ev  Fa  Fn  G  I  J  La  Li 
Ma  Me  Na   Ne  No  O  Pa  Pr  Q  Ra  Reg  Sa  Sh  St  T  U  W  X 

Appendix




newLISP Users Manual

1. Introduction

newLISP focuses on the core components of LISP: Lists, Symbols and Lambda expressions. To these newLISP adds arrays, dynamic scoping and lexical scoping with separated name-spaces called contexts and implicit indexing on lists.

The result is an easier to learn LISP, even smaller than most 'Scheme' implementations, but with about 270 built-in functions, only about 150k in size and built using only the most common UNIX system C-libraries for high portability. newLISP loads quickly and has a small memory footprint. It competes in execution speed with any other popular scripting language and uses very little computing resources.

newLISP is dynamically scoped inside lexically separated contexts (name-spaces). Contexts can be used to create isolated, protected expansion packages for newLISP and for prototype based object oriented programming.

Variables, built-in functions and user-defined functions share the same name-space and can be manipulated by the same functions. Symbols can be protected from accidental change. Lambda expressions and user-defined functions in newLISP can be manipulated like any other list expression. Like Scheme newLISP evaluates the operator element of a list expression.

Contexts in newLISP facilitate the development of bigger applications in newLISP composed from different independent developed modules with their own separated name-space. Contexts can also be copied, dynamically assigned to variables and passed as function parameters by reference. In this way contexts can serve as dynamically created objects packaging symbols and methods and with lexical separation of their name-spaces also enabling the definition of statically scoped functions.

newLISP's efficient red-black-tree symbol implementation can handle millions of symbols without degrading performance. Contexts can hold symbol-value pairs simulating hash-tables. Functions are available for iterative access of symbols in contexts.

newLISP allocates and reclaims memory automatically but without the traditional asynchronous type of garbage collection (except under error conditions). Excepting symbols, built-in primitives end contexts each object is referenced only once in and passed by value. Memory is automatically deallocated when dereferencing objects. This results in predictable processing times without the pauses observed with traditional garbage collection. newLISP's unique automatic memory management makes it the fastest interactive LISP available.

Many of newLISP's built-in functions are polymorph in type, accepting a variety of data types and thereby greatly reducing the total number of different functions and syntactic forms necessary to be learned and implemented.

Some of newLISP's functions can access multidimensional lists and arrays to modify, insert or delete any element in a complex nested LISP list or array structure.

Strings can be treated as binary data and can contain null characters.

newLISP can be extended with a shared library interface and helper functions to access data in foreign binary data structures. The distribution contains a module for importing the MySQL and ODBC database API.

newLISP's HTTP, TCP/IP and UDP socket interfaces make it easy to write networked applications. Simple examples of network clients and servers are included. newLISP's text processing features include Perl compatible regular expression pattern matching (PCRE) and text parsing functions. These and the built-in XML interface make newLISP a useful tool for CGI processing on web servers. An example for HTML forms processing and a simple web server written in newLISP are also included in the source distribution.

The newLISP source distribution can be compiled for LINUX, BSDs, Mac OSX/Darwin, Solaris and WIN-32.


newLISP-tk

newLISP-tk is a graphical user interface (GUI) front-end written in Tcl/Tk to control newLISP. With newLISP-tk, graphics applications can be built based on the host operating system's graphical user interface. Third party interfaces to GTK GUI libraries and the openGL graphics library are also available.

newLISP can be compiled on most operating systems including Win32. Because Tcl/Tk is available for most OS's, newLISP-tk is a platform-independent solution for writing graphics applications in LISP.

For more information on newLISP-tk see the HTML documentation in newlisp-tk.html.


Licensing

newLISP and newLISP-tk are licensed under version 2 of the GPL (General Public License). This manual and the manual for newLISP-tk are licensed under the GNU Free Documentation License. If this license is not suitable for your application, please contact http://nuevatec.com for different arrangements.




2. Deprecated functions and future changes

newLISP tries to stay current in the functionality offered and small in executable size and memory footprint. From time to time functions get renamed or eliminated. Future changes whuch may break existing code will be announced in advance.

Deprecated functions

match for strings Match a pattern string and a string. This function is now only available for lists, the string version has been eliminated. Use find or regex instead.
get-integer Use the shorter writing get-int. The longer writing will be disabled in a future version.
integer Use the sorter writing int. The longer writing will be disabled in a future version.
symbol Use the shorter writing sym. The longer writing will be disabled in a future version.

Future changes

open, save, write-file Currently these functions when creating files give executable file permission for owner, group and other by default, resulting in a rwxr-xr-x or 0755 UNIX file permissions pattern assuming a 022 user mask. The next release will omit excutable file permissions on files created resulting in rw-r--r-- or 0644 file permissions pattern assuming a 022 user mask.



3. Command line options and directories

When starting newLISP from the command line it will first look for init.lsp and load it if present. Then one or more options and one or more newLISP source files can be specified. The options and source files are executed in the sequence they appear. For some options it makes sense to have source files loaded first like for the -p and -d options. For other options like -s and -m it is logical to specify these before the source files to be loaded. If an -e switch is used the program text is evaluated and then newLISP exits; otherwise evaluation continues interactively (unless an exit occurs during lisp-file load).


Stack size

newlisp -s 4000
newlisp -s 100000 aprog bprog
newlisp -s 6000 myprog

The examples show starting newLISP with different stack sizes using the -s option and loading one or more newLISP source files. When no stack size is specified the stack defaults to 1024.


Maximum memory usage

newlisp -m 128

The example limits memory to 128 megabytes for LISP cell memory. Each LISP cell in newLISP consumes 16 bytes. The 128Mb quantity specified is shown as 8,388,l608 LISP cells, the maximum number in the information returned by sys-info. Although LISP cell memory is not the only memory consumed by newLISP, it is a good estimate of overall memory usage.


Suppressing the prompt

The command line prompt can be suppressed:

newlisp -c 

This option will also suppress the initial copyright banner. Listen and connection messages in -p and -d modes are suppressed if logging is not enabled. This option is useful when controlling newLISP from other programs.

To also suppress return values from evaluations use silent.


newLISP as a TCP/IP server

newlisp some.lsp -p 9090

The example shows how newLISP can listen for commands on a TCP/IP socket connection. In this case standard I/O is redirected to the port specified in the -p option. some.lsp is an optional file to be loaded during startup and before listening for a connection.

This option is used to control newLISP from another application, for example, a GUI front-end to newLISP or any other program written in another programming language.

A telnet application can be used to test newLISP as a server. At first newLISP is started as a server:

newlisp -p 1234 &

The & indicates to LINUX or other UNIX to run the process in the background. Now connect with a telnet application:

telnet localhost 1234

If connected, the newLISP sign-on banner and prompt appear.

When the client application closes the connection newLISP will exit too. To avoid this use the -d mode instead. In this mode newLISP will stay loaded and wait for a new connection.

To log the connection, use the -l or -L option together with the -p option. This registers time and IP number of the connecting client in file newlisp-log.txt. When using -L all remote commands received are also logged. If the log-file newlisp-log.txt already exists, new content is appended; otherwise newlisp-log.txt is created. The logging option should appear before the -p option.

newlisp -L -p 1234 &

When controlling newLISP from other applications in -p mode communications can be simplified using the silent function to suppress return values from expressions, which would normally printed to the console.

When running in -p mode the tags [cmd] and [/cmd] can be used to enclose multi-line statements. The opening and closing tag have to appear each on separate lines. This way it is possible to transfer bigger portions of code from controlling applications. This technique is used in newLISP-tk, a Tcl/Tk front-end to newLISP.


TCP/IP demon mode

When the connection to the client is closed in -p mode newLISP exits. To avoid this use the -d option instead of the -p option:
newlisp -d 1234 &

This works like the -p option, but newLISP does not exit after a closed connection and stays in memory listening for a new connection. exit issued from the client application closes the network connection, but the newLISP demon remains resident and waits for a new connection.

To log the connection use the -l or -L option together with the -d option. This registers time and IP number of the connecting client in file newlisp-log.txt. When using -L all remote commands received are also logged. If the log-file newlisp-log.txt already exists, new content is appended; otherwise newlisp-log.txt is created. The logging option should appear before the -d option.

newlisp -l -d 1234 &

Note that the demon mode only works correctly on LINUX and BSD systems. On Win32 based systems newLISP may not be able to reconnect at all times.

The tags [cmd] and [/cmd] can be used to enclose multi-line statements. The opening and closing tags have to appear each on separate lines.


Server demon mode with handler function

This mode works similar to the -d mode but instead of executing incoming information as a newLISP command line, the request line gets passed to a handler function x-event with the request line as the parameter. The function x-event must be defined by the user and loaded on startup:

newlisp -x 8080 my-httpd

In the example the file my-httpd containing the definition of x-event is loaded and newLISP will listen for requests on port 8080. The file my-httpd could contain the following definition:

  ;; my-httpd - simple web server for static text/html pages
  ;;
  (define (x-event request)
      (find "GET /(.*) HTTP" request 0)
      (while (!= "" (read-line)))       ;skip header
      (set 'page (or (read-file $1) "Error 404: Page not found"))
      (print
            "HTTP/1.0 200 OK\r\n"
            "content-length: " (length page) "\r\n"
            "Content-type: text/html\r\n\r\n"
            page))

In a web browser type http://localhost:8080/mypage.html, where mypage.html is a HTML page in the current directory.

Using the -x server mode handlers for any protocol can be defined in x-event using only print, println and read-line or write-line to communicate through the TCP/IP port with the connected client. After returning from x-event newLISP will wait for further incoming requests. After a client/server exchange the client should close the connection. The -x server mode will automatically listen for a new connection on the specified port.

For HTTP requests containing Content-length: parameters, or whenever line oriented reading of input does not apply, net-receive can be used with the current connection socket obtained from net-sessions. The following is a code snipped from the file xmlrpc-server from the examples shipped with the source distribution:

    ; get header info
    (while (!= "" (read-line))
        (if (find "Content-length:(.*)" (current-line) 0)
            (set 'contentLength (int $1))))

    ; read XML
    (net-receive (first (net-sessions)) 'XML contentLength)

The (net-sessions) statement retrieves an internal list, whose first member is always the last connection or listen-socket opened.


Direct execution mode

Small pieces of newLISP code can be executed directly from the command line:
newlisp -e "(+ 3 4)"  => 7

The expression enclosed in quotation marks is evaluated and the result printed to standard out device (STDOUT). In most UNIX system shells apostrophes can also be used to delimit the command line. Note that there is a space between -e and the quoted command string.


Command line help summary

The -h command line switch prints a copyright notice and summary of all options:
newlisp -h

On Linux and other UNIX system a newlisp man page can be found:

man newlisp

This will display a man page in the Linux/UNIX shell.


The initialization file init.lsp

On LINUX, BSD, OSX and CYGWIN the initialization file is installed and looked for in /usr/share/newlisp/init.lsp. newLISP compiled with MinGW or Borland BCC looks for init.lsp in the same directory where newlisp.exe is installed. The file init.lsp and any file specified on the command line are loaded before the banner and prompt are shown. When newLISP is executed or launched by another program or process rather than from a shell, the banner and prompt are not shown, and newLISP communicates by standard I/O; but init.lsp is still loaded and evaluated if present.

init.lsp is not necessary for running newLISP, but it is convenient for defining functions and variables used system wide. init.lsp is not included in the newLISP-tk exe distribution but can be found in the source distribution.

The last part of init.lsp contains OS specific code to load a second .init.lsp file (starting with a dot). On Linux/UNIX this file is looked for in the directory specified in the HOME environment variable. ON Win32 this files is looked for in the directory specified by the USERPROFILE or DOCUMENT_ROOT environment variable.


Directories on LINUX, BSD, OSX

The directory /usr/share/newlisp/ also contains other modules with useful functions for a variety of tasks, like data base management with MySQL, procedures for statistics, POP3 mail, etc. Another directory /usr/doc/newlisp/ contains the HTML manual file newlisp_manual.html and related files.


Directories Win32/newLISP-tk distribution

On Win32 systems all files are installed in one directory, by default C:\newlisp\. If an init.lsp file is required, it should be in the same directory where newlisp.exe resides.




4. Shared library module for Linux/BSD versions

On Linux and BSD platforms newLISP can be compiled as a UNIX shared library object newlisp.so. newLISP can then be used like any other shared library in an UNIX environment

To use newlisp.so import the function newlispEvalStr. This function behaves like eval-string taking a string containing a newLISP expression and returning the result in a string address, which can be converted using get-string.

The first example shows how newlisp.so is imported from newLISP itself.

(import "/usr/lib/newlisp.so" "newlispEvalStr")
(get-string (newlispEvalStr "(+ 3 4)"))    => "7"

The second example shows how to import newlisp.so in a 'C' program:

/* libdemo.c - demo for importing newlisp.so
 * 
 * compile using: 
 * 	gcc -ldl libdemo.c -o libdemo
 *
 * use:
 *
 * 	./libdemo '(+ 3 4)'
 * 	./libdemo '(symbols)'
 * 	
 */

#include 
#include 

int main(int argc, char * argv[])
{
void * hLibrary;
char * result;
char * (*func)(char *);
char * error;

if((hLibrary = dlopen("/usr/lib/newlisp.so", 
                       RTLD_GLOBAL | RTLD_LAZY)) == 0)
	{
	printf("cannot import library\n");
	exit(-1);
	}

func = dlsym(hLibrary, "newlispEvalStr");
if((error = dlerror()) != NULL)
	{
	printf("error: %s\n", error);
	exit(-1);
	}

printf("%s\n", (*func)(argv[1]));

return(0);
}

/* eof */

The program will accept quoted newLISP expressions and print the evaluation result.

When using newlisp.so, output which is normally directed to the console, like output from print statements or return values, will be returned in a string pointed to by the call to newlispEvalStr. To silence the output from return values use the silent directive.




5. DLL module for Win32 versions

On Win32 platforms newLISP can be compiled as a DLL (Dynamic Link Library). In this way newLISP functions can be made available to other programs using this platform, e.g., MS Excel, Visual Basic, Borland Delphi, or even newLISP itself.

The function exposed via the DLL interface is newlispEvalStr or the older deprecated dllEvalStr , which takes a string containing valid newLISP expressions and returns a string with the results:

When the DLL is loaded it looks for an init.lsp file in the current directory of the calling process.

(import "newlisp.dll" "newlispEvalStr")
(get-string (newlispEvalStr "(+ 3 4)"))     => "7"

This example shows how to load the DLL when using newLISP. The get-string function is necessary within newLISP to access the string being returned. Other applications running on Win32 platforms allow the returned data type to be declared when importing the function.

When using newlisp.dll, output which is normally directed to the console, like output from print statements or return values, will be returned in a string pointed to by the call to newlispEvalStr. To silence the output from return values use the silent directive.




6. Evaluating newLISP expressions

The following pages are a short introduction on how LISP statements are evaluated in newLISP and the role of integer and floating point arithmetic in newLISP.


Integer and floating point data types and operators

All functions and operators in newLISP take both types of numbers, integers or floating points, and convert them to the format needed. For example passing a floating point number to a bit manipulating operator will convert a floating point number to an integer by omitting the fractional part of the number. In the same fashion a trigonometric function working on an integer number will convert the number internally to floating point format.

All operators which are not written with letters return integers: +, -, *, / ,%,$,~,|,^,<<,>> . All other operators and functions written with letters return floating point numbers. Integer operators when given floating point parameters will truncate them to the integer part and discard the fractional part.

newLISP has two types of basic arithmetic operators: +, -, *, / . All perform integer arithmetic converting parameters passed to them to integers, while the functions add, sub, mul and div convert arguments passed to them to floating point numbers. To make newLISP more behave like other scripting languages the integer operators +, -, *, / can be redefined to perform like add, sub, mul and div floating point operators:

(constant '+ add)
(constant '- sub)
(constant '* mul)
(constant '/ div)

Now all numbers, integers and floating pointing point numbers alike can be treated with the same common arithmetic operators +, -, * and / and will always return floating point results.

Note that all looping variables in the functions dotimes and for contain floating point numbers.

Care must be taken when using functions imported from libraries, which take integer arguments. After redefining +, -, *, / the results of arithmetic operations could be passed to imported library functions in double floating point when an integer format is required. In this case floating point numbers can be converted to integers using int. Likewise integer numbers returned can be transformed to double floats using float:

(import "mylib.dll" "foo")  ; importing 'C' int foo(int x)

(foo (int x))               ; passed argument as integer

(import "mylib.dll" "bar")  ; importing 'C' int bar(double y)

(bar (float y))             ; force double float

Note that most newLISP users leave =, -, *, / defined as integer operators and use add, sub, mul and div explicitly when required.


Evaluation rules and data types

Evaluate expressions by entering and editing them on the command line in the console window or by loading them from a file using the load function. Enter and edit bigger portions of LISP using an editor. Both Emacs and VI have modes to show matching parenthesis while editing or entering code.

The characters ; (semicolon) and # (pound) are used to start a comment. Text after these characters to the end of the line is not evaluated by newLISP. # is useful when using newLISP as a scripting language in LINUX/UNIX environments where # is commonly used as a comment indicator in shell and other scripts.

When evaluating from the command line, the evaluation result is printed in the console window.

To try out the following examples, just type in the part on the left side of the => sign in the console window and hit the [enter] key. After hitting [enter] the part to the right side of the => sign appears on the next line in the console window as the result.

nil and true are Boolean data types and evaluate to themselves:

nil                     => nil
true                    => true

Integers and floating point numbers evaluate to themselves:

Integers are 32 bit plus including sign bit. Valid integers are numbers between -2,147,483,648 and +2,147,483,647. Bigger numbers are truncated to one of the two limits. Floating-point numbers are IEEE 754 64-bit double floats.

123                 => 123
0xE8                => 232    ; hexadecimal prefixed by 0x
055                 => 45     ; octal prefixed by 0 (zero)
1.23                => 1.23
123e-3              => 0.123  ; scientific notation

Strings evaluate to themselves, may contain null characters and may have different delimiters:

"hello"                 => "hello"
"\032\032\065\032"      => "  A "                  
"\t\r\n"                => "\t\r\n"                

; strings can contain null characters

"\000\001\002"          => "\000\001\002" 

{this "is" a string}    => "this \"is\" a string"

;; [text], [/text] tags for text longer 2048 bytes

[text]this too[/text]   => "this too"  

Strings delimited by quotes " will also process the following characters escaped with a backslash \ :

\"for a quote inside a quoted string
\nfor a line-feed character ASCII 10
\rfor a return character ASCII 13
\tfor a TAB character ASCII 9
\nnnfor a three digit ASCII number in nnn between 000 and 255

Quoted string must not be longer than 2048 characters, for strings longer than 2048 use the [text] and [/text] tag delimiters. When newLISP outputs delimited strings it will automatically use tags for strings longer than 2048 characters.

The {, } and [text], [/text] delimiters don't do any escape character processing.

Lambda expressions evaluate to themselves:

(lambda (x) (* x x))    => (lambda (x) (* x x))
(fn (x) (* x x))    => (lambda (x) (* x x))

;; the second form is an alternative syntax

Symbols evaluate to their contents:

(set 'something 123)    => 123
something               => 123

Contexts evaluate to themselves:

(context 'CTX)          => CTX
CTX                     => CTX

Built in functions evaluate to themselves:

add                     => add <B845770D>
(eval (eval add))       => add <B845770D>
(constant '+ add)       => add <B845770D>
+                       => add <B845770D>

The part enclosed in < > is the hexadecimal memory address of the built-in function. It appears when trying to print a built-in primitive.

Quoted expressions lose one quote ' :

'something              => something
''''any                 => '''any
'(a b c d)              => (a b c d)

A quote is often used to protect an expression from evaluation, e.g., when referring to a symbol itself instead of its contents or when referring to a list as data and protecting it from being evaluated.

Lists in newLISP are evaluated by evaluating their first element first (as in the Scheme dialect of LISP). The result must be a primitive (built-in function), a lambda expression, or a lambda-macro expression which then is applied to the elements following in the list.

(+ 1 2 3 4)                => 10
(define (double x)(+ x x)) => (lambda (x)(+ x x))

or

(set 'double (lambda (x) (+ x x)))
(double 20)                        => 40
((lambda (x) (* x x)) 5)           => 25

For all user-defined lambda expressions, newLISP evaluates arguments before using their results in the body expressions. Evaluation is done from left to right. Results then bind to the parameter variables in the lambda expressions from left to right.

Like Scheme, newLISP also evaluates the functor part of an expression before applying the result to its arguments, for example:

( (if (> X 10) * +) X Y)

This expression returns the product of X and Y if X is greater then 10 and otherwise the sum of X and Y.

lambda-macro expressions do not evaluate their arguments. Using this feature newLISP's syntax can be expanded. Most built-in functions evaluate their arguments first and from left to right, as needed when executed. Deviations from this rule are stated in the reference section of this manual. In LISP, built-in functions, which do not evaluate all or some of their arguments first, are called special forms.

Shell commands: If a ! is entered as the first character on the command line immediately followed by a shell command, that command will be executed, i.e. !ls in Unix or !dir in Win32 would show a directory listing. There should be no space between ! and the shell command. Symbols starting with ! are still valid when occurring inside expressions or preceded by a space on the command line. Note that this mode will only work in a newLISP OS shell and not when controlling newLISP from another application.

Pressing Ctrl-D from the newLISP shell command line will exit newLISP on Linux/UNIX.

To use shell commands from another application or pass results back to newLISP use the exec function.




7. Lambda expressions in newLISP

Lambda expressions in newLISP evaluate to themselves and can be treated like any other list:

(set 'double (lambda (x) (+ x x))
(set 'double (fn (x) (+ x x))      ;; alternative syntax

(last double) => (+ x x)           ;; treat lambda as a list

Note that no quote ' was necessary in front of the lambda expression because lambda expressions in newLISP evaluate to themselves.

The second line uses an alternative syntax using the keyword fn (this was first suggested by Paul Graham in his language project Arc).

In newLISP Lambda expressions are sub data type lambda list of type list. When using append on lambda lists the lambda list type is associated from the left to the right argument:

(append (lambda (x)) '((+ x x))) => (lambda (x) (+ x x))

When using cons on lambda lists the lambda list type is associated from the right to the left:

(cons '(x) (lambda (+ x x)))     => (lambda (x) (+ x x))

Note that the lambda keyword is not a symbol in a list but rather designates a special type of list: the lambda list.

(length (lambda (x) (+ x x)))    => 2
(first (lambda (x) (+ x x)))     => (x)

Lambda expressions in newLISP can be applied or mapped to parameters to work as user-defined, anonymous functions:

((lambda (x) (+ x x)) 123)           =>  246
(apply (lambda (x) (+ x x)) '(123))  =>  246
(map (lambda (x) (+ x x)) '(1 2 3))  => '(2 4 6)

As in Scheme lambda expressions can be assigned to symbols, that then can be used like functions:

(set 'double (lambda (x) (+ x x)))   => (lambda (x) (+ x x))
(double 123)                         => 246

The function define is just a shorter form of setting a symbol to a lambda expression:

(define (double x) (+ x x)))         => (lambda (x) (+ x x))
(double 123)                         => 246

The inside of the lambda list is still accessible in double (as shown previously):

(set 'double (lambda (x) (+ x x)))   => (lambda (x) (+ x x))
(last double)                        => (+ x x)

A lambda list assigned to a symbol can still be manipulated as a first class object with any function operating on lists:

(set-nth 1 double '(mul 2 x))      =>  (lambda (x) (mul 2 x))
double                             =>  (lambda (x) (mul 2 x))
(double 123)                       =>  246

When applying lambda expressions, all parameters are optional and will be set to nil if not filled in by the user. This makes it possible to write functions with multiple parameter signatures.




8. nil, true, cons and () in newLISP

The symbols nil and true in newLISP represent both, symbols and the Boolean values false and true. Depending on the context nil and true are treated differently. The following examples deal with nil but can be applied to true by reversing the logic.

Evaluation of nil yields Boolean false and is treated as false in flow expressions such as if, unless, while, until and not. In like manner true yields true.

(set 'lst '(nil nil nil))    =>    (nil nil nil)
(map symbol? lst)            =>    (true true true)

In the first example nil represents a symbol. In the following example nil and true are evaluated and represent a Boolean values:

(if nil "no" "yes")    =>  "yes"
(if true "yes" "no")   =>  "yes"
(map not lst)          =>  (true true true)

In newLISP nil and the empty list () are not the same as in some other LISPs. Only in conditional expressions as found in and, or, if, unless, cond, while and until are they treated as a Boolean false.

The expression (list? '()) is true but (list? nil) fails because in newLISP nil is a Boolean data type when evaluated.

Evaluation of (cons x '()) yields (x), but (cons x nil) yields (x nil), because nil is not treated as an empty list but as a Boolean type value when evaluated. The cons of two atoms in newLISP does not yield a dotted pair but rather a list with two elements. The predicate atom? is true for nil but false for the empty list (). The empty list () in newLISP is still only a list and is not equal to nil.

In newLISP a list is a LISP cell of type list, which acts like an envelope for a linked list of elements making up the list cell's contents. There is no dotted pair in newLISP, as the cdr (tail) part of a lisp cell always points to another lisp cell in newLISP and never to a basic data type such as a number or a symbol. Only the car (head) part may contain a basic data type. cdr and car were the names of the 'head' and 'tail' of a list in the first and other early LISP implementations.

For a proof of consistency when defining nil and cons in newLISP see purelisp.lsp, the consistency of newLISP




9. Arrays

Arrays in newLISP are used to speed up access in large lists. Using the function array arrays can be constructed or lists can be converted to arrays for much faster access. New arrays can be initialized from existing lists. Arrays can be converted back to lists. Some of the same functions used for accessing and modifying lists can be used on arrays. Arrays can hold any data type or mixture of data types.

In particular the following functions can be used for creating, accessing and modifying arrays:


  function  description
array create and initialize an array with up to 16 dimensions
array-list return a list conversion from an array
array? check if expression is an array
nth-set change the element and returns the old element, this form is much faster than set-nth
set-nth change the element and returns the changed array

Internally newLISP represents multidimensional arrays with arrays in which each row in turn is an array.

When working with newLISP interactively in a console window or with the newLISP-tk front-end, arrays are displayed as lists. There is no special character or parenthesis differentiating between lists and arrays when printed or displayed.

When serializing arrays using the source or save function, arrays are shown with the array statement necessary to create them. This way variables containing arrays are correctly serialized when saving with save or creating source strings using source.

Similar to lists negative indices can be specified to enumerate array elements beginning at the last position in a row.

Indices out of bounds will cause an error message. This is different in lists where out of bound indices pick the last or first element.

Arrays can be non-rectangular but will be made rectangular during serialization with source or save, because the array functions always constructs arrays in a rectangular form.

The 3 matrix functions transpose, multiply and invert should still only be used on matrices built with lists. These functions convert lists to matrices internally for fast processing.

See the reference sections for array, array? and array-list for more details.




10. Hash tables

newLISP has no built-in hash tables but can simulate hash tables very efficiently using symbols. Symbols in newLISP are implemented using an efficient read black binary tree algorithm. This algorithm balances the binary symbol tree for faster access. Symbol trees in newLISP represent name spaces itself named by a context name, part of the MAIN name-space.

For a more detailed introduction to namespaces see the chapter Contexts.

Associative access similar as found in hash tables is done using the function sym or symbol, which is just an older longer spelling of the same function:

;; create a hash symbol and store data in it

(set (sym "John Doe" 'MyHash) 123)   => 123
(set (sym "Jane Doe" MyHash) 456)    => 456

;; retrieve contents from hash symbol

(eval (sym "John Doe" MyHash))       => 123
(eval (sym "Jane Doe" MyHash))       => 456

;; list all hash symbols

(symbols MyHash)    => (MyHash:Jane Doe MyHash:John Doe)

Each of the set statements creates a symbol and stores a value of any data type in it. The first statement also creates the hash context named MyHash. Note that once the name space MyHash is created in the first statement, the quote can be ommitted in the subsequent statements, but quoting would give the same result.

The two eval statements retrieve the contents of the symbols in the name space MyHash. The last statement uses the symbols function to retrieve a list of all symbols created.

Note that hash symbols can contains spaces or any other special character normally not allowed in newLISP symbols working as names of variables.

The file hash.lsp from the source distribution displayed here puts an object oriented wrapper around the hash symbol creation and retrieval and adds some utility functions for creating new hashes and list the contents.

Note that constant rather than define statements are used to define the functions in order to pretect the function names from being used as hash symbols themselves.

;;
;; hash.lsp - functions for making  hashes in newLISP
;;
;; version 1.1 - changed HASH:new to HASH:make
;; to make correct serialization of hashes possible
;;
;; version 1.2 - changed 'symbol' function can take any string
;;               much faster than last version
;;               now uses the default function HASH as constructor
;;
;; version 1.3 - changed 'symbol' to the identical but shorter 'sym'
;; version 1.4 - one 'symbols' was converted wrong
;;
;; a hash key can be any string, number or symbol, 
;; a key can contain any characters and does not have to
;; be a legal newLISP symbol, but the keys:  
;; this, put, get, key, keys, value, values and the name of the
;; hash created, can not be used and are protected.
;;
;;
;; example: 
;;
;;       (load "hash.lsp")                  ;; load this module
;;
;;       (HASH 'MyHash)                     ;; create a hash MyHash
;;
;;       (MyHash:put "someKey" 1234)        ;; create key-value entry
;;       (MyHash:put "anything" '(1 2 3))   ;; create key-value entry
;;
;;       (MyHash:get "someKey")             => 1234
;;       (MyHash:get "anything")            => (1 2 3)
;;
;;       (MyHash:keys)                      => ("anything" "someKey")
;;
;;       (new MyHash 'MyHash-2)             => MyHash-2
;;       (MyHash-2:get "someKey")           => 1234
;;
;;       (MyHash:values)                    => ((1 2 3) 1234)

(context 'HASH)

(constant 'HASH:HASH (lambda (this) ;; default function as constructor    
    (new 'MAIN:HASH this)))         ;; use new to copy
	
(constant 'put (lambda (key value)
    (set (sym key this) value)))

(constant 'get (lambda (key)
    (eval (sym key this))))

(constant 'keys (lambda ()
    (map name (difference (symbols this);; subtract illegal keys
                (append '(this put get key keys value values) 
                         (list (sym (name this) this)))))))

(constant 'values (lambda () 
    (map get (keys))))


(context MAIN)

;; eof

In the new created HASH object MyHash the symbol this will contain the context MyHash. This insures that the functions inside MyHash refer to MyHash and not the calling context. Note also, that all new created HASH object symbols are members of MAIN.

As constructor function for new symbol trees the default function HASH:HASH is used, which can be called abbreviated as (HASH ...).

Note that hash context objects containing symbols, which are not legal symbols in newLISP source expressions, should not be serialized using save, but should be serialized writing out the name strings to a data file. This data file can then be loaded again an fed into the hash table.

See the chapter Programming with context objects for more detail on using contexts as objects.




11. Indexing elements of strings, lists and arrays

Elements of strings (characters) or elements of lists or arrays are specified in some functions by one or more int-index. The (positive) indices run 0, 1, ..., N-2, N-1 where N is the number of elements in the list. If int-index is negative, the sequence of indexing is -N, -N+1, ..., -2, -1. Adding N to the negative index of an element yields the positive index. Unless otherwise specified for a function, an index greater than N-1 returns the last element in a list but causes an 'out of bounds' error in arrays. An index less than -N returns the first when in lists, but will cause an error message in an arrays.


Implicit indexing for nth

Since version 8.5 instead of using nth for retrieving characters of strings, or elements of lists or arrays implicit indexing can be used without the nth operator:

(set 'lst '(a b c (d e) (f g)))

(lst 0)    => a      ; same as (nth 0 lst)
(lst 3)    => (d e)  
(lst 3 1)  => e      ; same as (nth 3 1 lst)
(lst -1)   =>  (f g)

(set 'myarray (array 3 2 (sequence 1 6)))

(myarray 1)     => (3 4)
(myarray 1 0)   => 3
(myarray 0 -1)  => 2

("newLISP" 3)   => "L"

Indices may also be supplied in a list. This way implicit indexing works together with other functions, which can take or produce index vectors like push, pop and ref.

(lst '(3 1)) => e

(set 'vec (ref 'e lst)) => (3 1)

(lst vec)    => e

Implicit indexing is slightly faster then indexing using nth and can take an unlimited number of indices.

Note that implicit indexing with nth works on character rather than byte boundaries when using the UTF-8 enabled version of newLISP.

Implicit indexing for rest and slice

By prepending a list with one or two numbers for offset and length implicit forms of rest and slice can be created:

;; implicit nrest

(1 '(a b c d e f g))      => (b c d e f g)
(2 '(a b c d e f g))      => (c d e f g)
(10 '(a b c d e f g))     => ()
(-3 '(a b c d e f g))     => (e f g)

(1 "abcdefg")             => "bcdefg"
(2 "abcdefg")             => "cdefg"
(10 "abcdefg")            => ""
(-3 "abcdefg")		  => "efg"

;; implicit slice

(0 3 '(a b c d e f g))    => (a b c)
(-4 2 '(a b c d e f g))   => (d e)

(0 3 "abcdefg")           => "abc"
(-4 2 "abcdefg")          => "de"

Note that implicit indexing for rest works on character boundaries rather than byte boundaries when in using the UTF-8 enabled version of newLISP. Implicit indexing for slice will always work on byte boundaries and can be used for binary content.


Implicit indexing and the default function

The default function is a funtion in a context with the same name as the context itself, see chapter The context default function. The default mechanism can be used together with implicit indexing and at the same time serve as a mechanism for referencing lists:

(set 'MyList:MyList '(a b c d e f g))

(MyList 0)    => a
(MyList 3)    => d
(MyList -1)   => g

(set 'aList MyList)

(aList 3)     => d

The list in aList references MyList:MyList and is not a copy. See also the chapter Programming with context objects.




12. Destructive versus non-destructive functions

In newLISP almost all primitives are non-destructive (have no side effects), they may create new data objects but don't change the existing ones. There are a few destructive functions which do change the contents of a list, string or variable:

constant sets the contents of a variable and protects it
dec decrements the value in a variable
inc increments the value in a variable
net-receive reads into a buffer variable
push pushes a new element onto a list
pop pops an element from a list
read-buffer reads into a buffer variable
replace replaces elements in a list or string
replace-assoc    replaces associations in a association list
reverse reverses a list or string
rotate rotates elements of a list
set, setq, set! set the contents of a variable
set-nth, nth-set changes an element in a list or string
sort sorts the members of a list
swap swaps two elements in a list or string



13. Dynamic and lexical scoping

Inside contexts newLISP uses dynamic scoping, but different contexts are separated lexically from each other. In this way newLISP programs can take advantage of both scoping mechanisms.

When binding parameter symbols in lambda expressions to their new contents, the old bindings (environment) of these symbols are saved on a stack. newLISP automatically restores the environment (the original variable bindings) when leaving the lambda function. The following example illustrates this dynamic scoping mechanism. The boldface characters are output from newLISP on the console; the normal type face is the keyboard input:

(define (add-three-nums x y z)
    (print-vars)
    (+ x y z))

(define (print-vars)
    (print "X=" x " Y=" y " Z= " z "\n")

> (set 'x 4)
4

> (set 'y 5)
5

> (set 'z 6)
6

> (print-vars)
X=4 Y=5 Z=6
6

> (add-three-nums 70 80 90)
X=70 Y=80 Z=90
240

> (print-vars)
X= 4 Y=5 Z=6
6

>

A function add-three-nums is defined, which calls a function, which prints the contents of the symbols x, y, z, then returns the sum of its three arguments. Another function print-vars prints the contents of the symbols x, y, and z. Before calling add-three-nums the symbols x, y, and z are bound to the values 4, 5, and 6.

Note that the function print-vars prints different bindings of x, y and z depending where it was called from. While in the scope of add-three-nums the symbols x, y and z have different bindings. The old bindings of x, y and z are restored after returning from add-three-nums. This is different from the lexical scoping mechanism in languages like 'C', Java and most current LISPs, where the binding of local parameter symbols yields only inside the function. In lexically scoped languages like 'C' print-vars would always print the global bindings of the symbols x, y, z (4, 5, 6).

Note that by passing quoted symbols to a user-defined function, a potential name clash may occur if the same variable name is used as a function parameter:

(define (inc-symbol x y)
    (inc x))

(set 'y 200)
(inc-symbol 'y 123) => 246

y                   => 999   ; y is still 999

When trying to modify the content of 'y inside the function it modifies 123 to 124 not 200 to 323. This variable capture is a disadvantage of dynamic scoping when passing symbol references to user-defined functions.

The problem can be avoided by grouping related user-defined functions in their own context. This way, when called from the outside of that context, a symbol clash never occurs.

When creating function libraries or interfaces in newLISP, functions belonging together should always be grouped into contexts, which put a lexical 'fence' around them and avoid variable name clashes with calling functions.

newLISP creates different forms of lexical scoping using contexts. See the chapters contexts, Programming with context objects and the sub chapter Lexical, static scoping in newLISP and the usage of default functions.




14. Early return from functions, loops, blocks

This shows methods to interrupt the proggram flow in blocks of statements as they occur in loops and the begin expression.


Using catch and throw

As a functional language newLISP has not return or break statement to exit from a function or break or an iteration loop early. Control functions like if, unless or cond are used for program flow control. Fortunately newLISP has a catch and throw, which can be used to exit a function or block at different points or to break out of iteration loops. Since version 8.3.3 this has gotten easier with an added simplified syntax for catch which now can be used to return the evaluation result of the called function:

(define (foo x)
	...
	(if condition (throw 123))
        ...
	456)

; if condition is true

(catch (foo p))  => 123

; if condition is not true

(catch (foo p))  => 456

Multiple return points could be coded with multiple throw function calls.

Breaking out of an iteration loop works similar:

(catch 
	(dotimes (i N) 
		(if (= (foo i) 100) (throw i)))) 

=> value of i when foo(i) equals 100

The example shows how an iteration loop can be left before executing N times.

catch can be used to leave any block of code ant any point:

(catch (begin
	(foo1)
	(foo2)
	(if condition-A (throw 'x))
        (foo3)
        (if condition-B (throw 'y))
	(foo4)
	(foo5)))

In the last example, if condition-A is true x will be returned from the catch expression or y if condition-B is true, else the result from foo5 will be the return value from the catch expression.

Note that catch can also be used to catch error exceptions caused by faulty code or by user initiated error exceptions using throw-error.

Using and or or

Using the logical functions and and or statement blocks can be built, which are left depending on the Boolean result of the enclosed functions:

(and
    (func-a)
    (func-b)
    (func-c)
    (func-d))

The and expression will return as soon as one of the blocked functions returns nil or the empy list () or will return the evaluation result of the last function. Likewise or ca be used.

(or
    (func-a)
    (func-b)
    (func-c)
    (func-d))

As soon as any of the function returns a value which is not nil or not the empty list () the or expression will return the evaluation result of the succeeding function.




15. Contexts

Contexts in newLISP constitute different name-spaces. Each name-space has its own private symbol table and is lexically separated from the other contexts. The same name may be used for a symbol in different contexts without a conflict.

In newLISP contexts can be used to build software modules with isolated variable and function definitions. Contexts can also be copied and dynamically assigned to variables or passed as parameters during runtime. Because contexts have their own lexically separated name-spaces, newLISP can be used for lexical scoping style of programming and programming with software objects.

Contexts are identified by symbols which are owned by the root or the MAIN context. Context symbols are always shown in this chapter in uppercase. Lowercase contexts symbols may be used as well and are only avoided here for better visibility. The MAIN context contains also all symbols for built-in functions in newLISP and the symbols true and nil. MAIN is built into newLISP and needs not be created by the user.


Scoping rules for contexts

All built-in function symbols, context symbols and symbols in MAIN made global using the global function and special symbols like nil or true are known in all other contexts. All other symbols not from the current context must be prefixed by the context name.

The following lines simulate a command line session in newLISP.

Except for MAIN, the current context symbol is visible on the command line before the > prompt symbol, e.g.:

> (context 'FOO)
FOO>

If the context FOO already exists, newLISP just switches to it. If FOO does not exist newLISP creates it. All symbols which are now created are known only in the context FOO and the command line prompt changes to FOO> :

FOO> (set 'x 123)
123
FOO> (set 'y 456)
456
FOO> (symbols)
(x y)

To refer to a symbol outside its context, it has to be preceded by the context name and a colon, e.g.:

> FOO:x
123

The same symbol x may also be used in another context:

> (context 'FOO-B)
FOO-B> (set 'x 777)
777
FOO-B> FOO:x
123

When quoting a symbol from another context, the quote precedes the name of the context, for example:

> (set 'FOO-B:x 555)
555

Referring to a context which does not exist causes it to be created implicitly without using the context function and without switching to the context:

> (set 'ACTX:var hello)
"hello"
> ACTX:var
"hello"

The same symbol name x used in a context can also be used in MAIN. Now we have three versions of x all in a different context:

> (set 'x "I belong to MAIN")
"I belong to MAIN"
> FOO:x
123 > FOO-B:x 555 > x "I belong to MAIN"

In context FOO, symbols owned by MAIN or other contexts are not accessible unless prefixed by the context name:

FOO> MAIN:x
"I belong to MAIN"

FOO> FOO-B:x 555 FOO> x 123

The context function tells newLISP where to put all symbols and definitions when translating source files, the command line, or strings in the eval-string, or symbol function:

;; file MY_PROG.LSP
;
; every thing from here on goes into GRAPH
(context 'GRAPH)

(define (draw-triangle x y z)
        (...))

(define (draw-circle) 
        (....)

; switch back to MAIN
(context 'MAIN)

;; end of file

The functions draw-triangle and draw-circle and there variable symbols are now part of the context GRAPH. Both, the functions and their variable symbols are lexically separated from MAIN or any other context. To execute these functions from a context other than GRAPH, prefix them with the context name GRAPH.

(GRAPH:draw triangle 1 2 3)

Comparing symbols in different contexts compares their names including the context names. To compare just the name parts of symbols use name to extract the name from a symbol without the context.

(set 'CTXA:val 123)    => 123
(set 'CTXB:val 456)    => 456

; same symbol name, but different context name

(= 'CTXA:val 'CTXB:val)                => nil 

(= (name 'CTXA:val) (name 'CTXB:val))  => true

Changing scoping and symbol protection

By default only built-in functions and symbols like nil and true are visible in other contexts than MAIN. To make other symbols in MAIN visible to other contexts use the function global:

(set 'aVar 123)   => 123
(global 'aVar)    => aVar

(context 'FOO)    => FOO

aVar => 123

Without the global statement, the second aVar would have referred to a variable in the context FOO and returned its value. Symbols can be protected from change using the function constant :

(constant 'aVar 123)   => 123

(set 'aVar 999)        ; causes error:  symbol is protected

Sometimes there is the need to make a symbol both a constant and a global:

(constant (global 'aVar) 123)

By nesting both functions a symbol can be made global and constant at the same time. This may be useful when importing functions from libraries, which are used globally.

To overwrite a variable protected by constant, constant has to be used again, but can only be used for symbols in the current context. This protects symbols from being overwritten  by code in other contexts.


Overwriting global symbols and built-ins

Global symbols and built-in functions symbols can be overwritten inside a context by explicitly prefixing them with the context symbol:

(context 'Account)

(define (Account:new ...)
...)
(context 'MAIN)
In this example the built-in function new is overwritten by Account:new which is a different function, private to the context Account. Whenever the symbol new occurs from now on in the context Account, it will refer to the private definition.


Variables holding contexts

Contexts can be referred to by variables:

(set 'ctx FOO)     => FOO

ctx:x              => 123

(set 'ctx:x 999)   => 999

FOO:x              => 999

Assigning contexts to variables is important when using contexts as objects created with new during runtime and when writing functions for non-existing contexts.

Context variables also offer the possibility to pass big data objects by reference via the enclosure of memory objects in contexts and passing the context variable as a parameter.


Sequence of creating or loading contexts

The sequence how contexts are created or loaded can lead to unexpected situations:

;; demo - file for loading contexts
(context 'FOO)
  (set 'ABC 123)
(context MAIN)

(context 'ABC)
  (set 'FOO 456)
(context 'MAIN)

Now the contexts are loaded:

> (load "demo")
symbol is protected in function set : FOO
>

Loading the context files causes an error message for FOO but not for ABC. When the first context FOO is loaded, the context ABC does not exist yet and a local variable FOO:ABC gets created. When context ABC loads, the symbol FOO already exists as a global protected symbol and will be correctly flagged as protected.

FOO could still be used as a local variable symbol in context ABC by explicitly prefixing it: ABC:FOO .

To avoid unexpected behavior when loading contexts used as program modules, when building bigger applications always follow the following pattern:

;; begin of file - MyModule.lsp

(load "This.lsp")
(load "That.lsp")
(load "Other.lsp")

(context 'MyModule) 
   ...

(define (func x y z)
   ...
)
   ...
   ...

(context 'MAIN)

(MyModule:func 1 2 3)

(exit)

;; end of file

Always load auxiliary modules required before the module's context statement. Always terminate the context switching back to MAIN. Start the code from MAIN.


Symbol creation in contexts

The following rules can simplify the understanding of contexts and to which context symbols belong to when they are created.

  1. newLISP first parses and translates code then it evaluates it, during translation symbols are created.

  2. A symbol is created when seen by newLISP first, specifically during load, eval-string and symbol. Symbols are created when before evaluation when newLISP reads source.

  3. During symbol creation the symbol is assigned to a context and stays. Once a symbol is created for a speficic context, it will belong to that context for forever.

  4. When newLISP during code translation sees a new symbol it is looked up first in the current context, if not there it is looked up in the MAIN context to check if it is a built-in function or existing context name. If not found as a global function or context symbol in MAIN its is created as a local symbol in the current context.

The following code illustrates the working of these rules:

(context 'A)    ; create context 
(set 'y 123)
(context 'MAIN) ; switch back to MAIN

(context 'C)
(context 'MAIN)

(context 'CTX)

(set 'x 123)    ;  x belongs to CTX
(set 'y 123)

(define (foo)
	(context 'A)
	(set 'x 888)  ; x belongs to CTX not A
	(set 'y 456)  ; y belongs to CTX not A
	)
	
(define (foobar)
	(context 'A)
	(eval-string "(set 'x 999)") ; x will be created in A
	(eval-string "(set 'y 999)") ; y will be changed in A
	)
	
(define (foofoo)
	(eval-string "(set 'x 222)") ; x will be created in the context
	                             ; from where foofoo is called
	)	                             

(context 'MAIN)

(CTX:foo)    ; changes CTX:x and CTX:y
(CTX:foobar) ; creates A:x and changes A:y
(CTX:foofoo) ; creates MAIN:x

(context 'C)

(CTX:foo)    ; changes CTX:x and CTX:y
(CTX:foobar) ; changes A:x (was created before) and changes A:y
(CTX:foofoo) ; creates C:x

(context 'MAIN



16. Programming with context objects

As contexts are lexically isolated from each other and can hold variables and methods, they can be used for prototype based object oriented programming.

(context 'ACCOUNT)
    (set 'full-name "") 
    (set 'balance 0.0)  
    (set 'phone "")     

    (define (deposit amount)
        (inc 'balance amount))

    (define (withdraw amount)
        (dec 'balance amount))
(context 'MAIN)

The context ACCOUNT serves as a prototype for other account objects:

(new ACCOUNT 'John)     ; this creates a new context copy of 
                        ; ACCOUNT called 'John'

(set 'John:full-name "John Doe")
(set 'John:phone "555-123-456")

(John:deposit 100.00)
(John:withdraw 60)

(new ACCOUNT 'Anne)

(set 'Anne:full-name "Anne Somebody")
(set 'Anne:phone "555-456-123")

(Anne:deposit 120.00)
(Anne:withdraw 50)

The previous lines creates two new contexts as copy from the prototype context using the function new. Note that OO programming purists would use getter and setter functions to access object variables. This is not necessary in newLISP as context variables are still accessible prefixing the variables with the context/object name and user-defined functions in a context would occupy space in each instance of a context object. Using new mixins of different contexts into one are possible. See the description of new for details.


Late binding of context symbols

A contexts can be assigned to a variable and referred to by the variable name. Inside the following report function, the context passed in a variable is referred to by accnt:

(define (report accnt)
    (println 
       (format "%-20s %8.2f" accnt:full-name accnt:balance)))

(report John)
John Doe                40.00

(report Anne)
Anne Somebody           70.00

; eval symbols to contexts first 
(map report (map eval '(John Anne)))

John Doe                40.00
Anne Somebody           70.00

map is used here to apply the function report in each of the context objects John and Anne. The inner map evaluates the context symbols to contexts. Inside the report function the contexts are referred to by the variable accnt.

Note that the function report could have been defined before any of the contexts existed. The variables accnt:full-name and accnt:balance and there context prefixes are not resolved until the function is called. This late binding of variable symbols facilitates using contexts as software objects, which can be dynamically referenced during runtime.


Passing objects by reference

In newLISP all parameter passing is done by value. This could pose a potential problem when passing big lists or strings to user defined functions or macros. Fortunately Symbols and context objects are passed by reference and can be used to pass big memory objects by reference and without the overhead of copying the entire list or string:

;; pass an object by reference

(set 'mydb:lst (sequence 1 1000000))

(define (change-db obj idx value)
	(nth-set idx obj:lst value))

(change-db mydb 1234 "abcdefg")

(nth 1234 mydb:lst)     => "abcdefg"

The example shows how objects can be passed by reference to a user defined function using context variables, without the overhead of copying in parameter passing by value. The same technique shown here for a list can be used for string buffers or any other date object enclosed in a context.


Contexts as prototypes

Dynamic context variables can be used inside a context to create object protoypes with a make-new method. This make-new method can be used to initialize variables in the instantiated object:

(context 'Account)

    (define (make-new ctx nme bal ph) 
	(new Account ctx)
	(set 'ctx (eval ctx))             ;; get context out of symbol

	(set 'ctx:full-name nme)          ;; initialize new object
        (set 'ctx:balance bal)
        (set 'ctx:phone ph))

    (define (Account:deposit amount)
        (inc 'balance amount))

    (define (Account:withdraw amount)
        (dec 'balance amount))

(context 'MAIN)

(Account:make-new 'JD-001 "John Doe" 123.45 "555-555-1212")

;; or when creating an account from inside a different context

(Account:make-new 'MAIN:JD-001 "John Doe" 123.45 "555-555-1212")

JD-001:balance    => 123.45

The context default function

A context can contain a user defined function or macro with the same name as the context. This is function is called a default function because it is evaluated by default when calling using the context symbol as a function name. When trying to apply a context as a function, newLISP will execute this default function.

(define (foo:foo a b c) (+ a b c))

(foo 1 2 3)    => 6

This feature can be used to create functions, which look like normal functions, but really are context objects with a method whose name is identical to the context name and can update their lexically isolated static variables:

(define (gen:gen x) 
    (if gen:acc 
        (inc 'gen:acc x)
        (set 'gen:acc x)))

(gen 1) => 1
(gen 1) => 2
(gen 2) => 4
(gen 3) => 7

gen:acc => 7

The function gen increments its internal accumulator by the parameter or sets it to the parameter when the function is called the first time.

If default functions are called from any other context than main the context should already exist before referred to in another context or it should be declared in a forward declaration, which causes the context and function symbol to be created:

(define fubar:fubar)    ;; forward declaration 
                        ;; of default function

(context 'foo)
(define (foo:foo a b c)
	...
	(fubar a b)	;; forward reference 
	            ;; to default function
	...
	) 

(context 'MAIN)


;; definition of previously declared default function

(context 'fubar)        
(define (fubar:fubar x y)
	...
	)

(context 'MAIN)

Default functions look like normal global functions, but are lexically separated from the context they are used in. A default function is safe against variable capture when calling it with variables carrying the same name as the parameter variables of the function.

Default functions can also be used with map or apply like any other lambda or lambda-macro function. Only when accessing a default function as a data object, it has to be written in conventional form with context prefix and colon.


Lexical, static scoping in newLISP

Effectively a default function looks and behaves like a statically scoped function in other programming languages. Several functions can share one lexical closure.

Using the function def-new a function or macro can be defined to define other statically scoped functions:

    ;; define static functions
    ;;
    ;; Example:
    ;;
    ;; (def-static 'foo (fn (x) (+ x x)))
    ;;
    ;; foo:foo => (lambda (foo:x) (+ foo:x foo:x))
    ;;
    ;; (foo 10) => 20
    ;;
    (define (def-static s contents)
       (def-new 'contents (sym s s)))

While parameters of lambda functions are set to nil after function return, other variables will keep there contents in the lexical environment (context) they where defined in:

    (def-static 'acc (fn (x) (if sum (inc 'sum x) (set 'sum x))))

    (acc 5) => 5
    (acc 5) => 10
    (acc 2) => 12

    acc:sum => 12
    acc:x   => nil

The example shows how the parameter variable acc:x behaves like a automatic local variable and the variable acc:sum like a local static variable.

When forward referencing a statically defined function in another statically defined function, the forwarded function has to be declared earlier:

(define foo:foo)    ;; declare so it can be 
                    ;; referenced before definition

;; foo is forward referenced 
(def-static 'forward (fn (x) (foo x)))  

(def-static 'foo (fn (x) (+ x x)))

(forward 10) => 20

Without the pre declaration fo foo:foo it would not be possible to reference it in another statically defined function.

Note that the keyword fn and lambda have the same effect and can be interchanged.



Serializing context objects

Serializing a software object is the process of making it persistent by converting it to a character stream, which can be saved to a file or memory string. In newLISP any object can be serialized to a file using the save function. Like other symbols Contexts are saved by just using their name:

    (save "mycontext.lsp" 'MyCtx)  ; save MyCtx to mycontext.lsp

    (load "mycontext.lsp")         ; loads MyCtx into memory

Multiple context objects can be saved in one statement. See the function save for details.

See the function source for serializing to a newLISP string.




17. XML, SXML and XML-RPC

newLISP has built-in support for XML encoded data or documents using only the three functions xml-parse, xml-type-tags and xml-error.

While xml-parse is used to parse the XML encoded string, the xml-type-tags functions is used to control or suppress the appearance of XML type tags. These tags classify each XML part in one of the for categories of text, raw string data, comments and element data. The function xml-error is used to diagnose syntax errors caused by not well formed XML. In case of an error xml-parse would return nil.

XML source:
    <?xml version="1.0" >?
    <DATABASE name="example.xml">
    <!--This is a data base of fruits-->
        <FRUIT>
	        <NAME>apple</NAME>
            <COLOR>red</COLOR>
		    <PRICE>0.80</PRICE>
        </FRUIT>
    </DATABASE>

Parsing without any options:
    (xml-parse (read-file "example.xml"))

    =>
    (("ELEMENT" "DATABASE" (("name" "example.xml")) (("TEXT" "\r\n")
       ("COMMENT" "This is a data base of fruits")
       ("TEXT" "\r\n        ")
       ("ELEMENT" "FRUIT" () (
         ("TEXT" "\r\n\t        ") 
         ("ELEMENT" "NAME" () (("TEXT" "apple")))
         ("TEXT" "\r\n\t\t")
         ("ELEMENT" "COLOR" () (("TEXT" "red")))
         ("TEXT" "\r\n\t\t")
         ("ELEMENT" "PRICE" () (("TEXT" "0.80")))
         ("TEXT" "\r\n\t")))
       ("TEXT" "\r\n"))))

Using xml-type-tags and special option parameters in the xml-parse function SXML can be generated directly from XML:


SXML generation using all options:
    (xml-type-tags nil nil nil nil) 
    (xml-parse (read-file "example.xml") (+ 1 2 4 8 16))

    =>
    ((DATABASE (@ (name "example.xml")) 
        (FRUIT (NAME "apple") 
            (COLOR "red")
            (PRICE "0.80"))))

SXML is XML reformatted as LISP s-expressions the @ denotes a XML attribute specification.

For details on parsing and option numbers and a bigger example see the documentation for the function xml-parse in the reference section of the manual.


XML-RPC

XML-RPC is a remote procedure calling protocol using a HTTP post request as a transport and XML for encoding of method names, parameter types and parameters. Implementations of XML-RPC client libraries and servers exist for most popular compiled and scripting languages.

For more information about XML visit http://www.xmlrpc.com/.

XML-RPC clients and servers are easy to write in newLISP via it's built-in support for XML and HTTP request functions. Version 8.4.0 of newLISP introduces a working newLISP XML-RPC server. This stand-alone server can be found in the source distribution as examples/xmlrpc-server server and does not require any other web-server. The server is started with the following shell command line on all platforms:

newlisp -x 8080 xmlrpc-server

This assumes the newLISP executable in the OS path and the file xmlrpc-server in the current directory. Instead of 8080 a different port could be chosen. This stand-alone server maintains state between function calls. If a state-less XML-RPC server is required the file examples/xmlrpc.cgi can be used together with Apache or another web server. Both XML-RPC service scripts implement the following methods:


system.listMethodsReturns a list of all method names
system.methodHelpReturns help for a specific method
system.methodSignature  Returns a list of return/calling signatures for a specific method
newLISP.evalStringEvaluates an BASE64 newLISP expression string

The first three methods are discovery methods implemented by most XML-RPC servers The last method is newLISP XML-RPC server specific and implements remote evaluation of a piece of newLISP source in a BASE64 encoded string. newLISP's base64-enc and base64-dec functions can be used to encode and decode BASE64 encoded information.

In the modules directory of the source distribution a file xmlrp-client.lsp is included implementing a specific client interface for all of the above methods. In a future version a generic XMLRPC:call function will be implemented to call any function in a remote XML-RPC server. After starting the newLISP XML-RPC server the following code could be used to access it remotely:

    (load "xmlrpc-client.lsp")    ;; load XML-RPC client routines

    (XMLRPC:newLISP.evalString "http://localhost:8080" "(+ 3 4)")   
    
    => "7"

In a similar fashion standard system.xxx calls could be issued. All functions return a result or nil if the request fails. In case of failure (XMLRPC:error) can be evaluated to return an error message.

For more information please consult the header of the file modules/xmlrpc-client.lsp.




18. Customization, localization and UTF-8

All built-in primitives in newLISP can be easily renamed:

(constant 'plus +)

The new primitive plus now behaves exactly like + and at the same speed. This can be used to use double-float arithmetic through out newLISP like many script languages do.

constant has to be used to rename symbols of built-in primitives instead of set, because all built-in function symbols are protected by default against accidental overwriting.

(constant '+ add)
(constant '- sub)
(constant '* mul)
(constant '/ div)

All operations using +, -, * , / are now performed as floating point operations.

Using the same mechanism, the names of built-in functions can be translated:

(constant 'wurzel sqrt)       ;; German for 'square-root'
(constant 'imprime print)     ;; Spanish for 'print'
...

Switching the locale

newLISP can switch to the locale used on your platform and operating system. Upon startup, newLISP attempts to set the ISO C standard default POSIX locale, which is available on most platforms and locales. To switch to the default locale in your country outside USA use set-locale:

(set-locale "")

This switches to the default locale used on your platform/operating system and makes character handling such as upper-case work correctly.

Many Linux or other Unix systems have a variety of locales available. To find out the locales available on your Linux/BSD or other Unix like system execute the following command in a system shell:

locale -a

This prints a list of all available locales on your shell screen. Any of these can be used together with set-locale:

(set-locale "en_US")

This would switch to a US Spanish locale, which correctly would convert case on accented vocals or other Spanish characters used in Spanish as used in a US environment.

For more details on the usage of set-locale see its manual description.


Decimal point and decimal comma

A majority of countries in the world uses a comma instead of a point as a decimal separator in numbers. Since version 8.4.4 newLISP correctly parses numbers depending on the locale set.

; switch to German locale on a Linux system
(set-locale "de_DE") 

; newLISP source and output use a decimal comma
(div 1,2 3)   => 0,4 

The default POSIX 'C' locale, which is set when newlisp starts up, uses a dot as a decimal separator.


Unicode and UTF-8 encoding

Note that for many European languages the set-locale mechanism is sufficient to display no ASCII character sets as long as each character is presented as one byte internally. Only for multi-byte character sets UTF-8 encoding, as described in this chapter, is necessary.

newLISP can be compiled as an UTF-8 enabled application. UTF-8 is a multi-byte encoding of the international Unicode character set. Using UTF-8 on an UTF-8 enabled operating system any character of the installed locale can be handle by newLISP.

The following steps should be followed to make UTF-8 working with newLISP on your operating system and platform:

(1) Compile newLISP as an UTF-8 application using one of the makefiles ending in: utf8. Type make at the command line to see what is available. If no UTF-8 makefile is available for your platform, the normal makefile of your operating system contains instructions on how to change it for UTF-8.

(2) Enable the UTF-8 locale on your operating system. On Unix like OSs use the locale command to check and set to a UTF-8 locale or use set-locale function in newLISP. On Linux the locale can be changed by setting an appropriate environment variable (example for US):

export LC_CTYPE=en_US.UTF-8

(3) The UTF-8 enabled newLISP will automatically switch to the locale found in the operating system's environment. Make sure the command shell you are using is UTF-8 enabled. When using the Tcl/Tk front-end on Linux/UNIX Tcl/Tk will automatically switch to UTF-8 display when the UNIX environment variable is set correctly. On US-WinXP the notepad.exe application can display Unicode UTF-8 encoded characters, but the command shell and the Tcl/Tk front-end do not. On Linux and other UNIX the Xterm shell application can be used when started as follows:

LC_CTYPE=en_US.UTF-8 xterm

The following procedure now can be used to check UTF-8 support: After starting newLISP type the following in newLISP:

(char 937)              ;; displays Greek upper case omega
(lower-case (char 937)) ;; displays lower case omega

While the upper case omega looks like a big O on two tiny legs, the lower case omega has a shape similar to a Latin small w.

When using UTF-8 enabled newLISP but the display system of the underlying OS is not UTF-8 enabled, two characters will be visible in both cases. These are the two bytes necessary to encode the omega character.

The following string functions work on character boundaries rather than byte boundaries when using UTF-8 enabled newLISP:

char translate between characters and ASCII/Unicode codes
chop chop of characters from the end of a string
date convert date number to string (when used with 3rd parameter)
explode transform a string into a list of characters
first get first element in a list (car, head) or string
last returns the last element of a list or string
lower-case convert a string to lower case characters
nth get the nth element in a list or string
nth-set changes the nth element of a list or string
rest get all but the first element of a list (cdr, tail) or string
select select and permute elements from a list or string
set-nth changes the element in a list or string
trim trim a string from both sides

All other string functions work on bytes. When positions are returned as in find or regex, these are byte positions not character positions. The slice function takes byte offsets rather than character offsets. reverse reverses a byte vector rather than a character vector. The last two functions still can be used to manipulate binary non-textual data in the UTF-8 enabled version of newLISP.

To enable UTF-8 in PCRE regular expressions used by find, parse, regex and replace, the options number has to be set accordingly, see the documentation for regex for details.

To manipulate characters rather than bytes in cases where a UTF-8 enabled function is not available use explode to obtain an array of UTF-8 characters:

(join (reverse (explode str))) ;; reverse UTF-8 characters

Many string functions in newLISP are often used to manipulate non-textual binary data. Care must be taken when using the UTF-8 enabled version, that the above table of functions now works on character rather than byte boundaries. When using only the lower 127 characters of the ASCII set, all characters are one byte long. The same is true when using popular code pages like ISO 8859. Working exclusively in these code pages UTF-8 enabled newLISP is not required and the set-locale function alone is sufficient for localized behavior.

Two new functions are available to convert between 4-byte size Unicode (UCS-4) and and multi-byte UTF-8 code. The UTF-8 function is used to convert from UCS-4 to UTF-8 and the unicode function is used to convert UTF-8 or ASCII strings to USC-4 Unicode.

Both functions are rarely used as most Unicode text files are already encoded in UTF-8, rather than UCS-4 (for byte integer for each character). When using the  "%ls"  format specifier Unicode can be displayed directly.

For further details on UTF-8 and Unicode consult the following reference:

UTF-8 and Unicode FAQ for Unix/Linux by Markus Kuhn:
http://www.cl.cam.ac.uk/~mgk25/unicode.html



19. Commas in parameter lists

Some of the functions in the example programs use a comma to separate the parameter list in two groups. This is not a special syntax of newLISP but rather a visual trick. The comma is just a symbol like any other symbol. The parameters after the comma are not required when calling the function; they declare local variables in a convenient way. This technique is based on the fact that parameter variables in a lambda expression are local and that in newLISP parameters in lambda expressions are optional and not required to be filled in by the caller:

  
(define (my-func a b c , x y z)
        (set 'x .....)
        ...
        ...
        )

When calling the function only a, b and c are used as parameters. The others x, y and z are initialized to nil and are local to the function. After executing the function their contents are forgotten and are restored to their values in the previous Environment.

See also let and letn for another possibility to declare and initialize local variables.




20. purelisp.lsp, the consistency of newLISP

As outlined in a previous chapter, nil the empty list '() and cons work differently in newLISP compared to other LISP implementations. The following "re-definitions" of basic LISP functions prove the internal consistency of this approach.

;;  purelisp.lsp
;;
;;  this file proves the consistent working of 'cons' with 'first'
;;  and 'rest' in newLISP defining some basic list manipulating
;;  functions. 'cons' has a different working in newLISP in the 
;;  following cases: 
;;
;;       (cons 1 nil) => (1 nil)  ;; would be '(1) in other LISP dialects
;;  and
;;       (cons exp)     => (exp)  ;; not defined in other LISP dialects
;;
;;  working definitions using for:
;;
;;    append, apply, reverse, last, length and nth
;;
;;  all defined functions have a pre-pended "_" underscore, so they
;;  do not interfere with the built-in functions of the same name.
;;
;;

;;
;; (_append list1 list2)
;;
;; appends to lists
;;
(define (_append x y)
        (if (empty? x) y
              (cons (first x) (_append (rest x) y))))


;;
;; (_apply op lst)
;;
;; apply an operator/function to a list of args
;;
(define (_apply op lst)                    
        (eval (cons op lst)))


;;
;; (_reverse lst)
;;
;; reverse a list
;;
(define (_reverse lst)
  (if (empty? lst) lst
      (_append (_reverse (rest lst)) (cons (first lst)))))


;;
;; (_last lst)
;;
;; return last element in a list or string
;;
(define (_last lst) 
        (if (empty? (rest lst)) (first lst) (_last (rest lst))))


;;
;; (_length lst)
;;
;; length of a list or string
;;
(define (_length lst) 
        (if (not (first lst)) 0 (+ 1 (_length (rest lst)))))


;;
;; (_nth n lst)
;;
;; return element of list or string at position n
;;
(define (_nth n lst)
  (cond 
   ((= n 0) (first lst))
   ((empty? (rest lst)) (first lst))  
   (true (_nth (- n 1) (rest lst)))))




21. Linking newLISP source and executable

Source code and the newLISP executable can be linked together to build a self-contained executable application. The program link.lsp to accomplish this can be found in the source distribution in the examples directory. As an example the following simple program is linked to the newLISP executable to form a simple self-contained program:

;; uppercase.lsp - Link example
;;
(println (upper-case (nth 1 (main-args))))
(exit)

The program takes the first word on the command line and converts it to upper case. The program resides in the file uppercase.lsp.

To build this program as a self-contained executable follow these steps:

(1)  A copy of the newLISP executable newlisp or newlisp.exe (on Win32), link.lsp and the program to link with: uppercase.lsp should be all in the same directory.

(2)  In a command shell of your computers OS go to that directory and load link.lsp:

    newlisp link.lsp

(3)  On the newLISP command line type in Win32:

    (link "newlisp.exe" "uppercase.exe" "uppercase.lsp")

Or on LINUX/BSD type:

    (link "newlisp" "uppercase" "uppercase.lsp")

(4)  Now exit newLISP and type:

    uppercase "convert me to uppercase"

This will print:

    CONVERT ME TO UPPERCASE

in the console window. Note that on LINUX/BSD the new executable has to be made marked as an executable for the operating system doing the following:

    chmod 755 uppercase

This will give the file executable permission. On Win32 this step is not necessary.




newLISP Function Reference



1. Syntax of symbol variables and numbers

Source code in newLISP is parsed according the rules outlines here. When in doubt the function parse without any optional arguments can be used to verify the behavior of newLISP's internal parser.


Symbols for variable names

A symbol used as a variable or function name must be built according these rules:

  1. Variable symbols must not start with:
    # ; " ' ( ) { } . , 0 1 2 3 4 5 6 7 8 9

  2. Variable symbols staring with a + or - must not continue with a number digit.

  3. Inside the variable name any character is allowed except:
    " ' ( ) : , and space. These characters mark the end of a variable symbol.

  4. A symbol name starting with [ and ending with ] may contain any other character.

All the following symbols are legal variable name in newLISP:

example:
myvar
A-name
X34-zz
[* 7 5 ()};]
*111*

Note that the function sym can be used to create symbols which are not legal as newLISP variables but useful for creating hash like lookup dictionaries:

(set (sym "(#:L*") 456)  => 456

(eval (sym "(#:L*"))     => 456

(set (sym 1) 123)    => 123

(eval (sym 1))       => 123

1                    => 12
(+ 1 2)              => 3

The last example creates a symbol 1 containing the value 123. Note that creating such a symbol will not confuse newLISP's normal operation, because 1 will still be parsed as a number 1.


Numbers

newLISP can recognize any of the following numbers formats:

Integers are one or more digits, optionally preceded by a + or - sign. Any other character will mark the end of the integer or may be part of the sequence if parsed to a float (see float syntax below).

example:
123
+4567
-999

Hexadecimals start with the character string 0x or 0X followed by any combination of hexadecimal digits 0123456789abcdefABCDEF. Any other character will end the hexadecimal number.

example:
0xFF         =>  255
0x10ab       => 4267
0X10CC       => 4300

Octals start with a + or - sign followed by a 0 zero or start with a 0 zero, followed by any combination of the octal digits 01234567. Any other character will end the octal number.

example:
012          =>  10
010          =>   8
077          =>  63
-077         => -63

Floating point numbers start with a + or - sign or a . dot or number digit. When starting with a +, - a non-zero number digit must follow, so the number cannot be confused with an octal number. Floating point numbers can have a decimal point embedded.

example:
1.23          =>  1.23
-1.23         => -1.23
+2.3456       =>  2.3456
.506          =>  0.506

Floating point numbers in scientific notation start with a mantissa part which is a floating point number as described above followed by the letter e or E and exponent formed like an integer.

example:
1.23e3        =>  1230
-1.23E3       => -1230
+2.34e-2      =>     0.0234
.506E3        =>   506



2. Data types and names in the reference

The following type names are used to describe arguments of primitive functions; for example:

syntax: (format str-format exp-data_1 [exp-date-i ... ])

Here str-format denotes a string used as an argument called "format", and exp-data_1 is an expression called "data_1."

bool

true, nil, or expressions evaluating to true or nil.
true, nil, (<= X 10)

int

An integer or expression evaluating to an integer number. Generally if a floating-point number is used when an int is expected, the value is truncated to an integer.
123, 5, (* X 5)

num

An integer, a floating-point number, or an expression evaluating to an integer or floating-point number. If an integer is passed it is converted to a floating-point number.
1.234, (div 10 3), (sin 1)

matrix

A list in which each element itself is a list. All element lists (rows) are of same length. When using multiply or invert all numbers must be floats or integers.
((1  2  3  4)
 (5  6  7  8)
 (9 10 11 12))       ; 3 rows 4 columns

((1 2)(3 4)(5 6))    ; 3 rows 2 columns

str

A string or an expression which evaluates to a string.
"Hello", (append first-name  " Miller")

Several special characters may be included in quoted strings encoded with the escape character \:

\n the line feed character (ASCII 10)
\r the carriage return character (ASCII 13)
\t the tab character (ASCII 9)
\nnn where nnn is a decimal ASCII code between 000 and 255

"\065\066\067" => "ABC"

Instead of quotation marks, "...", curly brackets, {...}, can be used to delimit strings. This is useful when quotation marks occur inside strings. Quoting with curly brackets {...} suppresses the "backslash escape" convention for special characters, and properly nested curly brackets may be used in the string. This can be useful in writing regular expressions or short sections of HTML.

(print "<A HREF=\"http://mysite.com\">" ) ; the cryptic way

(print {<A HREF="http://mysite.com">} )   ; the readable way

; also possible because the inner brackets are balanced
(regex {abc{1,2}} line) 

(print [text]
  this could be
  a very long (> 2048 characters) text,
  i.e. HTML.
[/text])

The delimiter tags [text] and [/text] can be used to limit long portions of text and suppress any translation inside. This is useful for limiting long HTML text passages in CGI files written in newLISP or for use in any situation where character translation should be totally suppressed. Always use the [text] tags when strings are longer than 2048 characters.

sym

A symbol or expression evaluating to a symbol.
'xyz, (first '(+ - /)), '*, '- , 'someSymbol,

context

A special kind of symbol specifying a context or name-space and evaluating to itself.
MyContext, aCtx
Most of the time context symbols in this manual start with an uppercase letter for easier distinction from normal symbols.

func

A symbol or symbol expression evaluating to an operator symbol or lambda-expression.
+, add, (first '(add sub)), (lambda (x) (+ x x))

list

A list of elements of any type, or an expression evaluating to a list.
(a b c "hello" (+ 3 4))

array

An array constructed with the array function.

exp

Any of the above.

body

One or more expressions which can be evaluated. The expressions are evaluated sequentially if there's more than one.
1 7.8
nil
(+ 3 4)
"Hi" (+ a b)(print result)
(do-this)(do-that) 123




3. Functions in groups

Some functions appear in more than one group.

List processing, flow control and integer arithmetic

+, -, *, /,% integer arithmetic
<, >, =, compare any data type: less, greater, equal
<=, >=, != compare any data type: less-equal, greater-equal, not-equal
amb pick an argument at random and evaluate it
and logical and
append append lists or strings to form a new list or string
apply apply a function or primitive to a list of arguments
args retrieve the argument list of a macro expression
assoc search for key word associations in a list
begin begin a block of functions
case branch depending on contents of symbol
catch evaluates an expression and catches an error
cond branch to expressions conditionally
cons prepend an element to a list, make a list
constant define a constant symbol
count counts elements of one list in another list
define define a new function / lambda expression
define-macro define a macro / lambda-macro expression
def-new copy a symbol to a different name-space/context
difference return the set difference of two lists
dolist evaluate repeatedly for all elements in a list
dotimes evaluate repeatedly for a range of numbers
dotree iterate through all symbols of a context
do-until repeat conditionally evaluating an expression
do-while repeat conditionally evaluating an expression
dup duplicates an expression in a list or string
ends-with check the end of a string / list against a key string / list
eval evaluate an expression
expand replace a symbol in a nested list
first get first element in a list (car, head) or string
filter filter a list
find search for an element in a list or string
flat return the flattened list
fn define a new function / lambda expression
for evaluate repeatedly for a range of numbers
if evaluate an expression conditionally
index filter elements from a list and returns their indexes
intersect return the set intersection of two lists
lambda define a new function / lambda expression
last return the last element of a list or string
length calculate the length of a list or string
let declare and initialize local variables
letn nested let initialize local variables incrementally
list make a list
lookup lookup in an association list
map map functions on members of a list, collect results
match pattern matching for strings or lists, see also find and regex
member find a list member
name return the name of a symbol as a string without the context
not logical not
nth get the nth element in a list or string
nth-set changes the nth element of a list or string
or logical or
pop delete a member from a list
push insert a new member in a list
quote quotes an expression
ref return the position of an element in a nested list
rest get all but the first element of a list (cdr, tail) or string
replace replace elements in a list or string
replace-assoc replace an association in a list
reverse reverse a list or string
rotate rotate a list
select select and permute elements from a list or string
set set the binding / contents of a symbol
setq, set! set the binding / contents of a symbol (no quote)
set-nth changes the nth element of a list or string
silent like begin but suppresses console output of return value
slice extracts a sublist or substring
sort sort the members of a list
starts-with checks the start of the string / list against a key string / list
swap swap two elements in a list or string
unique return a list without duplicates
unless evaluate an expression conditionally
until repeat conditionally evaluating an expression
while repeat conditionally evaluating an expression

Bit operators

<<, >>    bit shift left, bit shift right
& bitwise and
| bitwise inclusive or
^ bitwise exclusive or
~ bitwise not

Floating point math and special functions

abs calculate the absolute value of a number
acos calculate the arc-cosine of a number
add add floating point or integer numbers
array create an array
array return a list conversion from an array
asin calculate the arcsine of a number
atan calculate the arctangent of a number
atan2 compute the principal value of the arctangent of Y / X in radians
beta calculate the beta function
betai calculate the incomplete beta function
binomial calculate the binomial function
ceil round to the next higher integer
cos calculate the cosine of a number
crc32 calculate a 32 bit CRCR for a data buffer
crit-chi2 calculate the Chi square for a given probability
crit-z calculate the normal distributed Z for a given probability
dec decrement a number
div divide floating point or integer numbers
exp calculate the exponential e to a number
factor factor a number into primes
fft fast Fourier transform (FFT)
floor round to the next lower integer
flt converts a number to a 32 bit integer representing a float
gammai calculate the incomplete gamma function
gammaln calculate the log gamma function
ifft inverse fast Fourier transform (FFT)
inc increment a number
log calculate the natural logarithm of a number
min find the smallest value in a series of values
max find the largest value in a series of values
mod calculate the modulo of two numbers
mul multiply floating point or integer numbers
normal make a list of normal distributed floating point numbers
pow calculate x to the power of y
prob-chi2 calculate the cumulated probability of a Chi square
prob-z calculate the cumulated probability of a Z value
sequence generate a list sequence of numbers
series create a geometric sequence of numbers
sin calculate the sine of a number
rand generate random numbers in a range
random generate a list of evenly distributed floats
seed seed the internal random number generator
sqrt calculate the square root of a number
sub subtract floating point or integer numbers
tan calculate the tangent of a number

Matrix functions

invert return the inversion of a matrix
multiply multiply to matrices
transpose  return the transposition of a matrix

Array functions

array create and initialize an array
array-list return a list conversion from an array
array? check if expression is an array
nth-set change the element and return old element
set-nth change the element and return changed array

Financial math functions

fv future value of an investment
irr internal rate of return
nper number of periods for an investment
npv net present value of an investment
pv present value of an investment
pmt calculates the payment for a loan

Time and date functions

date converts a date-time value to a string
date-value time in seconds since 1970-1-1 for date and time
now return current date time information in a list
time time in milliseconds to evaluate an expression
time-of-day milliseconds elapsed after start of day

String and conversion functions

add get the memory address of a number of string
append append lists or strings to form a new list or string
char translate between characters and ASCII codes
chop chop of characters from the end of a string
dup duplicates an expression in a list or string
ends-with check the end of a string / list against a key string / list
encrypt one-time-pad encryption and decryption of a string
eval-string compile, then evaluate a string
explode transform a string into a list of characters
find search for an element in a list or string
first get first element in a list (car, head) or string
float translate a string or integer into a floating point number
format format numbers and strings as in the C-language
get-char get a character from a memory address
get-float get a double float from a memory address
get-int   get an integer from a memory address
get-string get a string from a memory address
int translate a string or float into an integer number
join join strings in a list
last returns the last element of a list or string
lower-case convert a string to lower case characters
match search a string for a pattern or match two lists
nth get the nth element in a list or string
nth-set changes the nth element of a list or string
pack pack lisp expressions into a binary structure
parse break a string into tokens
regex Perl Compatible POSIX regular expression search.
replace replace elements in a list or string
rest get all but the first element of a list (cdr, tail) or string
reverse reverse a list or string
select select and permute elements from a list or string
set-nth changes the element in a list or string
slice extracts a substring or sublist.
source return the source to bind a symbol to a string
starts-with checks the start of the string / list against a key string / list
string transform anything into a string
sym translate a string into a symbol
trim trim a string from both sides
unicode convert ASCII/UTF-8 to UCS-4 Unicode
utf8 convert UCS-4 Unicode to convert UTF-8
unpack unpack a binary structure into lisp expressions
upper-case convert a string to uppercase characters

Input/output and file operations

close close a file
command-line    enable or disable interactive command line
current-line retrieve contents of last read-line buffer
device set or inquire current print device
exec launch another program, read from or write to it.
load load / evaluate LISP code from a file
open open a file for reading or writing
print print to the console or a device
println print to the console or a device with line feed
read-buffer read binary data from a file
read-char read a 8-bit character from a file
read-file read a whole file in one operation
read-file read a keyboard key
read-line read a line from the console or file
save save workspace, context or symbol to a file
search searches a file for a string
seek set or read a file position
write-buffer write binary data to a file or string
write-char write a character to a file
write-file write a file in one operation
write-line write a line to the console or a file

Processes, pipes and threads

! shell out to the operating system
exec run a process and read from or write to it.
fork launch a newLISP child process thread
pipe create a pipe for interprocess communication
process launch a child process, remap standard I/O
semaphore create and control semaphores
share share memory with other processes and threads
wait-pid wait for a child process to end

File and directory management

change-dir  change to a different drive and directory
copy-file copy a file
delete-file delete a file
directory return a list of directory entries
file-info get file size, date, time and attributes
make-dir make a new directory
remove-dir remove an empty directory
rename-file rename a file or directory

System functions and predicates

$ access system variables $0 -> $15
atom? check if expression is an atom
array? check if expression is an array
catch evaluate an expression and catch errors
context create or switch to a different name-space
context? check if a context
debug Debug a user-defined function
delete deletes symbols from the symbol table
directory? checks if a disk node is a directory
empty? check if a list or string is empty
env Get or set the operating system's environment.
error-event define an error handler
error-number get the last error number
error-text get the error text for an error number
file? check for existence of a file
float? check if expression is a float
global make a symbol accessible outside MAIN
import import a function from a shared library
integer? check if expression is an integer
lambda? check if a lambda expression
legal? Checks if a string contains a legal symbol
list? check if expression is a list
macro? check if a lambda-macro expression
main-args get command line arguments
NaN? test if NaN float (not a number)
new create a copy of a context
pretty-print change the pretty printing characteristics
primitive? check if expression is a primitive
quote? check if expression is quoted
reset goto top level, release memory
set-locale switch to a different locale
signal set a signal handler
sleep suspend processing for milliseconds
string? check if expression is a string
symbol? check if expression is a symbol
symbols return a list of all symbols in the system
sys-error reports OS system error numbers
sys-info gives information about system resources
throw make a previous catch return
throw-error throw a user defined error
timer starts a one-shot timer firing an event
trace set or inquire trace mode
trace-highlight set highlighting strings in trace

HTTP networking API

base64-enc Encode a string to BASE64 format
base64-dec Decode a string from BASE64 format
get-url read a file or page from the web
post-url post info to an URL address.
put-url upload a page to an URL address.
xml-error return last XML parse error
xml-parse parse a XML document
xml-type-tags  show or modify XML type tags

Socket TCP/IP and UDP network API

net-accept accepts a new incoming connection
net-close closes a socket connection
net-connect connects to a remote host
net-error returns the last error
net-listen listens for connections to a local socket
net-local local IP and port number for a connection
net-lookup the name for an IP-number
net-peer remote IP and port for a net-connect
net-peek number of characters ready to read
net-receive reads data on a socket connection
net-receive-from  reads a UDP datagram on an open connection
net-receive-udp reads a UDP datagram on and closes connection
net-select checks a socket or list of sockets for status
net-send sends data on a socket connection
net-send-to sends a UDP datagram on an open connection
net-send-udp sends a UDP datagram and closes connection
net-service translates a service name to a port number
net-sessions returns a list of currently open connections

Importing libraries

address get the memory address of a number of string
flt converts a number to a 32 bit integer representing a float
float translate a string or integer into a floating point number
get-char get a character from a memory address
get-float get a double float from a memory address
get-int   get an integer from a memory address
get-string get a string from a memory address
import import a function from a shared library
int translate a string or float into an integer number
pack pack lisp expressions into a binary structure
unpack unpack a binary structure into lisp expressions

newLISP internals API

cpymem direct memory access
dump show binary address and contents of newLISP cells



Functions in alphabetical order

!

syntax: (! str-command)

Shells out to the operating system and executes a command in str-command at the operating systems shell level. Depending on the operating system, this function returns different values.

example:
(! "vi")  
(! "ls -ltr")

See also exec for executing a shell command and capturing the standard output or feeding standard input, and see process for launching a non-blocking child process and redirecting std I/O to pipes.

Note that ! can be also be used as a command line shell operator without the parenthesis and omitting the space after the !:

example:
!ls -ltr    ; executed in the newLISP shell window

The ! operator used in this way is not a newLISP function, but rather a special feature of the newLISP command shell.



$

syntax: ($ int-idx)

All functions using regular expressions like find, parse, regex, search and replace return expressions or subexpressions found in the predefined system variables $0, $1, $2 ... $15, after or during the execution of the function. nth-set and set-nth store the replaced expression in $0. System variables can be used just like any other symbol. As an alternative the contents of these variables can also be accessed by using ($ 0), ($ 1), ($ 2) ... etc. This method allows indexed access, i.e: ($ i), where i is an integer.

example:
(set 'str  "http://newlisp.org:80")
(find "http://(.*):(.*)" str 0)   => 0

$0                                => "http://newlisp.org:80"
$1                                => "newlisp.org"
$2                                => "80"

($ 0)                             => "http://newlisp.org:80"
($ 1)                             => "newlisp.org"
($ 2)                             => "80"

(set-nth 2 '(a b c d e f g) 'x)   => (a b x d e f g)

$0                                => c
($ 0)                             => c

System variables are accessible when doing substitutions with nth-set, set-nth or replace:

(set-nth 3 '(1 2 3 4) (* $0 3))  => (1 2 3 12)


+, -, *, / ,%

syntax: (+ int-1 [int-2 ... ])

Returns the sum of all evaluations of int-1 ... .

syntax: (- int-1 [int-2 ... ])

Evaluates int-1 ... and subtracts each consecutive evaluated result from the previous one. If only one argument is given, its sign is reversed.

syntax: (* int-1 [int-2 ... ])

Expressions are evaluated from left to right and the product is calculated.

syntax: (/ int-1 [int-2 ... ])

Expressions are evaluated. Each result is divided successively until the end of the list is reached. Division by zero causes an error.

syntax: (% int-1 [int-2 ... ])

Expressions are evaluated. Each result is divided successively by the next int and the rest (modulo operation) is returned. Division by zero causes an error.

example:
(+ 1 2 3 4 5)           => 15
(+ 1 2 (- 5 2) 8)       => 14
(- 10 3 2 1)            => 4
(- (* 3 4) 6 1 2)       => 3
(- 123)                 => -123
(map - '(10 20 30))     => (-10 -20 -30)
(* 1 2 3)               => 6
(* 10 (- 8 2))          => 60
(/ 12 3)                => 4
(/ 120 3 20 2)          => 1
(% 10 3)                => 1
(+ 1.2 3.9)             => 4

Floating point values in arguments of +,-,* and / are truncated to their floor value.

Floating point values bigger than the maximum or minimum integer values 2147483647 or -2147483648 are truncated to those values.

Calculations which result in values bigger than 2,147,483,647 or smaller than -2,147,483,648 wraps around from positive to negative or negative to positive numbers.

Floating point values which evaluate to NaN (Not a Number), +INF or -INF are treated as 0 (zero).



<, >, =, <=, >=, !=

syntax: (< exp-1 exp-2 [exp-3 ... ])
syntax: (> exp-1 exp-2 [exp-3 ... ])
syntax: (= exp-1 exp-2 [exp-3 ... ])
syntax: (<= exp-1 exp-2 [exp-3 ... ])
syntax: (>= exp-1 exp-2 [exp-3 ... ])
syntax: (!= exp-1 exp-2 [exp-3 ... ])

Expressions are evaluated and the results are compared successively. As long as comparisons conform to the comparison operator, evaluation and comparison continue until all arguments are tested and true is returned. As soon as one comparison fails, nil is returned.

All types of expressions may be compared: atoms, numbers, symbols, and strings, as well as list expressions. In case that list expressions are compared, list elements are compared recursively.

When comparing lists, elements at the beginning of the list are considered more significant than elements following (in a similar fashion to characters in strings compared). When comparing lists of different length but equal elements, the longer list is considered greater (see examples).

When mixed type expressions are compared, their types are compared in the following order low to high. Floats and integers numbers are compared as numbers not as types.

  Atoms: nil, true, integer or float, string, symbol, primitive
  Lists: quoted list/expression, list/expression, lambda , lambda-macro

example:
(< 3 5 8 9)                      => true
(> 4 2 3 6)                      => nil
(< "a" "c" "d")                  => true
(>= duba aba)                    => true
(< '(3 4) '(1 5))                => nil
(> '(1 2 3) '(1 2))              => true
(= '(5 7 8) '(5 7 8))            => true
(!= 1 4 3 7 3)                   => true
(< 1.2 6 "Hello" 'any '(1 2 3))  => true
(< nil true)                     => true
(< '(((a b))) '(((b c))))        => true
(< '((a (b c)) '(a (b d)) '(a (b (d)))))  => true


<<, >>

syntax: (<< int-1 int-2 [int-3 ...])
syntax: (>> int-1 int-2 [int-3 ...])

The number int-1 is arithmetically shifted to the left or right by the number of bits given by int-2 and then shifted by int-3 and so on. Integers up to 32 bits may be shifted up to 31 positions. When shifting right, the most significant bit is duplicated:

( >> 0x80000000 1) => 0xC0000000   ; not 0x04000000 !

example:
(<< 1 3)                => 8
(<< 1 2 1)              => 8
(>> 1024 10)            => 1
(>> 160 2 2)            => 10


&

syntax: (& int-1 int-2 [int-3 ...])

A bitwise and operation is performed on the number in int-1 with the number in int-2 and then successively with int-3 etc.

example:
(& 0xAABB 0x000F)        => 11  ; which is 0xB


|

syntax: (| int-1 int-2 [int-3 ...])

A bitwise or operation is performed on the number in int-1 with the number in int-2 and then successively with int-3 etc.

example:
(| 0x10 0x80 2 1)       => 147


^

syntax: (^int-1 int-2 [int-3 ...])

A bitwise xor operation is performed on the number in int-1 with the number in int-2 and then successively with int-3 etc.

example:
(^ 0xAA 0x55)        => 255


~

syntax: (~ int)

A bitwise not operation on the number in int is performed reversing all bits.

example:
(format "%X" (~ 0xFFFFFFAA))    => "55"
(~ 0xFFFFFFFF)                  => 0


abs

syntax: (abs num)

Returns the absolute value of a number in num.

example:
(abs -3.5)      => 3.5


acos

syntax: (acos num)

The arc-cosine function is calculated from the number in num.

example:
(acos 1)      => 0


add

syntax: (add num-1 [num-2 ... ])

All the numbers num-1, num-2, are summed. add accepts float or int operands but always returns floating point numbers. Any floating-point calculation with NaN also returns NaN.

example:
(add 2 3.25 9)          => 14.25
(add 1 2 3 4 5)         => 15


address

syntax: (address int)
syntax: (address float)
syntax: (address str)

Returns the memory address of an integer in int, double floating point number in float or string in str. This function is used when passing parameters to library functions imported using import.

example:
(set 's "\001\002\003\004")

(get-char (+ (address s) 3)) => 4

(get-int (address 1234)) => 1234

(get-float (address 1.234))  => 1.234

Passing strings will pass their address automatically, but as the example shows address can be used in this case to do pointer arithmetic on the string address.

See also the functions get-char, get-int and get-float.



amb

syntax: (amb exp-1 exp-2 [exp-3...])

On of the expressions exp-1 ... n is selected at random and the evaluation result is returned.

example:
(amb 'a 'b 'c 'd 'e) => one of a, b, c, d or e at random

(dotimes (x 10) (print (amb 3 5 7))) => 35777535755

Internally newLISP uses the same function as rand to pick a random number. See also random and normal for random floating point number generation and seed to initialize the internal pseudo random generating process at a specific starting point.



and

syntax: (and exp-1 exp-2 [exp-3...])

The expressions exp-1, exp-2, ... are evaluated in turn. If some expression yields nil, nil is returned without further evaluation; otherwise the result of the last expression is returned.

example:
(set 'x 10)                       => 10
(and (< x 100) (> x 2))           => true
(and (< x 100) (> x 2) "passed")  => "passed"
(and '())                         => nil
(and true)                        => true
(and)                             => nil


append

syntax: (append list-1 list-2 [list-3 ....])
syntax: (append str-1 [str-2 ...])

In the first form append works on lists and all list-n ... are appended to form a new lisp. The original lists are unchanged.

example:
(append '(1 2 3) '(4 5 6) '(a b))   => (1 2 3 4 5 6 a b)

(set 'aList '("hello" "world"))     => ("hello" "world")

(append aList '("here" "I am"))     

=> ("hello" "world" "here" "I am")

In the second form append works on strings. The strings in str-1 ... are concatenated into a new string and returned.

example:
(set 'more " how are you")      => " how are you"

(append "Hello " "world," more) 

=> "Hello world, how are you"

See also join for specifying linkage characters or strings. See string for converting to strings and appending in one step.

See also a special syntax of write-buffer when appending in place to an existing string.



apply

syntax: (apply func list [int-reduce])

Applies the primitive, defined function or lambda expression contained in func to the arguments in list.

example:
(apply + '(1 2 3 4))                    => 10
(set 'aList '(3 4 5))                   => (3 4 5)
(apply * aList)                         => 60
(apply sqrt '(25))                      => 5
(apply (lambda (x y) (* x y)) '(3 4))   => 12

Optionally a int-reduce parameter can contain the number of arguments the function in func is taking. In this case func will be repeatedly applied using the previous result as the first argument and taking the other arguments required successively from list and in left-associative order. For example if op takes two arguments then:

(apply op '(1 2 3 4 5) 2)

;; is equivalent to

(op (op (op (op 1 2) 3) 4) 5)

;; find the greatest common divisor 
;; or two or more integers

(define (gcd_ a b)
(let (r (% b a))
    (if (= r 0) a (gcd_ r a))))

(define-macro (gcd)
    (apply gcd_ (args) 2))

(gcd 12 18 6)      => 6
(gcd 12 18 6 4)    => 2

The last example shows, how the reduce functionality of apply can be used to convert a two-argument function to take multiple arguments.



args

syntax: (args)
syntax: (args int-idx)

Accesses a list of all unbound arguments, passed to the current evaluating define or define-macro lambda or lambda-macro expression. Only arguments which are not taken by local variables of the current function or macro are accessed. args is useful when defining functions or macros with a variable number of arguments.

example:
(define-macro (print-line)
    (dolist (x (args))
        (print x "\n")))
                        
(print-line "hello" "World")

This prints a line feed after each element. This macro mimics the effect of the built-in function println.

In the second syntax args can take an index in int-idx.

example:
(define-macro (foo)
  (println (args 2) (args 1) (args 0)))

(foo x y z) 

zyx 

The function foo prints out the arguments in reverse order.

Note that (args) only contains the arguments not bound by local variables of the current function or macro:

example:
(define (foo a b) (args))
  
(foo 1 2)          => ()

(foo 1 2 3 4 5)    => (3 4 5)

In the first example an empty list () is returned because the two arguments are bound to the two local symbols a and b. In the second example three arguments are left over and returned by args.

(args) can be used as an argument to another built-in or user defined function call, but should not be used as an argument to another macro, where (args) would not be evaluated and have a different contents int the new macro environment.



array

syntax: (array int-n [int-n2 ... int-n16] [list-init])

Creates an array with int-n elements and optionally initializes it to the contents in list-init. Up to 16 dimensions may be specified for multidimensional arrays.

Internally newLISP builds multidimensional arrays by putting arrays into elements of arrays.

example:
(array 5)                  => (nil nil nil nil nil)

(array 5 (sequence 1  5))  => (1 2 3 4 5)

(array 10 '(1 2))          => (1 2 1 2 1 2 1 2 1 2)

Arrays can be initialized with objects of any type. If not enough initializers are found in the list than the list is repeated until all elements of the array are initialized.


(set 'myarray (array 3 4 (sequence 1 12)))

=> ((1 2 3 4) (5 6 7 8) (9 10 11 12))

Arrays are modified and accessed using the usual functions for lists:

(set-nth 2 3 myarray 99)        

=> ((1 2 3 4) (5 6 7 8) (9 10 11 99))


(nth-set 1 1 myarray "hello")   => 6


myarray                         

=> ((1 2 3 4) (5 "hello" 7 8) (9 10 11 99))


(set-nth 1 myarray (array 4 '(a b c d)))

=> ((1 2 3 4) (a b c d) (9 10 11 99))


(nth 1 myarray)      => (a b c d) ; access a whole row

(nth 0 -1 myarray)   => 4

When replacing a whole row care must be taken to replace it as an array.

array-list can be used to convert arrays back to lists:

(array-list myarray) => ((1 2 3 4) (a b c d) (1 2 3 99))

To convert a list back to an array apply flat to the list:

(set 'aList '((1 2) (3 4)))             => ((1 2) (3 4))

(set 'aArray (array 2 2 (flat aList)))  => ((1 2) (3 4))

The function array? can be used to check if an expression is an array:

(array? myarray)                => true

(array? (array-list myarray))   => nil

When serializing arrays using the source or save function, arrays are shown with the array statement necessary to create them. This way variables containing arrays are correctly serialized when saving with save or creating source strings using source.

(set 'myarray (array 3 4 (sequence 1 12)))

(save "array.lsp" 'myarray)

;; contents of file arraylsp ;;

(set 'myarray (array 3 4 (flat '(
  (1 2 3 4) 
  (5 6 7 8) 
  (9 10 11 12)))))

;;


array-list

syntax: (array-list array)

Returns a list conversion from array leaving the original array unchanged:

example:
(set 'myarray (array 3 4 (sequence 1 12)))

=> ((1 2 3 4) (5 6 7 8) (9 10 11 12))


(array-list myarray)            

=> ((1 2 3 4) (5 6 7 8) (9 10 11 12))


array?

syntax: (array? expr)

Checks if expr is an array:

example:
(set 'M (array 3 4 (sequence 1 4)))   

=> ((1 2 3 4) (1 2 3 4) (1 2 3 4)))


(array? M)                 => true

(array? (array-list M))    => nil


asin

syntax: (asin num)

The arcsine function is calculated from the number in num and the result is returned.

example:
(asin 1)        => 1.570796327


assoc

syntax: (assoc exp-key list-alist)

The value of exp-key is used as a key to search list-alist for a member-list whose first element is the key value. The member-list found is returned; if none is found, nil is returned.

example:
(assoc 1 '((3 4) (1 2)))                => (1 2)
(set 'data '((apples 123) (bananas 123 45) (pears 7)))
(assoc 'bananas data)                   => (bananas 123 45)
(assoc 'oranges data)                   => nil

See also replace-assoc for making replacements in association lists and lookup for an association lookup and extraction of an element in one step.



atan

syntax: (atan num)

The arctangent function of num is calculated an returned.

example:
(atan 1)        => 0.7853981634


atan2

syntax: (atan2 num-Y num-X)

The atan2 function computes the principal value of the arctangent of Y / X in radians, using the signs of both arguments to determine the quadrant of the return value. atan2 is useful for converting Cartesian coordinates to polar coordinates.

example:
(atan2 1 1)                       => 0.7853981634
(div (acos 0) (atan2 1 1))        => 2
(atan2 0 -1)                      => 3.141592654
(= (atan2 1 2) (atan (div 1 2)))  => true


atom?

syntax: (atom? exp)

Returns true if the value of exp is an atom and nil otherwise. An expression is an atom if it evaluates to nil, true, an integer, a float, a string, a symbol or a primitive. Lists and lambda or lambda-macro expressions are not atoms.

example:
(atom? '(1 2 3))     => nil
(and (atom? 123)
     (atom? "hello")
     (atom? 'foo))   => true
(atom? ''foo)        => nil


base64-dec

syntax: (base64-dec str)

The BASE64 string in str is decoded. Note that str is not checked to be a valid BASE64 string. The decoded string is returned.

example:
(base64-dec "SGVsbG8gV29ybGQ=")  => "Hello World"

See also base64-enc for encoding.



base64-enc

syntax: (base64-enc str)

The string in str is encoded into BASE64 format. This format encodes groups of 3*8=24 input bits into 4*8=32 output bits where each 8 bit output group represents 6 bits from the input string. The 6 bits are encoded into 64 possibilities from the letters A to Z, a to z, numbers 0 to 9 and the characters + and /. The = character is used as a filler in unused 3-to-4 byte translations. The function is useful to convert binary content into printable characters.

The encoded string is returned

BASE64 encoding is used with many Internet protocols to encode binary data for inclusion in text based messages, i.e. XML-RPC.

example:
(base64-enc "Hello World")   => "SGVsbG8gV29ybGQ="

Note, that base64-enc does not insert carriage-return/linefeed pairs in longer BASE64 sequences, but returns a pure BASE64 encoded string.

See also base64-dec for decoding.



begin

syntax: (begin body)

The begin form is used to group a block of expressions. The expressions in body are evaluated. The value of the last expression of body is returned.

example:
(begin
  (print "This is a block of 2 expressions\n")
  (print "================================"))

Some built-in functions like cond, define, dolist, dotimes and while already allow multiple expressions in their body sections, but begin is often used in if.

See also silent, which works like begin but suppresses console output on return.



beta

syntax: (beta cum-a, num-b)

The Beta beta function is derived from the log Gamma gammaln function as follows:

beta = exp(gammaln(a) + gammaln(b) - gammaln(a + b))
example:
(beta 1 2)    => 0.5


betai

syntax: (betai num-x, num-a, num-b)

The Incomplete Beta function betai equals the cumulative probability of the Beta distribution betai at x in num-x. The cumulative binomial distribution is defined as the probability of an event pev with probability p to occur k or more times in N trials:

pev = Betai(p, k, N - k + 1)
example:
(betai 0.5 3 8)    => 0.9453125

;; probability of F ratio for df1/df2
;;
(define (f-prob f df1 df2)
  (let (prob (mul 2 (betai (div df2 (add df2 (mul df1 f))) 
                           (mul 0.5 df2) 
                           (mul 0.5 df1)))) 
    (div (if (> prob 1) (sub 2 prob) prob) 2)))

The first example calculates the probability for an event with a probability of 0.5 to occur 3 or more times in 10 trials (8 = 10 - 3 + 1). The incomplete Beta distribution can be used to derive a variety of other functions in mathematics and statistics. The second example calculates the one-tailed probability of a variance F ratio. In similar fashion students t could be calculated using betai. See also the binomial function.



binomial

syntax: (binomial int-n, int-k, float-p)

The binomial distribution function is defined as the probability for an event to occur int-k times in int-n trials if that event has a probability of float-p and all trials are independent from each other:

binomial = n! / (k! * (n - k)!) * pow(p, k) * pow(1.0 - p, n - k)

Where x! is the factorial of x and pow(x, y) is x raised to the power of y.


example:
(binomial 10 3 0.5)    => 0.1171875

The example calculates the probability for an event with a probability of 0.5 to occur 3 times in 10 trials. For a cumulated distribution see the betai function



case

syntax: (case exp-switch (exp-1 body-1) [ (exp-2 body-2) ...] )

The result of evaluating exp-switch is compared to each of the unevaluated expressions exp-1, exp-2, ... . If a match is found, the corresponding expressions in body are evaluated. The result of the last match is returned as the result for the whole case expression.

example:
(define (translate n)
  (case n
    (1 "one")
    (2 "two")          
    (3 "three")
    (4 "four")
    (true "Can't translate this")))
(translate 3)    => "three"
(translate 10)   => "Can't translate this"

The last body in this example is evaluated if no match can be found.



catch

syntax: (catch exp)
syntax: (catch exp symbol )

In the first syntax catch will return the result of the evaluation of exp or the argument of a throw executed during the evaluation of exp:

example:
(catch (dotimes (x 1000) 
	(if (= x 500) (throw x)))) => 500

This form is useful for breaking out of iteration loops or to force an early return from a function or expression block:

(define (foo x)
	...
	(if condition (throw 123))
        ...
	456)

; if condition is true

(catch (foo p))  => 123

; if condition is not true

(catch (foo p))  => 456

In the second syntax catch evaluates the expression exp, stores the result in symbol, and returns true. If an error occurs during evaluation, catch returns nil and stores the error message in symbol. This form is useful when errors can be expected as a normal potential outcome of a function and are dealt with during program execution.

example:
(catch (func 3 4) 'result) => nil
result = "Invalid function in function catch"

(constant 'func +)         => add <4068A6>
(catch (func 3 4) 'result) => true
result                     => 7

See also the function eval-string, which can also be used to catch errors, when evaluating from strings.

When a throw is executed during the evaluation of expr catch will return true and the throw argument will be stored in symbol:

(catch (dotimes (x 100) 
         (if (= x 50) (throw "fin")) 'result) => true

result   => "fin"

Like the first syntax of catch, the second can be used for early return from functions or for breaking out of iteration loops, but additionally errors can be caught. See also throw-error for throwing user defined errors.



ceil

syntax: (ceil number )

Returns the next higher integer to number as a floating point number.

example:

(ceil -1.5)  => -1
(ceil 3.4)   => 4

See also the function floor.



change-dir

syntax: (change-dir str-path)

Makes the current directory the one given in str-path. Returns true on success and nil otherwise.

example:
(change-dir "/etc")

Makes /etc the current directory.



char

syntax: (char str [int-index] )
syntax: (char int)

Given a string argument, extracts from str the character at index int-index and returns the ASCII value of that character. If int-index is omitted, 0 (zero) is assumed.

See also Indexing elements of strings and lists.

Given an integer argument, char returns a string containing the ASCII character with value int.

example:
(char "ABC")    => 65  ; ASCII code for "A"
(char "ABC" 1)  => 66  ; ASCII code for "B"
(char "ABC" -1) => 67  ; ASCII code for "C"
(char "B")      => 66  ; ASCII code for "B"

(char 65)       => "A"
(char 66)       => "B"

(char (char 65))=> 65    ; two inverse applications

(map char (sequence 1 255)) ; current character set



chop

syntax: (chop str [int-chars] )
syntax: (chop list [int-elements] )

If the first argument evaluates to a string, chop returns a copy of str with the last int-char characters omitted. If the int-char argument is absent, one character is omitted. chop does not alter str.

If the first argument evaluates to a list, a copy of the list is returned with int-elements omitted in like manner as for strings.

example:
(set 'str "newLISP")   => "newLISP"

(chop str)             => "newLIS"
(chop str 2)           => "newLI"

str                    => "newLISP"

(set 'lst '(a b (c d) e))

(chop lst)             => (a b (c d))
(chop lst 2)           => (a b)

lst                    => (a b (c d) e)


close

syntax: (close int-file)

Closes a file specified by a file handle in int-file. The file handle was obtained in a previous open operation. close returns true on success and nil otherwise.

example:
(close (device))    => true
(close 7)           => true
(close aHandle)     => true

Note that using close on device automatically resets it to 0 (zero, the screen device).




command-line

syntax: (command-line [bool])

Enables or disables the interactive command-line mode in the console window. When bool evaluates to nil the command line is switched off. When bool evaluates to anything other than nil, command-line mode is switched on. Reset or any error condition also switches command-line mode on.

example:
(command-line nil)

On Linux/UNIX this will also disable the Ctrl-C handler.



cond

syntax: (cond (exp-condition-1 body-1) [(exp-condition-2 body-2).. ]

Similar to if, the evaluation of a body expression using cond The exp-condition expressions are evaluated in turn until some exp-condition-i is found that evaluates to anything other than nil or the empty list (). Then the result of evaluating body-i is returned as the result of the whole cond-expression. If all conditions evaluate to nil or an empty list (), cond returns the value of the last cond-expression.

example:
(define (classify x)
    (cond
        ( (< x 0) "negative")
        ( (< x 10) "small")
        ( (< x 20) "medium")
        ( (>= x 30) "big")))

(classify 15)    => "medium"
(classify 22)    => "nil"
(classify 100)   => "big"
(classify -10)   => "negative"

When a body_n is missing, the value of the last cond-expression evaluated is returned. If no condition evaluates to true the value of the last conditional expression is returned, that is, nil or the empty list ().

(cond ((+ 3 4)))     => 7

See also if with multiple arguments, which behaves like a cond but with less parenthesis clutter.



cons

syntax: (cons exp-1 exp-2)

If exp-2 evaluates to a list, then a list is returned with the result of evaluating exp-1 inserted as the first element. If exp-2 evaluates to anything else than a list, a list is returned, containing two elements from evaluating exp-1 and exp-2. Note that there is no dotted pair in newLISP: consing two atoms constructs a list.

example:
(cons 'a 'b)            => (a b)
(cons 'a '(b c))        => (a b c)
(cons (+ 3 4) (* 5 5))  => (7 25)
(cons '(1 2) '(3 4))    => ((1 2) 3 4)
(cons nil 1)            => (nil 1)
(cons 1 nil)            => (1 nil)
(cons 1)                => (1)
(cons)			=> ()

In newLISP (cons 's nil) results in (s nil), not (s) as in other LISPs. newLISP treats nil as a Boolean value, not as an equivalent to the empty list ().

cons behaves like the inverse operation to first and rest, or like the inverse operation of first and last if the list is a pair:

(cons (first '(a b c)) (rest '(a b c))) => (a b c)

(cons (first '(x y)) (last '(x y)))     => (x y)


constant

syntax: (constant sym-1 exp-1[sym-2 exp-2])

Works exactly like set but protects the symbol from subsequent modification. A symbol set with constant can only be modified again using constant. When trying to modify the contents of a symbol set with constant an error message is generated by newLISP. Only symbols from the current context can be used with constant. This prevents constant from overwriting symbols, which have been protected in their home context.

Symbols can also be protected using constant after being initialized with set, define or define-macro:

(constant 'aVar 123)	=> 123
(set 'aVar 999) 
    => error: symbol is protected in function set: aVar

(define (double x) (+ x x))

(constant 'double)

The first example defines a constant aVar, which can only be changed by another constant statement. The second example protects double from being changed, except by another constant statement.

The last value to be assigned can be omitted. constant returns the contents of the last symbol set and protected.

Built-in functions can be assigned to symbols or to the names of other built-in functions, effectively redefining them as different functions. There is no performance loss when renaming functions.

(constant 'squareroot sqrt)  => sqrt <406C2E>
(constant '+ add)            => add <4068A6>

squareroot will behave like sqrt. + is redefined to use the mixed type floating point mode of add. The hexadecimal number displayed in the result is the binary address of the built-in function and is different on different platforms and OSs.



context

syntax: (context [sym])
syntax: (context [context])

If a quoted symbol is given as sym, this function switches to the context sym for subsequent translation of newLISP source. If the context does not exist, it is created. If the context already exists, the symbol can be given unquoted. When no parameter is specified in sym or context, then the symbol for the current context is returned. Symbols for contexts are protected from change.

example:
(context 'GRAPH)              ; create / switch context GRAPH

(define (foo-draw x y z)      ; function resides in GRAPH
        ( .... ))
                                
(set 'var 12345)
(symbols) => (foo-draw var)   ; GRAPH has now 2 symbols

(context 'MAIN)               ; switch back to MAIN

(print GRAPH:var) => 12345    ; contents of symbol in GRAPH

(GRAPH:foo-draw 10 20 30)     ; executes function in GRAPH
(set 'GRAPH:var 6789)         ; assign to a symbol in GRAPH

If a context symbol is referred to before the context exists, the context will be created implicitly.

(set 'person:age 0)          ; no need to create context first
(set 'person:address "")     ; useful for quickly defining
                             ; data structures

Contexts can be copied:

(new person 'JohnDoe)    =>  JohnDoe

(set 'JohnDoe:age 99)

Contexts can be referred to by a variable:

(set 'human JohnDoe)

human:age                => 99

(set 'human:address "1 Main Street")

JohnDoe:address          => "1 Main Street"

An evaluated context (no quote) can be given as an argument:

(set 'old MAIN)
(context FOO)       ; will switch to FOO (note unquoted FOO)  
(context old)       ; will switch back to MAIN

If an identifier with the same symbol already exists, it is redefined to be a context.

Symbols within the current context are referred to simply by their names as are built-in functions and special symbols like nil and true. Symbols outside the current context are referenced by prefixing the symbol name with the context name and a colon :. To quote a symbol in a different context, put the quote mark before the context name.

Within a given context, symbols may be created with the same name as built-in functions or context symbols in MAIN, thereby overriding the symbols in MAIN when prefixing them with the current context:

(context 'CTX)
(define (CTX:new var)
    ...
    )
    
(context 'MAIN)

CTX:new will overwrite new in MAIN.



context?

syntax: (context? exp)

context? is a predicate which returns true only if exp names a context and nil otherwise.

example:
(context? MAIN)      => true
(set 'x 123)
(context? x)         => nil

(set 'FOO:q "hola")  => "hola"
(set 'ctx FOO)
(context? ctx)       => true  ; ctx contains context foo


copy-file

syntax: (copy-file str-from-name str-to-name)

Copies a file from a path-file-name given in str-from-name to a path-file-name given in str-to-name. Returns true or nil depending on a successful copy.

example:
(copy-file "/home/me/newlisp/data.lsp" "/tmp/data.lsp")


cos

syntax: (cos num)

The cosine function is calculated from num and the result is from the result.

example:
(cos 1)                          => 0.5403023059
(set 'pi (mul 2 (acos 0)))       => 3.141592654
(cos pi)                         => -1


count

syntax: (count list-1 list-2)

Counts elements of list-1 in list-2 and returns a list of those counts.

example:
(count '(1 2 3) '(3 2 1 4 2 3 1 1 2 2)) => (3 4 2)
(count '(z a) '(z d z b a z y a)) => (3 2)

(set 'lst (explode (read-file "myFile.txt")))
(set 'letter-counts (count (unique lst) lst))

The second example counts all occurrences of different letters in myFile.txt.



cpymem

syntax: (cpymem int-from-address int-to-address int-bytes)

Copies int-bytes of memory from memory address int-from-address to memory address int-to-address. The function can be used for direct memory writing/reading or for hacking newLISP internals, i.e. protection bits in LISP cells, or other tasks where direct memory access is required.

Note that this function should only be used when familiar with newLISP internals. cpymem can crash the system or make it unstable if not used correctly.

example:
(cpymem (pack "c c" 0 32) (last (dump 'sym)) 2)

(set 's "0123456789")

(cpymem "xxx" (+ (address s) 5) 3)

s              => "01234xxx89")

The first example would remove the protection bit in symbol sym. The second example copies a string directly into a string variable.

See also dump for retrieving binary address and contents from newLISP cells.



crc32

syntax: (crc32 str-data)

Calculates a running 32 bit CRC (Circular Redundancy Check) from the buffer in str-data starting with a CRC of 0xffffffff for the first byte. crc32 uses an algorithm published by www.w3.org.

example:
(crc32 "abcdefghijklmnopqrstuvwxyz")    => 1277644989

crc32 is often used to verify data integrity in unsafe data transmissions.



crit-chi2

syntax: (crit-chi2 num-probability num-df)

Calculates the critical minimum Chi-square for a given confidence probability num-probability and degrees of freedom num-df for testing the significance of a statistical null hypothesis.

example:
(crit-chi2 0.99 4)   => 13.27670443


crit-z

syntax: (crit-z num-probability)

Calculates the critical normal distributed Z value for a given cumulated probability num-probability for testing of statistical significance and confidence intervals.

example:
(crit-z 0.999)   => 3.090232372


current-line

syntax: (current-line)

Retrieves the contents of the last read-line operation. The contents of current-line is also implicitly used when using write-line without a string parameter.

example:
(set 'inFile (open "/usr/share/newlisp/init.lsp" "read"))
(while (read-line inFile) 
        (if (starts-with (current-line) ";;")
                (write-line)))

This displays all lines in file INIT.LSP starting with ;;.



date

syntax: (date)
syntax: (date int-secs [int-offset])
syntax: (date int-secs int-offset str-format)

The first syntax returns the date/time string representation for the local time zone of the current time.

In the second syntax date translates the number of seconds in int-secs into its date/time string representation for the local time zone. The number in int-secs is usually retrieved from the system using date-value. Optionally a timezone offset can be specified in int-offset in minutes, which is added or subtracted before conversion of int-sec to a string.

example:
(date)                          => "Fri Oct 29 09:56:58 2004"

(date (date-value))             => "Fri Oct 29 09:56:58 2004" 
(date 0)                        => "Wed Dec 31 16:00:00 1969"

Note that on some Win32 compiled versions values, which result in dates earlier than 1970 January, 1st 00:00:00 return nil. The MinGW compiled version will also work with values resulting in dates up to 24 hours less than 1970-1-1 and return a date time string for 1969-12-31.

The way the date and time are presented in a string depends on the underlying operating system. The second example would show 1-1-1970 0:0 when in the Greenwich time zone, but shows a time lag of 8 hours when in California. date assumes the int-secs given in Universal Coordinated Time UCT (formerly GMT) and converts adjusting to the local timezone.

The third syntax allows the date string to be fully customized with translation of day and month names to the current locale using a format specified in str-format:

example:
(set-locale "german") => "de_DE"      

(date (date-value) 0 "%A %-d. %B %Y")
=> "Montag  7. März 2005" 
; on Linux - suppresses the leading 0

(set-locale "C") ; default POSIX

(date (date-value) 0 "%A %B %d %Y")
=> "Monday March 07 2005" ;

(date (date-value) 0 "%a %#d %b %Y")
=> "Mon 7 Mar 2005" 
; suppressing leading 0 on Win32 using #

(set-locale "german")

(date (date-value) 0 "%x")
=> "07.03.2005"            ; day month year

(set-locale "C")

(date (date-value) 0 "%x")

=> "03/07/05"              ; month day year

The following table summarizes all format specifiers available on both, Win32 and Linux/UNIX platforms. More format options are available on Linux/UNIX. For details consult the documentation of the 'C' function strftime() in the individual platform's C-library.


formatdescription
%aabbreviated weekday name according to the current locale
%Afull weekday name according to the current locale
%babbreviated month name according to the current locale
%Bfull month name according to the current locale
%cpreferred date and time representation for the current locale
%dday of the month as a decimal number (range 01 to 31)
%Hhour as a decimal number using a 24-hour clock (range 00 to 23)
%Ihour as a decimal number using a 12-hour clock (range 01 to 12)
%jday of the year as a decimal number (range 001 to 366)
%mmonth as a decimal number (range 01 to 12)
%Mminute as a decimal number
%peither 'am' or 'pm' according to the given time value, or the corresponding strings for the current locale
%Ssecond as a decimal number 0 to 61 (60 and 61 to account for occasional leap seconds)
%Uweek number of the current year as a decimal number, starting with the first Sunday as ;the first day of the first week
%wday of the week as a decimal, Sunday being 0
%Wweek number of the current year as a decimal number, starting with the first Monday as the first day of the first week
%xpreferred date representation for the current locale without the time
%Xpreferred time representation for the current locale without the date
%yyear as a decimal number without a century (range 00 to 99)
%Yyear as a decimal number including the century
%ztime zone or name or abbreviation, same as %Z on Win32, different on Linux/UNIX
%Ztime zone or name or abbreviation, same as %z on Win32, different on Linux/UNIX
%%a literal '%' character

Leading zeros in the display of decimal numbers can be suppressed using - on Linux/UNIX and using # on Win32.

See also date-value, time-of-day, time and now.



date-value

syntax: (date-value int-year int-month int-day [int-hour int-min int-sec])
syntax: (date-value)

In the first syntax date-value returns the time in seconds since 1970-1-1 00:00:00 for a given date and time. The parameters for hour, minute and second are optional. The time is assumed to be Universal Time (UT), not adjusted for the current time zone.

In the second syntax date-value returns the time value in seconds for the current time.

example:
(date-value 2002 2 28)          => 1014854400
(date-value 1970 1 1 0 0 0)     => 0
(date (apply date-value (now))) => "Fri Oct 29 09:56:58 2004" 

(date (date-value))             => "Fri Oct 29 09:56:58 2004"

the following function can be used to to transform a date-value back to a list:

(define (value-date val)
    (append
       (slice (now (+ (/ (date-value) -60) (/ val 60))) 0 5)
       (list (% val 60)))) 

(value-date 1014854400)         => (2002 2 28 0 0 0)

See also date, time-of-day, time and now.



debug

syntax: (debug func)

Does trace and starts evaluating the user defined function in func. debug is a shortcut for executing (trace true) and then entering the function to be debugged.

example:
;; instead of doing
(trace true)
(my-func a b c)
(trace nil)

;; use debug as a shortcut
(debug (my-func a b c))

See also trace.



dec

syntax: (dec sym [num])

The number in sym is decremented by 1 or by the optional number num and returned. dec performs mixed int and float arithmetic according to the following rules:

If num is absent inc always returns an integer in sym. If the input arguments are floats and num is absent, the input arguments are truncated to integers.

Integer calculations (without num) which result in numbers greater than 2147483647 wrap around to negative numbers. Results smaller than -2147483648 wrap around to positive numbers.

If num is supplied, dec always returns the result as floating point even for integer input arguments.

example:
(set 'x 10)             => 10
(dec 'x)                => 9
x                       => 9
(dec 'x 0.25)           => 8.75
x                       => 8.75

See also inc for incrementing.



define

syntax: (define (sym-name [sym-param-1 ...]) [body-1 ...])
syntax: (define sym-name exp )

Defines a new function sym-name with optional parameters sym-param-1 .... define is equivalent to assigning a lambda expression to sym-name. When calling a defined function, all arguments are evaluated and assigned to the variables in sym-param-1 ..., then the body-1 ... expression(s) are evaluated. When defining a function, the result lambda expression, contained in sym-name, is returned.

All parameters defined are optional. When calling a defined function without supplying parameters, those parameters assume the value nil.

The return value of define> is the assigned lambda expression. When calling a user defined function, it's return value is the last expression evaluated in the function body.

example:
(define (area x y) (* x y))     => (lambda (x y) (* x y))
(area 2 3)                      => 6

As an alternative, area could be defined as a function without using define.

(set 'area (lambda (x y) (* x y))

lambda or fn expressions may be used by itself as an anonymous function without being defined into a symbol:

((lambda ( x y) (* x y)) 2 3)    => 6
((fn ( x y) (* x y)) 2 3)        => 6

fn is just a shorter form of writing lambda.

The second version of define works similar to a set.

example:
(define x 123)  =>   123
; is equivalent to
(set 'x 123)   =>   123

(define area (lambda ( x y) (* x y)))
; is equivalent to
(set 'area (lambda ( x y) (* x y)))
; is equivalent to
(define (area x y) (* x y))

Trying to redefine ant protected symbol will cause an error message.



define-macro

syntax: (define-macro (sym-name [sym-param-1 ...]) body)

Defines a new macro sym-name with optional arguments sym-param-1 .... define-macro is equivalent to assigning a lambda-macro expression to a symbol. When calling a macro defined function, arguments are assigned to the variables in sym-param-1 ... without evaluating the arguments first. Then the body expression(s) are evaluated. When evaluating the define-macro function, the lambda-macro expression is returned.

example:
;; use underscores on symbols
(define-macro (my-setq _x _y) (set _x (eval _y))) 
(my-setq x 123)            =>      123

See also args for accessing the argument list from inside the macro directly when defining macros with a variable number of parameters.

Macros in newLISP are similar to define functions, but do not evaluate their arguments. All parameters are passed by reference. This way new functions can be created which behave just like built-in functions.

Note that in macros the danger exists to pass a parameter using the same variable name as used in the macro definition and the macro internal variable would end up receiving nil, instead of the value intended:

example:
;; not a good definition!

(define-macro (my-setq x y) (set x (eval y)))  

;; symbol name clash for x

(my-setq x 123)        => 123
x                      => nil

This is a disadvantage when using dynamic scoping. To avoid this problem precede all macro variable names by an underscore character. Using this or a similar convention, the danger of symbol name clashes can be avoided minimized.

Another possibility is, to put the macro in its own lexically closed context as a default function. A default function is a function which has the same name as its context and can be called with the context name alone:

example:
;; a macro as a lexically isolated function

(context 'my-setq)

(define-macro (my-setq:my-setq x y) (set x (eval y)))  

(context MAIN)

(my-setq x 123)        => 123   ; no symbol clash

The macro in the example is lexically isolated and no name clashes can occur. Instead of calling the macro using (my-setq:my-setq ...) it can be called just with (my-setq ..) because it is the default function.



def-new

syntax: (def-new sym-source [sym-target])

This function works similar to new but only creates a copy of one symbol and its contents from the symbol in sym-source. When sym-target is not given, a symbol with the same name is created in the current context. All symbols referenced in the contents of sym-source will be translated to symbol references into the current context. If an argument is present in sym-target, the copy will be made into a symbol and context as referenced by the symbol in sym-target. This allows renaming of the function during copy and allows placing the copy in a different context. All symbol references will be translated into symbol references of the target context

def-new returns the symbol created:

example:
(set 'foo:var '(foo:x foo:y))

(def-new 'foo:var)   => var

var                  => (x y)

(def-new 'foo:var 'myvar)  => myvar

myvar                => (x y)

(def-new 'foo:var 'ct:myvar) => ct:myvar

ct:myvar             => (ct:x ct:y)

The function def-new can be used to configure contexts or context objects in a more granular fashion than possible with new, which copies a whole context.



delete

syntax: (delete symbol [bool])
syntax: (delete context [bool])

Deletes a symbol symbol or a context in context with all contained symbols from newLISP's symbol table. References to the symbol will be changed to nil When the expression in bool evaluates to true, symbols are only deleted when they are not referenced.

Protected symbols of built-in functions and special symbols like nil or true cannot be deleted.

delete returns true if the symbol was deleted, else returns nil.

example:
(set 'lst '(a b aVar c d))

(delete 'aVar)   ; aVar deleted, references marked nil

lst              => (a b nil c d)

(set 'lst '(a b aVar c d))

(delete 'aVar true)  

=> nil ; protect aVar if referenced

lst              => (a b aVar c d)

(set 'foo:x 123)
(set 'foo:y "hello")

(delete foo)     => in contexts the quote may be omitted
                     ; foo:x, foo:y and foo will be deleted

Note that deleting a symbol, which is part of a function currently executing, can crash the system or have other unforeseen effects.



delete-file

syntax: (delete-file str-file-name)

Deletes a file given in str-file-name. Returns true or nil depending on a successful outcome of the delete operation.

example:
(delete-file "junk")

This deletes the file junk in the current directory.



device

syntax: (device [int])

int is a I/O device number, which is 0 (zero) for the default STD I/O console window. int may also a the file handle previously obtained from opening a file using open. When no argument is supplied, the current I/O device number is returned. The I/O channel specified by device is internally used by the functions print and read-line. When the current I/O device is 0 print sends output to the console window and read-line accepts input from the keyboard. If the current I/O device has been set opening a file, then print and read-line work on that file.

example:
(device (open "myfile" "write"))  => 5
(print "This goes in myfile")     => "This goes in myfile"
(close (device))                  => true

Note that using close on device automatically resets device to 0 (zero).



difference

syntax: (difference [list-A list-B])

Returns the set difference of list-A - list-B. The resulting list only has elements occurring in list-A but not in list-B. All elements in the resulting list are unique, but list-A and list-B need not to be unique. Elements in the lists can be of any type of LISP expression.

example:
(difference '(2 5 6 0 3 0 2) '(1 2 3 3 2 1)) => (5 6 0)

See also the set functions intersect and unique.



directory

syntax: (directory [str-path])

A list of directory entry names is returned for the directory path given in str-path. On failure nil is returned. When omitting str-path, the list of entries in the current directory is returned.

example:
(directory "/bin")

(directory "c:/")

The first example returns the directory of /bin the second line returns a list of directory entries in the root directory of drive C:. Note that on Win32 systems a forward slash / can be used in path names. When using a backslash, it has to be preceded by a second backslash.

On Win32 systems there should be no trailing slash character after the directory name, but the drive letter has to be followed by a :/. On Linux/UNIX systems a trailing slash after the directory name will cause no problems.



directory?

syntax: (directory? str-path)

Checks if a disk node is a directory. Returns true or nil depending on outcome.

(directory? "/etc")           => true
(directory? "/usr/bin/emacs") => nil

On Win32 systems there should be no trailing slash character after the directory name, but the drive letter has to be followed by a :/. On Linux/UNIX systems a trailing slash after the directory name will cause no problems.



div

syntax: (div num-1 num-2 [num-3 ... ])

The result of evaluating num-1 is successively divided by the number in num-2 ... . div can perform mixed type arithmetic, but always returns floating point numbers. Any floating point calculation with NaN also returns NaN.

example:
(div 10 3)                      => 3.333333333
(div 120 (sub 9.0 6) 100)       => 0.4


dolist

syntax: (dolist (sym list) body ...)

The expressions in body are evaluated for each element in list. The variable in sym is set to each of the elements before evaluation of the body expressions. The variable used as loop index is local and behaves according to the rules of dynamic scoping.

example:
(set 'x 123)
(dolist (x '(a b c d e f g))       ; prints: abcdefg
    (print x))   	    => g   ; return value

; x is local in dolist
; x has still its old value outside the loop

x       => 123  ; x has still its old value

This prints abcdefg in the console window. The value for x is unchanged after execution of dolist because of x's local scope. The return value of dolist is the result of last evaluated expression.

Note that removing elements from the list, i.e. using pop will cause dolist to leave the loop after the removal of the element.



dotimes

syntax: (dotimes (sym int) body ...)

The expressions in body are evaluated int times. The variable in sym is set from 0 to (int - 1) each time before evaluating the body expression(s). The variable used as loop index is local to the dotimes expression and behaves according the rules of dynamic scoping. The loop index is of floating point type. dotimes returns the result of the last expression evaluated in body.

example:
(dotimes (x 10)         ; prints: 0123456789
    (print x))   => 9   ; return value

This prints 0123456789 in the console window.



dotree

syntax: (dotree (sym context-sym) body ...)
syntax: (dotree (sym context) body ...)

The expressions in body are evaluated for all symbols in sym-context. The variable in sym is set to a different symbol in sym-context each time before evaluating the body expression(s). The variable used as loop index is local to the dotree expression and behaves according the rules of dynamic scoping. The symbols are accessed in their context in a sorted manner.

example:
;; fast and less memory overhead
(dotree (s 'SomeCTX) (print s " ")) 

;; the quote can be omitted
(dotree (s SomeCTX) (print s " "))

;; slower and more memory usage
(dolist (s (symbols 'SomeCTX)) (print s " "))

This prints the names of all symbols of SomeCTX in the console window.



do-until

syntax: (do-until exp-condition body)

The expressions in body are evaluated then exp-condition is evaluated. If the evaluation of exp-condition is not nil, then the do-until expression is finished, else the the expressions in body get evaluated again. Note that do-until evaluates the conditional expression after evaluating the body expressions, while until checks the condition before evaluating the body.

example:
(set 'x 1)
(do-until (= x 1) (inc 'x))
x                            => 2

(set 'x 1)
(until (= x 1) (inc 'x))
x                            => 1

While do-until goes through the loop at least once, until will never enter the loop.

See also while and do-while.



do-while

syntax: (do-while exp-condition body)

The expressions in body are evaluated then exp-condition is evaluated. If the evaluation of exp-condition is nil, then the do-while expression is finished, else the the expressions in body get evaluated again. Note that do-while evaluates the conditional expression after evaluating the body expressions, while while checks the condition before evaluating the body.

example:
(set 'x 10)
(do-while (< x 10) (inc 'x))
x                             => 11

(set 'x 10)
(while (< x 10) (inc 'x)) 
x                             => 10

While do-until goes through the loop at least once, until will never enter the loop.

See also until and do-until.



dump

syntax: (dump [exp])

Shows the binary contents of a newLISP cell. Without an argument this functions outputs a listing of all lisp cells to the console. When exp is given, it is evaluated and the contents of the LISP cell is returned in a list.

example:
(dump 'a)      => (9586996 5 9578692 9578692 9759280)

(dump 999)     => (9586996 130 9578692 9578692 999)

The list contains the following memory addresses and information:

    (0) memory address of the LISP cell
    (1) cell->type, mayor/minor type, see newlisp.h for details
    (2) cell->next, linked list ptr
    (3) cell->aux, string length+1 or low word of IEEE 754 double float
    (4) cell->contents, string/symbol address, 32 bit integer or
                    high word of IEEE 754 double float

This function is valuable for changing protection bits in cells or other parts of newLISP internals directly with cpymem etc. The function is only useful for hacking newLISP internals and normally not used.



dup

syntax: (dup exp int-n)

If the expression in exp evaluates to a string, it will be replicated int-n times in a string and returned. For any other type in exp a list of int-n of the evaluation of exp is returned.

example:
(dup "A" 10)    => "AAAAAAAAAA"
(dup "A" 0)     => ""
(dup "AB" 5)    => "ABABABABAB"
(dup 9 7)       => (9 9 9 9 9 9 9)
(dup 9 0)       => ()
(dup 'x 8)      => (x x x x x x x x)
(dup '(1 2) 3)  => ((1 2) (1 2) (1 2))
(dup "\000" 4)  => "\000\000\000\000"

The last example shows handling of binary information.

See also sequence and series.



empty?

syntax: (empty? exp)
syntax: (empty? str)

exp is tested, if an empty list or string. Depending on the result true or nil is returned.

example:
(set 'var '())
(empty? var)        => true
(empty? '(1 2 3 4)) => nil
(empty? "hello")    => nil
(empty? "")         => true

The first example checks a list the second two examples check a string.



encrypt

syntax: (encrypt str-source str-pad)

Does a one-time-pad encryption of str-source using the encryption pad in str-pad. The longer str-pad and the more random the bytes in it, the safer the encryption. If the pad is as long as the source text and fully random and used only once, then one-time-pad encryption is virtually impossible to break, as the encryption seems to contain only random data. To retrieve the original, the same function and pad is applied again on the encrypted text:

example:
(set 'secret 
  (encrypt "A secret message" "my secret key")) 

=> ",YS\022\006\017\023\017TM\014\022\n\012\030E"

(encrypt secret "my secret key") => "A secret message"

The second example encrypts a whole file:

(write-file "myfile.enc" 
    (encrypt (read-file "myfile") "29kH67*"))


ends-with

syntax: (ends-with str-data str-key [nil] )
syntax: (ends-with list exp)

In the first version ends-with tests if a string in str-data ends with the string specified in str-key and returns true or nil depending on the outcome. When specifying nil as a third parameter, the comparison is case insensitive.

example:
(ends-with "newLISP" "LISP")      => true
(ends-with "newLISP" "lisp")      => nil
(ends-with "newLISP" "lisp" nil)  => true

In the second version ends-with checks if a list ends with the list element in exp. true or nil is returned depending on outcome.

example:
(ends-with '(1 2 3 4 5) 5)             => true
(ends-with '(a b c d e) 'b)            => nil
(ends-with '(a b c (+ 3 4)) '(+ 3 4))  => true

The last example shows that exp could be a list by itself.

See also starts-with.



env

syntax: (env)
syntax: (env var-str)
syntax: (env var-str value-str)

In the first syntax without parameters the operating system's environment is retrieved as a list with a string for each entry.

example:

(env)        => ("PATH=/bin:/usr/bin:/sbin" "USER=LUTZ")

In the second syntax the name of an environment variable is given in var-str and env will return the value of the variable or nil if the variable does not exist in the environment.

example:
(env "PATH") => "/bin:/usr/bin:/usr/local/bin"

In the third syntax a variable name and value pair is given in var-str and value-str from which an environment variable is set or created.

example:
(env "NEWLISPDIR" "/usr/bin/")    => true
(env "NEWLISPDIR")                => "/usr/bin/"

env replaces the deprecated environ, getenv and putenv.



error-event

syntax: (error-event sym)

sym contains a user-defined function for error handling. Whenever an error occurs, the system performs a reset and executes the user-defined error handler. The error handler can use the built-in function error-number to inquire the number of the error.

example:
(define (my-handler)    
    (print "error # " (error-number) " has occurred\n")
    (restart-program))

(error-event 'my-handler)     => my-handler

See also the also the function catch for a different possibility to handle errors and the function throw-error to throw user defined errors.

Note that this method will only work when newLISP is run as a library newlisp.so (on Linux/UNIX) or newlisp.dll (on Win32), or when the program file is loaded interactively. For newLISP script files use error handlers written with catch.



error-number

syntax: (error-number)

Returns the number of the last error.

example:
(define (my-handler)    
    (print "error # " (error-number) " has occurred\n")
    (restart-program))

(error-event 'my-handler)

See also throw-error, error-event and error codes in the appendix.



error-text

syntax: (error-text [int-error])

Returns a descriptive text for an error number in int-error:

example:
(error-text 5) => "Not an expression"

If no int-error is given, then the last error is assumed.

See also the error codes in the appendix and the functions error-event, catch and throw-error.



eval

syntax: (eval exp)

exp is evaluated then the result is evaluated.

example:
(set 'expr '(+ 3 4))    => (+ 3 4)
(eval expr)             => 7
(eval (list + 3 4))     => 7
(eval ''x)              => x
(set 'y 123)
(set 'x 'y)
x                       => y
(eval x)                => 123

newLISP passes all parameters by value. Using a quoted symbol, expressions can be passed by reference through the symbol and eval can be used to access the original contents of the symbol:

(define (change-list aList) (push 999 (eval aList)))

(set 'data '(1 2 3 4 5))

(change-list 'data)  => (999 1 2 3 4 5)

Because the parameter 'data is passed quoted, push can work on the original list.

newLISP also offers the possibility of passing parameters by reference enclosing the data into context objects. See the chapter Programming with context objects and the sub chapter Passing objects by reference.



eval-string

syntax: (eval-string str [expr])

The result of str is compiled into newLISP's internal format and is then evaluated. The evaluation result is returned. If the string contains more then one expressions, the result of the last evaluation is returned.

Optionally a second expr argument can be passed which is evaluated and returned in case of an error. This permits maintaining programmatic control, if the evaluation of str finishes with errors.

example:
(eval-string "(+ 3 4)")         => 7
(set 'X 123)                    => 123
(eval-string "X")               => 123

(define (lisp)
  (while true
    (print "\n=>" (eval-string (read-line) "syntax error"))))

The second example shows a simple lisp interpreter eval loop.

See also catch, which can be used to catch errors evaluating expressions directly and not in strings.



exec

syntax: (exec str-process)
syntax: (exec str-process [str-stdin])

In the first form exec launches a process described in str-process and returns all standard output in an array of strings, one each for each line in the STDOUT device. If the process could not be launched, exec returns nil. example:

(exec "ls *.c") => ("newlisp.c" "nl-math.c" "nl-string.c")

A process is started performing a Linux shell list-files ls and the output is captured in an array of strings.

In the second form exec creates a process pipe, starting process in str-process and receiving standard input for this process from str-stdin. The return value is true is the process was successfully launched, else nil.

example:
(exec "cgiProc" query)

In this example cgiProc could be a cgi processor like Perl or newLISP receiving processing standard input, which would be supplied by query.



exit

syntax: (exit [int])

Exits newLISP. Optionally an exit code int may be supplied, which can be tested by the host operating system. When newLISP is run in demon server mode using '-d' as a command line parameter, then exit only closes the network connection and newLISP stays resident listening for a new connection.

example:
(exit 5)


exp

syntax: (exp num)

The expression in num is evaluated and the exponential function is calculated on the result. exp is the inverse function to log.

example:
(exp 1)         => 2.718281828
(exp (log 1))   => 1


expand

syntax: (expand list sym [sym_2 ... sym_n])

One or more symbols in sym are looked up in a simple or nested list and expanded to the current binding of the symbol. The expanded list is returned. The original list remains unchanged.

example:
(set 'x 2 'a '(d e))
(expand '(a x b) 'x)              => (a 2 b)
(expand '(a x (b c x)) 'x)        => (a 2 (b c 2))
(expand '(a x (b c x)) 'x 'a)     => ((d e) 2 (b c 2))

expand is useful when composing lambda expressions or writing variable ''unification'' algorithms:

example:
(define (raise-to power)
    (expand (fn (base) (pow base power)) 'power))

(define square (raise-to 2))
(define cube (raise-to 3))

(square 5) => 25
(cube 5)   => 125

If more than one symbols are present then expand will work in an incremental fashion:

example:
(set 'a '(b c))
(set 'b 1)

(expand '(a b c) 'a 'b)         => ((1 c) 1 c) 

expand reduces it's parameter list similar to apply.



explode

syntax: (explode str)

Transforms a string in str into a list of single character strings:

example:
(explode "newLISP")  
        => ("n" "e" "w" "L" "I" "S" "P")
(join (explode "keep it together"))  
        => "keep it together"

join and append are inverse operations of explode.

explode works also on binary content:

(explode "\000\001\002\003") 

=> ("\000" "\001" "\002" "\003")

But explode will work on character boundaries rather than byte boundaries on UTF-8 enabled versions of newLISP. In UTF-8 encoded strings characters may contain more than one byte.



factor

syntax: (factor num)

Factors a number in num into its prime components. For numbers bigger than the maximum integer of 2147483647 the number should be given as a float. The maximum float to be processed is 999,999,999,999,999.0 (15 digits).

example:

(factor 12345678901234567.0)  => (2 3 3 251 30881 88486577)

(= (apply mul (factor 12345678901234567.0)) 12345678901234567.0)  => true

;; primes.lsp - return all primes up to n in a list

(define (primes n , p)
  (set 'p '())
    (dotimes (e n) 
       (if (= (length (factor e)) 1) 
           (push e p -1)))  p)
           
(primes 20) => (2 3 5 7 11 13 17 19)         

For numbers smaller than 2 or for numbers which are to big factor returns nil.



fft

syntax: (fft list-num)

Calculates the discrete Fourier transform on a list of complex numbers in list-num using the FFT method (Fast Fourier Transform). Each complex number is specified by its real part followed by its imaginary part. In case only real numbers are used the imaginary part is set to zero 0.0. When the number of elements in list-num is not an integer power of 2, fft increases the number of elements padding the list with zeroes. When complex numbers are 0 in the imaginary part, simple numbers can be used.

example:
(ifft (fft '((1 0) (2 0) (3 0) (4 0)))) 
        => ((1 0) (2 0) (3 0) (4 0))

;; when imaginary part is 0, plain numbers work too
;; complex numbers can be intermixed

(fft '(1 2 3 4))     => ((10 0) (-2 -2) (-2 0) (-2 2))
(fft '(1 2 (3 0) 4)) => ((10 0) (-2 -2) (-2 0) (-2 2))

The inverse operation of fft is ifft.



file-info

syntax: (file-info str_name)

Returns a list of information about the file or directory in str_name. newLISP uses the POSIX system call stat() to get the following information:

size,
mode,
device mode,
user id,
group id,
access time
modification time
status change time
example:
(file-info ".bashrc")   
        => (124 33188 0 500 0 920951022 920951022 920953074)

(date (last (file-info "/etc")))   
        => "Mon Mar 8 18:23:17 1999"

In the second example the last status change date for the directory /etc is retrieved.



file?

syntax: (file? str-name)

Checks for the existence of a file in str-name. Returns true if the file exists else returns nil. This function will also return true on directory entries. The existence of a file does not imply anything about it's read or write permissions. A file may exists but may not have the permissions to read from or write to it by the current user.

example:
(if (file? "afile") (set 'fileNo (open "afile" "read")))


filter

syntax: (filter exp-predicate exp-list)

The predicate exp-predicate is applied to each element of the list exp-list. A list containing the elements for which exp-predicate is true is returned.

example:
(filter symbol? '(1 2 d 4 f g 5 h)) => (d f g h)

(define (big? x) (> x 5))        => (lambda (x) (> x 5))

(filter big? '(1 10 3 6 4 5 11))    => (10 6 11)

The predicate may be a built-in predicate or a user-defined function or lambda expression.

See also the related function index which returns the indices of the filtered elements.



find

syntax: (find exp-key list)
syntax: (find str-key str-data)

syntax: (find str-pattern str-data int-option)
syntax: (find str-pattern list int-option)

If the second argument evaluates to a list, then find returns the index position (offset) of the element derived from evaluating exp-key.

If the second argument str-data evaluates to a string then the offset position of the string str-key found in the first argument str-data is returned. In this case find works also on binary str-data.

The presence of a third parameter specifies a search with the regular-expression pattern specified in str-pattern and an option number specified in int-option, i.e. 1 (one) for case insensitive search or 0 (zero) no special options.

Regular expressions in newLISP are standard Perl Compatible Regular Expression (PCRE) searches. Expressions or subexpressions found are returned in the system variables $0, $1, $2 ... etc., which can be used just like any other symbol. As an alternative the contents of these variables can also be accessed by using ($ 0), ($ 1), ($ 2) ... etc. This method allows indexed access, i.e: ($ i), where i is an integer.

See regex for the meaning of the option numbers and more references about regular expression search.

example:
(find "world" '("hello" "world"))       => 1
(find "hi" '("hello" "world"))          => nil
(find '(1 2) '((3 4) 5 6 (1 2) (8 9)))  => 3

(find "world" "Hello world")            => 6
(find "WORLD" "Hello woRLd")            => nil

; case insensitive regex

(find "WorlD" "Hello woRLd" 1)          => 6   

(find "hi" "hello world")               => nil
(find "Hello" "Hello world")            => 0

; regex with default options

(find "cat|dog" "I have a cat" 0)       => 9 
$0                                      => "cat"
(find "cat|dog" "my dog" 0)             => 3
$0                                      => "dog"
(find "cat|dog" "MY DOG" 1)             => 3
$0                                      => "DOG"

; regex finds string at index 2 of a list

(find "a" '(1 2 "nnnammm" '(a b)) 0)    => 2   
$0                                      => "a"

;; find with sub-expressions in regular expression
;; and access with system variables

(set 'str  "http://nuevatec.com:80")

(find "http://(.*):(.*)" str 0)   => 0

$0                                => "http://nuevatec.com:80"
$1                                => "nuevatec.com"
$2                                => "80"

;; system variables as an indexed expression (since 8.0.5)
($ 0)                             => "http://nuevatec.com:80"
($ 1)                             => "nuevatec.com"
($ 2)                             => "80"

For other functions using regular expressions see parse, regex, replace and search.

For finding expressions in nested or multidimensional lists see ref.



first

syntax: (first list)
syntax: (first str)

Returns the first element or a list or the first character of a string. The operand is not changed. This function is equivalent to car or head in other LISP dialects.

example:
(first '(1 2 3 4 5))            => 1
(first '((a b) c d))            => (a b)
(set 'aList '(a b c d e))       => (a b c d e)
(first aList)                   => a
aList                           => (a b c d e)

In the second version the first character is returned from a string in str and returned in a string.

example:

(first "newLISP")        => "n"
(first (rest "newLISP")) => "e"

See also last and rest.



flat

syntax: (flat list)

Returns the flattened form of a list:

example:
(set 'lst '(a (b (c d))))
(flat lst)                  => (a b c d)

(map (fn (x) (ref x lst)) (flat lst))

=> ((0) (1 0) (1 1 0) (1 1 1))

flat can be used to iterate through nested lists.



fn

See define and lambda which is a different writing of the shorter fn.



float

syntax: (float exp [exp-default] )

If the expression in exp evaluates to a number or a string a conversion to a float is returned. If exp cannot be converted to a float then nil or if specified the evaluation of exp-default will be returned. This function is mostly used to convert strings from user input or from reading and parsing text. The string must start with a number digit or the +, - or . sign. If str is invalid, float returns nil as a default value.

Floats bigger than 1e308 or smaller than -1e308 in their exponents are converted to +INF or -INF respectively. The writing of +INF and -INF differs on different platforms and compilers

example:
(float "1.23")          => 1.23
(float " 1.23")         => 1.23
(float ".5")            => 0.50
(float "-1.23")         => -1.23
(float "-.5")           => nil
(float "#1.23")         => nil
(float "#1.23" 0.0)     => 0

(float? 123)            => nil
(float? (float 123))    => true

(float '(a b c))        => nil
(float '(a b c) 0)      => 0
(float nil 0)           => 0

(float "abc" "not a number")   => "not a number"


(print "Enter a float num:")
(set 'f-num (float (read-line)))

See also int for parsing integer numbers.



float?

syntax: (float? exp)

True is returned only if evaluation of exp yields a floating-point number; otherwise nil is returned.

example:
(set 'num 1.23)
(float? num)            => true


floor

syntax: (floor number )

Returns the next lower integer to number as a floating point number.

example:

(floor -1.5)  => -2
(floor 3.4)   => 3

See also the function ceil.



flt

syntax: (flt number )

Converts a number to a 32 bit float represented by an integer. This function is used when passing 32 bit floats to library routines. newLISP floating point number are 64 bit and get passed as 64 bit floats when calling imported 'C' library routines.

example:

(flt 1.23)                    => 1067282596

;; pass 32 bit float to C-function: foo(float value) 
(import "mylib.so" "foo")
(foo (flt 1.23))

(get-int (pack "f" 1.23)) => 1067282596

(unpack "f" (pack "ld" (flt 1.2345)))  => (1.230000019)

The last two statements illustrate the inner workings of flt.

See also import for importing libraries.



for

syntax: (for (sym num-from num-to [num-step]) body)

Repeatedly evaluates the expressions in body for a range of values specified in num-from and num-to inclusive. A step-size may be specified with num-step. If no step size is specified, one is assumed. for returns the last result from evaluating the expressions in body. The symbol sym, which is local in dynamic scope to the for expression, takes on successively each value in the specified range as a floating point value.

example:
 
> (for (x 1 10 2) (println x))
1
3
5
7
9

> (for (x 8 6 0.5) (println x))
8
7.5
7
6.5
6

>

The second example uses a range from a higher to a lower number. Note that the step size is always a positive number.

See also sequence for making a sequence of numbers.



fork

syntax: (fork exp)

The expression in exp is launched as a newLISP child process thread. The new process inherits the entire address space but will run independently, so symbol or variable contents changed in the child thread will not affect the parent process and vice versa. The child process ends when the evaluation of exp ends.

On success fork returns with the child process ID, on failure nil is returned. See also wait-pid which waits for a child process to finish.

This function is only available on Linux/UNIX versions of newLISP and on the CYGWIN compiled version on Win32.

example:
> (set 'x 0)
0
> (fork (while (< x 20) (println (inc 'x)) (sleep 1000)))
176
> 1
2
3
4
5
6

The example illustrates how the child process thread inherits the symbol space and how it is independent from the parent process. The fork statement returns right away with the process ID of 176. The child process increments the variable x by one each second and prints it to standard out (bold face). In the parent process commands can still be entered. Enter x to see that in the parent process the symbols x still has the value 0 (zero). Although statements entered will mix with the display of the child process output, they will be correctly input to the parent process.

The second example illustrates how pipe can be used to communicate between threads.

example:
(define (count-down-thread x channel)
(while (!= x 0)
  (begin
    (write-line (string x) channel)
    (sleep 100)
    (dec 'x))))

(define (observer-thread channel)
(setq i "")
(while (!= i "0")
    (println "thread " (setq i (read-line channel)))))

(map set '(in out) (pipe))
(fork (observer-thread in))
(fork (count-down-thread 5 out))

;; the following output is generated by observer-thread

thread 5
thread 4
thread 3
thread 2
thread 1

The count-down-thread writes numbers to the communication pipe, where they are picked up by the observer-thread and displayed.

See also the functions semaphore for synchronizing threads and share for sharing memory between threads.



format

syntax: (format str-format exp-data-1 [exp-data-i ... ] )

Constructs a formatted string from exp-data-1 using the format specified in the evaluation of str-format. The format is specified identical to the format used for the printf() function in the ANSI 'C' language. More than one exp-data can be specified for more than one format specifier in str-format.

format checks for a valid format string and matching data type and number of arguments. Error messages are given for wrong formats or data types. int, float or string can be used to insure correct data types and avoid error messages.

The format string has the following general format:

"%w.pf"

The percent % sign start a format specification. To display a percent sign % inside a format string double it: %%

w

Width of field. Data is right aligned, else when preceded by a minus sign left aligned. When preceded by a zero then unused space is filled with leading zeros. The width field is optional and serves all data types.

p

Precision number of decimals (floating point only) or strings separated by a period from the width field. Precision is optional. If preceded by a plus sign +, numbers are displayed with a + in front if positive. When using the precision field on strings, the number of characters displayed is limited to the number in p.

f

Type flag is essential and can not be omitted.

Types in f:

s       text string
c       character (value 1 - 255)
d       decimal (32 bit)
u       unsigned decimal (32 bit)
x       hexadecimal lower case
X       hexadecimal upper case
f       floating point
g       general floating point

Other text may be filled between, before and after the format specs.



example:
(format ">>>%6.2f<<<" 1.2345)     => ">>>  1.23<<<"
(format ">>>%-6.2f<<<" 1.2345)    => ">>>1.23  <<<"
(format ">>>%+6.2f<<<" 1.2345)    => ">>> +1.23<<<"
(format ">>>%+6.2f<<<" -1.2345)   => ">>> -1.23<<<"
(format ">>>%-+6.2f<<<" -1.2345)  => ">>>-1.23 <<<"

(format "%10g" 1.23)              => "      1.23"
(format "%10g" 1.234)             => "     1.234"

(format "Result = %05d" 2)        => "Result = 00002"

(format "%-15s" "hello")          => "hello          "
(format "%15s %d" "hello" 123)    => "          hello 123"
(format "%5.2s" "hello")          => "   he"
(format "%-5.2s" "hello")         => "he   "

(format "%x %X" -1 -1)            => "ffffffff FFFFFFFF"

(format "%c" 65)                  => "A"

In newLISP format will automatically convert from inter to floating point numbers or from floating point to integer if the format strings requires it:

(format "%f" 123)        => 123.000000

(format "%d" 123.456)    => 123


fv

syntax: (fv num-rate num-nper num-pmt num-pv [int-type])

Calculates the future value of a loan with constant payment num-pmt and constant interest rate num-rate after num-nper periods and a beginning principal value of num-pv. If payment is at the end of the period int-type is 0 for payment at the end of each period int-type is 1. If num-type is omitted payment at the end of each period is assumed.

example:
(fv (div 0.07 12) 240 775.30 -100000) => -0.5544645052

The example illustrates how a loan of $100,000 is paid down to a residual of $0.55 after 240 monthly payments and a yearly interest rate of 7%.

See also irr, nper, npv, pmt and pv.



gammai

syntax: (gammai num-a num-b)

Calculates the Incomplete Gamma function of value a and b in num-a and num-b.

example:
(gammai 4 5)   => 0.7349740847
The Incomplete Gamma function is used to derive the probability of Chi2 to exceed a given value for a degrees of freedom df as follows:
Q(Chi2|df) = Q(df/2, Chi2/2) = gammai(df/2, Chi2/2)

See also prob-chi2.



gammaln

syntax: (gammaln num-x)

Calculates the Log Gamma function of a value x in num-x.

example:
(exp (gammaln 6))    => 120

The example uses the equality of n! = gamma(n + 1) to calculate the factorial value of 5.

The Log Gamma function is also related to the Beta function which can be derived from it:

Beta(z,w) = Exp(Gammaln(z) + Gammaln(w) - Gammaln(z+w))


get-char

syntax: (get-char int-address)

Gets a character from an address specified in int-address. The function is useful when using imported shared library functions with import.

example:
char * foo(void)
        {
        char * result;
        result = "ABCDEFG";
        return(result);
        }

Consider the previous 'C' function in a shared library returning a character pointer (address to a string).

(import "mylib.so" "foo")
(print (get-char (foo) ))         =>  65
(print (get-char (+ (foo) 1)))    =>  66

Note that get-char is an unsafe function when used with a wrong address in int-address. When a wrong address is specified the system might crash.

See also address, get-int, get-float, get-string and pack, unpack.



get-float

syntax: (get-float int-address)

Gets a double float (64 bit) from an address specified in int-address. The function is useful when using imported shared library functions with import, and a function returns an address pointer to a double float or a pointer to a structure containing double floats.

example:
double float * foo(void)
        {
        double float * result;
        ...
        *result = 123.456;
        return(result);
        }

The previous C-function is compiled into a shared library.

(import "mylib.so" "foo")
(get-float (foo)) => 123.456

foo is imported and returns a pointer to a double float when called. Note that get-float is an unsafe function when used with a wrong address in int-address. When a wrong address is specified the system might crash.

See also address, get-int, get-char, get-string and pack, unpack.



get-int

syntax: (get-int int-address)

Gets an integer (32 bit) from an address specified in int-address. The function is useful when using imported shared library functions with import, and a function returns an address pointer to integers or a pointer to a structure containing integers.

example:
int * foo(void)
        {
        int * result;
        ...
        *result = 123;
        return(result);
        }

int foo-b(void)
        {
        int result;
        ...
        result = 456;
        return(result);
        }

Consider the first 'C' function foo in a shared library returning a integer pointer (address of an integer).

(import "mylib.so" "foo")
(get-int (foo))        =>  123
(foo-b)                    =>  456

Note that get-int is an unsafe function when used with a wrong address in int-address. When a wrong address is specified the system might crash.

See also address, get-char, get-float, get-string and pack, unpack.



get-string

syntax: (get-string int-address)

Gets a character string from an address specified in int-address. The function is useful when using imported shared library functions with import.

example:
char * foo(void)
        {
        char * result;
        result = "ABCDEFG";
        return(result);
        }
Consider the previous 'C' function in a shared library returning a character pointer (address to a string).
(import "mylib.so" "foo")
(print (get-string (foo)))   =>  "ABCDEFG"

When giving a string as an argument get-string will take it's address as the argument. Because get-string always breaks off at the first first \000- (zero) character it encounters, it can be used to get a string out of a buffer:

example:
(set 'buff "ABC\000\000\000") => "ABC\000\000\000"

(length buff)                 => 6

(get-string buff)             => "ABC"

(length (get-string buff))    => 3

See also get-char, get-int, get-float and pack, unpack

Note that get-string can crash the system if the wrong address is specified.



get-url

syntax: (get-url str-url [str-option(s)])

Reads a web page or file specified by the URL in str-url using the HTTP GET protocol. As an option "header" can be specified to retrieve only the header. A debug option "debug" prints raw header information, as it is received by the remote host, to the console. Previously get-url was named read-url.

(get-url "http://www.nuevatec.com")
(get-url "http://www.nuevatec.com" "header")
(get-url "http://www.nuevatec.com" "header" "debug")

(env "HTTP_PROXY" "http://ourproxy:8080")
(get-url "http://www.nuevatec.com/newlisp/")

The index page from the site www.nuevatec.com specified in str-url is returned as a string. In the second line only the HTTP header is returned in a string.

The second example shows the use of a proxy server. The URL of the proxy server must be in the operating system's environment. This can be done using the env function in newLISP.

See also put-url and post-url.



global

syntax: (global sym-1[sym-2...])

One or more symbols in sym-1[sym-2... can be made globally accessible from other contexts than MAIN. The statement has to be executed in the MAIN context and only symbols belonging to the context MAIN can be made global. global returns the last symbol made global.

example:
(global 'aVar 'x 'y 'z)  => z

(define (foo x) 
  ( ... ))

(constant (global 'foo))

The second example shows, how constant and global can be combined in one statement; protecting and making global a previous function definition.



if

syntax: (if exp-condition exp-1 [exp-2])
syntax: (if exp-cond-1 exp-1 exp-cond-2 exp-2 [...])

If the value of exp-condition is not nil or the empty list, the result of evaluating exp-1 is returned. Otherwise the value of exp-2 is returned; and if exp-2 is absent, the value of exp-condition is returned.

example:
(set 'x 50)                        => 50
(if (< x 100) "small" "big")       => "small"
(set 'x 1000)                      => 1000
(if (< x 100) "small" "big")       => "big"
(if (> x 2000) "big")              => nil

The second form of if works similarly to cond but does not take parentheses around the condition-body pair of expressions. In this form if can have an unlimited number of arguments.

example:

(define (classify x)
    (if
        (< x 0) "negative"
        (< x 10) "small"
        (< x 20) "medium"
        (>= x 30) "big"
        "n/a"))

(classify 15)    => "medium"
(classify 100)   => "big"
(classify 22)    => "n/a"
(classify -10)   => "negative"

The last expression "n/a" is optional, without it the evaluation of (>= x 30) would be returned, behaving exactly like a traditional cond but without requiring parenthesis around the condition-expression pairs.

In any case the whole if expression always returns the last expression or condition evaluated.

See also unless.



ifft

syntax: (ifft list-num)

Calculates the inverse discrete Fourier transform on a list of complex numbers in list-num using the FFT method (Fast Fourier Transform). Each complex number is specified by its real part followed by its imaginary part. In case only real numbers are used the imaginary part is set to zero (0.0). When the number of elements in list-num is not an integer power of 2, ifft increases the number of elements padding the list with zeroes. When complex numbers are 0 in the imaginary part, simple numbers can be used.

example:
(ifft (fft '((1 0) (2 0) (3 0) (4 0)))) 
        => ((1 0) (2 0) (3 0) (4 0))

;; when imaginary part is 0, plain numbers work too

(ifft (fft '(1 2 3 4))) 
        => ((1 0) (2 0) (3 0) (4 0))

The inverse operation of ifft is fft.



import

syntax: (import str-lib-name str-function-name ["cdecl"])

Imports a function str-function-name from a shared library named in str-lib-name. The functions address, get-char, get-int, get-float, get-string and pack, unpack can be used to retrieve return-values or unpack data from returned structure addresses. If the library is not found in the normal library search path, str-lib-name must contain the full path name.

To transform newLISP data types into the data types needed by the imported function use the functions float for 64bit double floats, flt for 32bit floats and int for 32bit integers. By default newLISP passes floating point numbers as 64bit double floats, integers as 32bit integers and strings as 32bit integers for string addresses.

example:
;; import in LINUX

(import "libc.so.6" "printf")      => printf <400862A0>

;; import in CYGWIN

(import "cygwin1.dll" "printf")    => printf <6106B108>  

(printf "%g %s %d %c\n" 1.23 "hello" 999 65)
                                   =>   1.23 hello 999 A
                                   =>   17 ; return value

;; import Win32 DLLs in Win32 or CYGWIN version

(import "kernel32.dll" "GetTickCount") => GetTickCount
(import "user32.dll" "MessageBoxA")    => MessageBoxA
(GetTickCount)                         => 3328896

In the first example a string "1.23 hello 999 A" is printed as a side effect and the expressions returns the value 17 (characters printed). Any 'C' function in any shared library can be imported this way.

The message box example pops up a Windows message box which may be hidden behind the console window, and the console prompt does not return until the 'OK' button is pressed in the message box.

;;this pops up message box

(MessageBoxA 0 "This is the body" "Caption" 1) 

The other examples show several imports of Win32 DLL functions and the details of passing values by value or by reference. Whenever strings or numbers are passed by reference, space has to be reserved first.

;; allocating space for a string return value

(import "kernel32.dll" "GetWindowsDirectoryA")
(set 'str (dup "\000" 64)  ;; reserve space and initialize

(GetWindowsDirectoryA str (length str))

str =>   "C:\\WINDOWS\000                     "

(slice str 0 (find "\000" str)) => "C:\\WINDOWS"

;; or use trim
(trim str) => "C:\\WINDOWS"


;; passing an integer parameter by reference

(import "kernel32.dll" "GetComputerNameA")

(set 'str (dup "\000" 64)    ;; reserve space, initialize

;; get size in a buffer lpNum
(set 'lpNum (pack "lu" (length str)))  

;; call the function
(GetComputerNameA str lpNum) 

str =>    "LUTZ-PC\000                        "

(slice str 0 (find "\000" str)) => "LUTZ-PC"

; or use trim
(trim str) => "LUTZ-PC"

import returns the address of the function, which can be used to assign to a different name for the imported function.

(set 'imprime (import "libc.so.6" "printf")) 
        => printf <400862A0>

(imprime "%s %d" "hola" 123)                 
        => "hola 123"

Note that the preceding examples are not displayed in the newLISP-tk GUI front-end, as the output of 'printf' is directed to standard out (STDIO) and is not visible in the newLISP-tk console. This only affects function imports with output to standard out.

Note that the Win32 version of newLISP uses standard call stdcall conventions to call DLL library routines. This is necessary to call DLLs belonging to the Win32 operating system like odbc32.dll. Most third party DLLs are compiled for 'C' declaration cdecl calling conventions and may need to specify the string "cdecl" as an additional last parameter when importing functions. newLISP compiled for LINUX and other UNIX uses the cdecl calling conventions by default and does ignore any additional string.

;; force cdecl calling conventions on Win32
(import "sqlite.dll" "sqlite_open" "cdecl") => sqlite_open <673D4888>

Imported functions may take up to 14 parameters, floats count double, i.e. passing 5 floating point numbers takes up 10 of the 14 parameter spaces.



inc

syntax: (inc sym [num])

The number in sym is incremented by 1 or by the optional number num and the result is returned. inc performs mixed int and float arithmetic according to the following rules:

If num is absent inc always returns an integer in sym. If the input arguments are floats and num is absent, the input arguments are truncated to integers.

Integer calculations (without num) which result in numbers greater than 2,147,483,647 wrap around to negative numbers. Results smaller than -2,147,483,648 wrap around to positive numbers.

If num is supplied, inc always returns the result as floating point even for integer input arguments.

example:
(set 'x 0)    => 0
(inc 'x)      => 1
x             => 1
(inc 'x 0.25) => 1.25
x             => 1.25

(inc 'x)      => 2    ; get truncated

See also dec for decrementing.



index

syntax: (index exp-predicate exp-list)

The predicate exp-predicate is applied to each element of the list exp-list. A list containing the indices of the elements for which exp-predicate is true is returned.

example:
(index symbol? '(1 2 d 4 f g 5 h)) => (2 4 5 7)

(define (big? x) (> x 5))          => (lambda (x) (> x 5))

(index big? '(1 10 3 6 4 5 11))    => (1 3 6)

The predicate may be a built-in predicate or a user-defined function or lambda expression.

See also filter which returns the elements themselves.



int

syntax: (int exp [exp-default] [int-base])

If the expression in exp evaluates to a number or a string a conversion to an integer is returned. If exp cannot be converted to an integer then nil or the evaluation of a exp-default will be returned. This function is mostly used when translating strings from user input or from parsing text. If exp evaluates to a string then the string must start with a number digit or space(s) or the + or - sign or '0x' for hexadecimal strings or a '0' (zero) for octal strings. If str is invalid, integer returns nil as a default value if not specified otherwise.

A second optional parameter can be used to force the number base of conversion to a specific value.

Integers bigger than 2,147,483,647 are truncated to 2,147,483,647. Integers smaller than -2,147,483,648 are truncated to -2,147,483,648.

When converting from a float as in the second form of integer, floating-point numbers bigger or smaller than the integer max / min values are truncated, too. A floating-point expression evaluating to NaN is converted to 0 (zero).

example:
(int "123")               => 123
(int " 123")              => 123
(int "a123" 0)            => 0
(int (trim " 123"))       => 123
(int "0xFF")              => 255
(int "055")               => 45
(int "1.567")             => 1

(integer? 1.00)		  => nil
(integer? (int 1.00))     => true

(int "1111" 0 2)          => 15    ; base 2 conversion
(int "0FF" 0 16)          => 255   ; base 16 conversion

(int 'xyz)                => nil
(int 'xyz 0)              => 0
(int nil 123)             => 123

(int "abc" "not a number")    => => "not a number"

(print "Enter a num:")
(set 'num (int (read-line)))

See also float for converting to floating point numbers.



integer?

syntax: (integer? exp)

integer? returns true only if the value of exp is an integer; otherwise it returns nil.

example:
(set 'num 123)  => 123
(integer? num)  => true


intersect

syntax: (intersect list-A list-B)

Returns a list containing one copy of each element found both in list-A and list-B.

example:
(intersect '(3 0 2 4 1) '(1 4 2 5)) => (2 4 1)

See also the set functions difference and unique.



invert

syntax: (invert matrix-A)

Returns the inversion of a two dimensional matrix in matrix-A. The matrix must be square with the same number of rows and columns and non-singular (invertible). Matrix inversion can be used to solve systems of linear equations, for example, multiple regression in statistics. newLISP uses LU-decomposition of the matrix to find the inverse.

example:
(set 'A '((-1 1 1) (1 4 -5) (1 -2 0)))
(invert A)    =>   ((10 2 9) (5 1 4) (6 1 5))

See also the matrix functions transpose and multiply.



irr

syntax: (irr list-amounts [list-times [num-guess]])

Calculate the internal rate of return of a cash flow per time period. The internal rate of return is the interest rate that makes the present value of a cash flow equal to 0.0 (zero). Inflowing (negative values) and outflowing (positive values) amounts are specified in list-amounts. If no time periods are specified in list-times, then amounts in list-amounts correspond to consecutive time periods increasing by 1 (1 2 3 ...). The algorithm used is iterative with an initial guess of 0.5 (50%). Optionally a different initial guess can be specified. The algorithm returns when a precision of 0.00001 (0.0001 %) is reached. nil is returned if the algorithm cannot converge after 50 iterations.

irr is often used to decide between different types of investments.

example:
(irr '(-1000 500 400 300 200 100))  

=> 0.2027


(npv 0.2027 '(500 400 300 200 100)) 

=> 1000.033848 ; ~ 1000


(irr '(-1000 500 400 300 200 100) '(0 3 4 5 6 7)) 

=> 0.0998


(irr '(-5000 -2000 5000 6000) '(0 3 12 18)) 

=> 0.0321

If an initial investment of 1000 yields 500 after the first year, 400 after 2 years, and so on, finally reaching 0.0 (zero) after 5 years, then that corresponds to a yearly return of about 20.2%. The next line demonstrates the the relation between irr and npv. Only 9.9% return are necessary when making the first withdrawal after 3 years.

In the last example securities where purchased initially for 5000 then for another 2000 3 month later. After a year (12 month) securities for 5000 are sold. Selling the remaining securities after 18 months renders 6000. The internal rate of return is 3.2% per month, or about 57% in 18 month.

See also fv, nper, npv, pmt and pv.



join

syntax: (join list-of-strings [separator-string])

Given a list of strings list-of-strings, join concatenates the strings. If separator-string is present, it is inserted between each string in the join.

example:

(set 'lst '("this" "is" "a" "sentence"))

(join lst " ") => "this is a sentence"

(join (map string (slice (now) 0 3)) "-")  => "2003-11-26"

(join (explode "keep it together"))  => "keep it together"

See also append, string, and explode, the inverse operation to join.



lambda

See define and fn which are different forms of building and writing of lambda expressions.



lambda?

syntax: (lambda? exp)

Returns true only if the value of exp is a lambda expression and otherwise nil.

example:
(define (square x) (* x x))
(lambda? square)             => true

See define and define-macro for more information about lambda expressions.



last

syntax: (last list)
syntax: (last str)

Returns the last element of a list or a string.

example:
(last '(1 2 3 4 5))            => 5
(last '(a b (c d)))            => (c d)

In the second version the last character in the string str is returned as a string.

example:
(last "newLISP")   = "P"

See also first, rest and nth.



legal?

syntax: (legal? str)

The token in string is checked if a legal symbol in newLISP source code. Non legal symbols can be created using the sym function, i.e. symbols containing spaces, quotes or other characters not allowed. Non legal symbols are created frequently when using symbols for for associative data access:

example:
(symbol? (sym "one two")) => true

(symbol? "one two")       => nil ; contains a space

(set (sym "one two) 123)  => 123

(eval (sym "one two"))    => 123

The example shows that the string "one two" does not contain a legal symbol although a symbol can be created from this string and treated like a variable.



length

syntax: (length expr)

Returns the number of elements in a list, the number of rows in an array or the number of characters in a string.

length applied to a symbol returns the length of the symbol name. Applied to a number, length returns the number of bytes needed in memory to store that number: 4 for integers and 8 for floating-point numbers.

example:
(length '(a b (c d) e))         => 4
(length '())                    => 0
(set 'someList '(q w e r t y))  => (q w e r t y)
(length someList)               => 6

(set 'ary (array 2 4 '(0)))     => ((1 2 3 4) (5 6 7 8))
(length ary)                    => 2

(length "Hello World")          => 11
(length "")                     => 0

(length 'someVar)               => 7
(length 123)                    => 4
(length 1.23)                   => 8



let

syntax: (let ((sym1 exp-init1) [ (sym2 exp-init2) ...] ) exp-body)
syntax: (let (sym1 exp-init1 [sym2 exp-init2 ... ] ) exp-body)

One or more variables sym1, sym2, ... are declared locally and initialized with expressions in exp-init1, exp-init2, etc. When the local variables are initialized the initializer expressions evaluate using symbol bindings as before the let statement. To incrementally use symbol bindings as evaluated during the initialization of locals in let, use letn. One or more expressions in exp-body are evaluated using the local definitions of sym1, sym2 etc. let is useful for breaking up complex expressions by defining local variables close to the place where they are used. The second form omits the parenthesis around the variable expression pairs but functions identical.

example:
(define (sum-sq a b)
  (let ((x (* a a)) (y (* b b)))
    (+ x y)))

(sum-sq 3 4) => 25

(define (sum-sq a b)           ; alternative syntax
    (let (x (* a a) y (* b b))
        (+ x y)))

The variables x and y are initialized, then the expression (+ x y) is evaluated. The let form is just an optimized version and syntactic convenience for writing:

((lambda (sym1 [sym2 ...]) exp-body ) exp-init1 [ exp-init2 ])

See also letn for an incremental or nested form of let.



letn

syntax: (letn ((sym1 exp-init1) [ (sym2 exp-init2) ...] ) exp-body)
syntax: (letn (sym1 exp-init1 [sym2 exp-init2 ... ] ) exp-body)

letn is like a nested let and works similar to let, but will incrementally use the new symbol bindings when evaluating the initializer expressions as if several let were nested. The following comparison of let and letn show the difference:

example:
(set 'x 10)
(let ((x 1) (y (+ x 1))) 
     (list x y))           => (1 11)

(letn ((x 1) (y (+ x 1))) 
      (list x y))          => (1 2)

While in the first example using let the variable y is calculated using the binding of x before the let expression, in the second example using letn the variable y is calculated using the new local binding of x.

(letn  ((x 1) (y x)) 
     (+ x y))             =>  2

;; same as nested let's

(let ((x 1))
     (let ((y x))
          (+ x y)))       =>  2

letn works like several nested let



list

syntax: (list exp-1 [exp-2 ...]

The exp are evaluated and the values used to construct a new list.

example:
(list 1 2 3 4 5)                => (1 2 3 4 5)
(list 'a '(b c) (+ 3 4) '() '*) => (a (b c) 7 () *)

See also cons and push for other forms of building lists.



list?

syntax: (list? exp)

Returns true only if the value of exp is a list; otherwise returns nil. Note that lambda and lambda-macro expressions are also recognized as special instances of a list expression.

example:
(set 'var '(1 2 3 4))    => (1 2 3 4)
(list? var)              => true

(define (double x) (+ x x))

(list? double)          => true


load

syntax: (load str-file-name [str-file-name-2 ...])

Loads and translates newLISP from a source file specified in one or more str-file-name and evaluates the expressions contained in the file(s). When loading is successful load returns true. If a file cannot be loaded load returns nil without loading other files specified. load functions may be nested, i.e.: loaded files may contain other load expressions.

example:
(load "myfile.lsp")               => true
(load "a-file.lsp" "b-file.lsp")  => true


log

syntax: (log num)

The expression in num is evaluated and the natural logarithmic function is calculated from the result.

example:
(log 1)         => 0
(log (exp 1))   => 1

See also exp, which is the inverse function to log.



lookup

syntax: (lookup exp assoc-list [int-index])

Finds in assoc-list a member-list the first element of which has the same value as exp and returns the int-index element of member-list (or the last element if int-index is absent). See also Indexing elements of strings and lists.

lookup is similar to assoc but goes one step further by extracting the element found in the list.

example:
(set 'params '(
        (name "John Doe") 
        (age 35) 
        (gender "M") 
        (balance 12.34)))

(lookup 'age params)    => 35

(set 'persons '(
        ("John Doe" 35 "M" 12.34) 
        ("Mickey Mouse" 65 "N" 12345678)))

(lookup "Mickey Mouse" persons 2)    => "N"
(lookup "Mickey Mouse" persons -3)   => 65
(lookup "John Doe" persons 1)        => 35 
(lookup "John Doe" persons -2)       => "M"

See also assoc



lower-case

syntax: (lower-case str)

All characters of string in str are converted to lower case characters. A new string is created, the original is untouched.

example:
(lower-case "HELLO WORLD")  => "hello world"
(set 'Str "ABC")
(lower-case Str)    => "abc"
Str                 => "ABC"

See also upper-case.



macro?

syntax: (macro? exp)

true is returned only if exp evaluates to a lambda-macro expression, otherwise nil is returned.

example:
(define-macro (mysetq lv rv) (set lv (eval rv)))
(macro? mysetq)           => true


main-args

syntax: (main-args)
syntax: (main-args int-index)

main-args returns a list with several string members, one for program invocation and each of the command line arguments.

example:
newlisp 1 2 3

> (main-args) =>  ("/usr/bin/newlisp" "1" "2" "3")

After executing: newlisp 1 2 3 at the command prompt. main-args returns the list of the invoking program and 3 command line arguments:

Optionally main-args can take an int-index indexing into the list:

newlisp a b c

> (main-args 0)   =>  "/usr/bin/newlisp"
> (main-args -1)  =>  "c"
> (main-args 2)   =>  "b"

Note that when newLISP is executed from a script, main-args also returns the name of the script as the second argument:

#!/usr/bin/newlisp
# 
# script to show the effect of 'main-args' in script file

(print (main-args) "\n")
(exit)

# end of script file

;; execute script in the OS shell:

script 1 2 3

=> ("/usr/bin/newlisp" "./script" "1" "2" "3")

Execute this script with different command line parameters.



make-dir

syntax: (make-dir str-dir-name [int-mode])

Creates a directory as specified in str-dir-name with the optional access mode int-mode. Returns true or nil depending on a successful outcome. If no access mode is specified 'drwxr-xr-x' results on most UNIX systems. On UNIX system the access mode specified will also be masked by the OS's user-mask set from the system administrator. The user-mask can be retrieved on UNIX system using the command: umask.

example:
;0 (zero) in front of 750 makes it an octal number

(make-dir "adir" 0750)  

The example creates a directory named adir in the current directory with an access mode 0750 (octal 750 = drwxr-x---).



map

syntax: (map exp-functor list-args-1 [list-args-2 ... ])

Applies the primitive, defined function or lambda expression exp-functor successively to the arguments specified in list-args-1, list-args-2, ... and returns all results in a list.

example:
(map + '(1 2 3) '(50 60 70))                 => (51 62 73)

(map (lambda (x y) (* x y)) '(3 4) '(20 10)) => (60 40)

The second example shows creating a function for map dynamically:

(define (foo op p) 
    (append (lambda (x)) (list (list op p 'x))))

(foo 'add 2) => (lambda (x) (add 2 x))

(map (foo add 2) '(1 2 3 4 5)) => (3 4 5 6 7 8)

(map (foo mul 3) '(1 2 3 4 5)) => (3 6 9 12 15)

Note that the quote before the operand can be omitted, as primitives in newLISP evaluate to themselves.

By incorporating the map into the function definition we could do:

(define (list-map op p lst) 
    (map (lambda (x) (op p x)) lst))

(list-map + 2 '(1 2 3 4))     => (3 4 5 6)

(list-map mul 1.5 '(1 2 3 4)) => (1.5 3 4.5 6)

The number of arguments used is defined by the length of the first argument list. Missing arguments in other argument lists cause an error message. If an argument list has more members than necessary those will be ignored.



match

syntax: (match list-pattern list-match [true])

A pattern in list-pattern is matched against a list in list-match and the matching expressions are returned in a list. The three wild card characters ?, + and * can be used in list-pattern.

Wild card characters may occur in a nested fashion. match returns a list of matched expressions. For each ? a matching expression element is returned. For each plus + or star * a list containing the matched elements is returned. If the pattern cannot be matched against the list in list-match match returns nil.

Optionally the Boolean constant true can be supplied as a third parameter to make match working as in versions previous to 8.2.3 showing all list elements in the returned result.

example:
(match '(a ? c) '(a b c))         => (b)

(match '(a ? ?) '(a b c))         => (b c)

(match '(a ? c) '(a (x y z) c))   => ((x y z))

(match '(a ? c) '(a x y z c))     => nil


(match '(a * c) '(a x y z c))     => ((x y z))

(match '(a (b c ?) x y z) '(a (b c d) x y z))   => (d)

(match '(a (*) x ? z) '(a (b c d) x y z))       => ((b c d) y)

(match '(+) '())                  => nil

(match '(+) '(a))                 => ((a))

(match '(+) '(a b))               => ((a b))

(match '(a (*) x ? z) '(a () x y z))       => (() y)
(match '(a (+) x ? z) '(a () x y z))       => nil 

Note that the star * tries to grab the least number of elements possible, but match back-tracks and grabs more elements if a match cannot be found otherwise. This is true for the string and list version of match.

The plus + operator works similar to the start * operator, but must take at least one list element.

The following example shows how the matched expressions can be bound to variables.

(map set '(x y) (match '(a (? c) d *) '(a (b c) d e f)))

x => b
y => (e f)

Note that match for strings is deprecated. For more powerful string matching use regex, find or parse.



max

syntax: (max num-1 [num-2 ... ])

The expressions num-1 ... are evaluated and the largest result is returned.

example:
(max 4 6 2 3.54 7.1)    => 7.1

See also min.



member

syntax: (member exp list)

Searches for the element exp in the list list. If the element is a member of the list, a new list starting with the element found and the rest of the original list is constructed and returned. If nothing is found nil is returned.

example:
(set 'aList '(a b c d e f g h)) => (a b c d e f g h)
(member 'd aList)               => (d e f g h)
(member 55 aList)               => nil

See also the related slice and find.



min

syntax: (min num-1 [num-2 ... ])

The expressions num-1 ... are evaluated, and the smallest resulting number is returned.

example:
(min 4 6 2 3.54 7.1)    => 2

See also max.



mod

syntax: (mod num-1 num-2 [num-3 ... ])

Calculates the modular value of the numbers in num-1 and num-2. mod computes the remainder from the division of numerator num-i by denominator num-i+1. Specifically, the return value is numerator - n * denominator, where n is the quotient of numerator divided by denominator, rounded towards zero to an integer. The result has the same sign as the numerator and has magnitude less than the magnitude of the denominator.

example:
(mod 10.5 3.3)    =>    0.6

See also %, which works on integers only.



mul

syntax: (mul num-1 num-2 [num-3 ... ])

All expressions num-1 ... are evaluated and the product is calculated and returned. mul can perform mixed type arithmetic, but always returns floating point numbers. Any floating point calculation with NaN also returns NaN.

example:
(mul 1 2 3 4 5 1.1)     => 132
(mul 0.5 0.5)           => 0.25


multiply

syntax: (multiply matrix-A matrix-B)

Returns the matrix multiplication of matrices in matrix-A and matrix-B. If matrix A has the dimensions n by m and B the dimensions k by l the m and k must be equal and the result returned is an n by l matrix. multiply can perform mixed type arithmetic but the result is always in double precision floating point, even if all input values are integers.

example:
(set 'A '((1 2 3) (4 5 6)))
(set 'B '((1 2)(1 2)(1 2)))
(multiply A B)   =>  ((6 12) (15 30))

See also matrix operations transpose and invert.



name

syntax: (name symbol)

Returns the name of a symbol as a string but discarding the context prefix.

example:
(set 'ACTX:var 123)
(set 'sym 'ACTX:var)
(string sym)         => "ACTX:var"
(name sym)           => "var"


NaN?

syntax: (NaN? number )

Tests if the result of floating point math operation is a NaN. Certain floating point operations return a special IEEE 754 number format called a NaN for 'Not a Number'.

example:

(set 'x (sqrt -1))   => NaN
(add x 123)          => NaN
(mul x 123)          => NaN

(+ x 123)            => 123
(* x 123)            => 0

(> x 0)              => nil
(<= x 0)             => nil
(= x x)              => true
(NaN? x)             => true

Note that all floating point arithmetic operations with a NaN yield a NaN. All comparisons with NaN return nil, but true when comparing to itself. On the contrary comparison with itself would result not true when using ANSI 'C'.

Integer operations treat NaN as zero 0 values.



net-accept

syntax: (net-accept int-socket)

Accepts a connection on a socket previously put into listening mode. Returns a newly created socket handle for receiving and sending data on this connection.

example:
(set 'socket (net-listen 1234))
(net-accept socket)

Note that for ports less than 1024 newLISP must be started as superuser on UNIX like operating systems.

See also the examples server and client in the appendix.



net-close

syntax: (net-close int-socket)

Closes a network socket in int-socket. The socket was previously created by a net-connect or net-accept function. Returns true on success nil on failure.

example:
(net-close aSock)


net-connect

syntax: (net-connect str-remote-host int-port [str-mode [ int-ttl] ])

Connects to a remote host computer specified in str-remote-host and a specific port int-port. Returns a socket handle after having connected successful else returns nil.

example:
(define (finger nameSite , socket buffer user site)
  (set 'user (nth 0 (parse nameSite "@")))
  (set 'site (nth 1 (parse nameSite "@")))
  (set 'socket (net-connect site 79))
  (if socket
   (net-send socket (append user "\r\n")) 
   "no connection")
  (net-receive socket 'str 512)
  (print "\n" str "\n"))

The above program uses the finger service on a remote computer. This service returns information about an account holder on this computer. Some ISP installations and UNIX servers provide this service.

When executing:

(finger "johnDoe@someSite.com")

The program tries to connect to a server named "someSite.com" and sends the string "johnDoe". If "someSite.com" is running a finger service it sends back information about the account "johnDoe" on this server. In case a connection cannot be made the function returns the string "no connection".

nameSite is split up into the account name and host name parts. net-connect is used to connect to someSite.com and returns the socket handle which handles incoming data.

UDP communications

As a third parameter an option string str-mode containing the string "udp" or the string "u" can be specified to create a socket suited for UDP (User Datagram Protocol) communications. In UDP mode net-connect does not try to connect to the remote host, but only binds the socket to the remote address. A subsequent net-send will send a UDP packet containing that target address. If using net-send-to that address would be overwritten.

The functions net-receive and net-receive-from can also be used and will perform UDP communications. net-select and net-peek can be used to check for received data in a non-blocking fashion.

If data never gets through opening a client connection with net-connect then net-listen with the "udp" option may be the better choice to start the client side of the connection. net-listen binds a specific local address and port to the socket. When using net-connect the local address and port will be picket by the socket-stack functions of the host OS.

UDP multi-cast communications

When specifying "multi" or "m" as a third parameter for str-mode, a socket for UDP multi-cast communications will be created. Optionally a fourth parameter int-ttl can be specified as a TTL (time to live) value. If no int-ttl value is specified a value of 3 is assumed.

Note that specifying UDP multi-cast mode in net-connect not actually establishes a connection to the target multi-cast address, but only put the socket into UDP multi-casting mode. On the receiving side use net-listen together with the UDP multi-cast option.

example:
;; example client

(net-connect "226.0.0.1" 4096 "multi") => 3

(net-send-to "226.0.0.1" 4096 "hello" 3)

;; example server

(net-listen 4096 "226.0.0.1" "multi") => 5

(net-receive-from 5 20)               

=> ("hello" "192.168.1.94" 32769)

On the server side net-peek or net-select can be used for non-blocking communications. In the example the server would block until a datagram is received.

The address 226.0.0.1 is just on multi-cast address in the Class D range of multi-cast addresses from 224.0.0.0 to 239.255.255.255.

net-send and net-receive can be used instead of net-send-to and net-receive-from.

UDP broadcast communications

If the third parameter in str-mode contains the string "broadcast" or "b", UDP broadcast communications is set up. In this case the broadcast address ending in 255 is used.

example:
;; example client

(net-connect "192.168.2.255" 3000 "broadcast") => 3

(net-send 3 "hello")

;; example server

(net-listen 3000 "" "udp")  => 5

(net-receive 5 'buff 10)

buff => "hello"

;; or

(net-receive-from 5 10)

=> ("hello" "192.168.2.1" 46620)

Note that on the receiving side net-listen should be used with the default address specified by an empty string "". Broadcasts will not be received when specifiying a specific address. As with all UDP communications net-listen does not actually put the receiving side in listen mode, but rather sets up the sockets for the specific UDP mode.

net-select or net-peek can be used to check for incoming commications in a non-blocking fashion.



net-error

syntax: (net-error)

Retrieves the last error occurred when calling a net-* function. When any of the following functions returns nil, then net-error can be called for more information: net-accept, net-connect, net-listen, net-lookup, net-receive, net-receive-udp, net-select, net-send, net-send-udp and net-service. Functions communicating using sockets close the socket automatically and remove it from the net-sessions - list, this makes for a very robust API in situations of unreliable net connections. Calling any of these functions successfully clears the last error.

The following messages are returned:

 
 1: Cannot open socket
 2: Host name not known
 3: Not a valid service
 4: Connection failed
 5: Accept failed
 6: Connection closed
 7: Connection broken
 8: Socket send() failed
 9: Socket recv() failed
10: Cannot bind socket
11: Too much sockets in net-select
12: Listen failed
13: Badly formed IP
14: Select failed
15: Peek failed
16: Not a valid socket


net-listen

syntax: (net-listen int-port [str-ip-addr] [str-mode])

The function listens on a port specified in int-port. A call to net-listen returns immediately with a socket number, which is then used by the blocking net-accept function to wait for a connection. As soon as a connection is accepted net-accept returns a socket number which can be used to communicate with the connecting client.

example:
(set 'port 1234)
(set 'listen (net-listen port))
(unless listen (begin
        (print "listening failed\n")
        (exit)))
(print "Waiting for connection on: " port "\n")
(set 'connection (net-accept listen))
(if connection
        (while (net-receive connection 'buff 1024 "\n")
                (print buff)
                (if (= buff "\r\n") (exit)))
        (print "Could not connect\n"))

The example waits for a connections on port 1234, then reads incoming lines until an empty line is received. Note that listening on ports less then 1024 may require superuser access on UNIX systems.

Optionally an interface IP address or name can be specified in str-ip-addr to listen on a specified address on computers with more then one interface card.

;; listen on a specific address
(net-listen port "192.168.1.54") 

UDP communications

As a third parameter an option string str-mode containing the string "udp" or "u" can be specified to create a socket suited for UDP (User Datagram Protocol) communications. A socket created this way can be used directly with net-receive-from to wait for incoming UDP data without using net-accept which is only used in TCP communications. The net-receive-from call will block until a UDP data packet is received, or net-select or net-peek can be used to check for ready data in a non-blocking fashion. To send data back to the address and port received with net-receive-from use net-send-to.

Note that net-peer will not work, as UDP communications do not maintain a connected socket with address information.

(net-listen 1002 "192.168.1.120" "udp") 

(net-listen 1002 "" "udp") 

The first example listens on a specific network adapter. The second example listens on the default adapter. Both calls return a socket number which can be used in subsequent net-receive, net-receive-from, net-send-to, net-select or net-peek function calls.

Both, a UDP server and a UDP client can be set up using net-listen with the "udp" option. In this mode net-listen does not really listen as in TCP/IP communications, but just binds the socket to the local interface address and port.

See the examples: UDP client and UDP server in the manuals appendix for a working example.

Instead of using net-listen and the "udp" option the functions net-receive-udp and net-send-udp alone can be used for short transactions consisting only of one data packet.

The difference between both approaches is, that using net-listen net-select and net-peek can be used to facilitate non-blocking reading and the listening / reading socket is not closed but used again for subsequent reads. When using the net-receive-udp and net-send-udp pair both sides close sockets after send and receive.

UDP multi-cast communications

If the option string str-mode is specified as "multi" or "m" net-listen returns a socket suitable for multi-casting. In this case str-ip-addr contains one of the multi-cast addresses in the range 224.0.0.0 to 239.255.255.255. net-listen will register str-ip-addr as an address on which to receive multi-cast transmissions. This address should not be confused with the IP address of the server host.

example:
;; example client

(net-connect "226.0.0.1" 4096 "multi") => 3

(net-send-to "226.0.0.1" 4096 "hello" 3)


;; example server

(net-listen 4096 "226.0.0.1" "multi") => 5

(net-receive-from 5 20)               

=> ("hello" "192.168.1.94" 32769)

On the server side net-peek or net-select can be used for non-blocking communications. In the example the server would block until a datagram is received.

net-send and net-receive can be used instead of net-send-to and net-receive-from.



net-local

syntax: (net-local int-socket)

Returns the IP number and port of the local computer for a connection on a specific int-socket.

example:
(net-local 16)  =>  ("204.179.131.73" 1689)

See also net-peer for the IP number and port of the remote computer.



net-lookup

syntax: (net-lookup str-ip-number)
syntax: (net-lookup str-hostname)

Returns a hostname string from str-ip-number in IP dot format or returns the IP number in dot format from str-hostname:

example:
(net-lookup "209.24.120.224")    => "www.nuevatec.com"
(net-lookup "www.nuevatec.com")  => "209.24.120.224"


net-peek

syntax: (net-peek int-socket)

Returns the number of bytes ready for reading on the network socket int-socket. net-peek returns nil, if an error occurred or the connection is closed.

example:
(set 'aSock (net-connect "aserver.com" 123))
(while ( = (net-peek aSock) 0) (do-something-else))
(net-receive aSock 'buff 1024)

After connecting the program waits in a while loop until aSock can be read.



net-peer

syntax: (net-peer int-socket)

Returns the IP number and port of the remote computer for a connection on int-socket.

example:
(net-peer 16)  =>  ("192.100.81.100" 13)

See also net-local for the IP number and port of the local computer.



net-receive

syntax: (net-receive int-socket sym-buffer int-max-bytes [wait-string])

Receives data on the socket int-socket into a string contained in sym-buffer. A maximum of int-max-bytes are received. net-receive returns the number of bytes read. If the connection broke down nil is returned. The space reserved in sym-buffer is exactly the size of bytes read.

Note that net-receive is a blocking call and does not return until data arrived at int-socket. Use net-peek or net-select to find out if a socket is ready for reading.

Optionally a wait-string can be specified as a fourth parameter. net-receive then returns after a character or string of characters is received matching wait-string. The wait-string will be part of the data contained in sym-buffer.

example:
(define (gettime)
    (net-connect "netcom.com" 13)
    (net-receive socket 'buf 256)
    (print buf "\n")
    (net-close socket))

When calling gettime The program connects to port 13 of the server netcom.com. Port 13 is a date time service on most server installations. Upon connection the server sends a string containing date and time of day.

(define (net-receive-line socket sBuff)
        (net-receive socket sBuff 256 "\n"))

(set 'bytesReceived (net-receive-line socket 'sym))

The second example defines a new function net-receive-line which returns after a newline character (a string containing one character in this example) or 256 characters are received. The "\n" string is part of the contents of sBuff.

Note that net-receive with the fourth parameter specified is slower than the normal version because information is read character by character. In most situations the speed difference can be neglected.



net-receive-from

syntax: (net-receive-from int-socket int-max-size)

With net-receive-from non-blocking UDP communications can be setup. A socket in int-socket is previously opened with net-listen and "udp" option or previously opened with net-connect and "udp" option. int-max-size specifies the maximum byte which will be received. On Linux/BSD if more bytes are received those will be discarded. On Win32 net-receive-from will return nil and close the socket.

example:

;; listen on port 1001 on the default address
(net-listen 1001 "" "udp") => 1980 

;; optionally poll for arriving data with 100ms timeout
(while (not (net-select 1980 "r" 100000)) (do-something ...))

(net-receive-from 1980 20) => ("hello" "192.168.0.5" 3240)

;; send answer back to sender
(net-send-to "192.168.0.5" 3240 "hello to you" 1980)

(net-close 1980) ;; close socket

The second line in the example is optional. Without it the net-receive-from call would block until data arrives. A UDP server could be set up by listening and polling several ports and serving them as they receive data.

Note that net-receive could not be used in this case, because it does not return the address and port information of the sender, which is required to talk back. In UDP communications the data packed itself contains the address of the sender, not the socket over which communications takes place.

See also net-connect with "udp" option and net-send-to for sending UDP data packets over open connections.

For blocking short UDP transactions see net-send-udp and net-receive-udp.



net-receive-udp

syntax: (net-receive-udp int-port int-maxsize [int-microsec][str-addr-if])

Receives a UDP datagram packet on port int-port. A size of int-maxsize bytes is read. On Linux if more bytes arrive those are discarded. On Win32 is more bytes arrive net-receive-udp returns nil. net-receive-udp blocks until a datagram arrives or an optional timeout value in int-microsec expires. When sending up communications between datagram sender and receiver, the net-receive-udp statement has to be set up first.

No previous setup using net-listen or net-connect is necessary.

net-receive-udp returns a list containing the UDP datagram packet in a string followed by the IP- umber string of the sender and the port used.

example:
;; wait for datagram with maximum 20 bytes 
(net-receive-udp 1001 20) 

;; or
(net-receive-udp 1001 20 5000000)  ;; wait for max 5 seconds

                          
;; executed on remote computer
(net-send-udp "nuevatec.com" 1001 "Hello")  => 4 

;; returned from the net-receive-udp statement
      => ("Hello" "128.121.96.1" 3312)  

;; sending binary information
(net-send-udp "ahost.com" 2222 (pack "c c c c" 0 1 2 3))  
      => 4 

;; extracting the received info
(set 'buff (first (net-receive-udp 2222 10)))   

(print (unpack "c c c c" buff)) => (0 1 2 3)

See also net-send-udp for sending datagrams and pack and unpack for packing and unpacking binary information.

Optionally an interface IP address or name can be specified in str-addr-if to listen on a specified address on computers with more then one interface card. When specifying str-addr-if a timeout in int-wait- must also be specified.

As an alternative UDP communication can be set up using net-listen, or net-connect together with the "udp" option to make non-blocking data exchange possible with net-receive-from and net-send-to.



net-select

syntax: (net-select int-socket str-mode int-micro-seconds)
syntax: (net-select list-sockets str-mode int-micro-seconds)

In the first form net-select finds out if int-socket about the status of one socket. Depending on str-mode the socket can be checked if it is ready for reading writing or if the socket has an error-condition. A timeout value is given in int-micro-seconds.

In the second syntax net-select can check for a list of sockets in list-sockets.

The following value can be given for str-mode:

"read" or "r" to check if ready for reading or accepting.
"write" or "w" to check if ready for writing.
"exception" or "e" to check if socket has an error condition.

Using net-select read, send or accept operations can be handled without blocking. net-select waits for a socket to be ready for the value given in int-micro-seconds and then returns true or nil depending on the readiness of the socket. During the select loop other portions of the program can run. On error net-error is set.

example:
(set 'listen-socket (net-listen 1001))

; wait for connection
(while (not (net-select listen-socket "read" 1000))
        (if (net-error) (print (net-error))))
(set 'connection (net-accept listen-socket))
(net-send connection "hello")

; wait for incoming message
(while (not (net-select connection "read" 1000))
        (do-something)) 
(net-receive connection 'buff 1024)

Using net-select several listen and connection sockets can be watched and multiple connections can be handled. The following example would listen on two sockets and continue accepting and serving connections:

example:
(set 'listen-list '(1001 1002))

(while (not (net-error))
    (dolist (conn (net-select listen-list "r" 1000))
        (accept-connection conn)) ; build and accept-list

    (dolist (conn (net-select accept-list "r" 1000))
        (read-connection conn))   ; read on conn socket

    (dolist (conn (net-select accept-list "w" 1000))
        (write-connection conn))) ; write on conn socket
        

In the second syntax a list is returned with all sockets, which passed the test or the empty list if the timeout occurred. On error net-error is set.

Note that supplying a non-existing socket to net-select will cause an error set in net-error.



net-send

syntax: (net-send int-socket sym-buffer [int-num-bytes])
syntax: (net-send int-socket str-buffer [int-num-bytes])

Sends the contents of sym-buffer on the connection specified by int-socket. If int-num-bytes is specified up to int-num-bytes are sent. If int-num-bytes is not specified all contents in sym-buffer is sent. net-send returns the number of bytes sent or nil on failure.

net-send can use a string buffer directly without quoting a symbol.

example:

(set 'buf "hello there")
(net-send sock 'buf)
(net-send sock 'buf 5)

;; a string buffer can be used unquoted
(net-send sock buf) 
(net-send sock "bye bye")

The first net-send sends the string "hello there" the second net-send sends only the string "hello".



net-send-to

syntax: (net-send-to str-remotehost int-remoteport str-buffer int-socket

This function is used to send UDP data packets on open connections. The socket in int-socket is previously opened with a net-connect or net-listen function. Both opening functions must be used with their "udp" option. The host in str-remotehost can be specified either as a hostname or an IP-number string.

example:
(net-connect "asite.com" 1010 "udp") 

=> 2058   ;; get a UDP socket


(net-send-to "asite.com" 1010 "hello" 2058)

;; optionally poll for answer
(while (not (net-select 2058 "r" 100000)) 
    (do-something ....))

;; receive answering data from UDP server
(net-receive-from 2058 20) 

=> ("hello to you" "10.20.30.40" 1010)

(net-close 2058)

The second line in the example is optional. Without it the net-receive-from call would block until data arrives. With polling a client could maintain conversations with several UDP servers at the same time.

See also net-receive-from and net-listen with "udp" option.

For blocking short UDP transactions see and net-receive-udp.



net-send-udp

syntax: (net-send-udp str-remotehost int-remoteport str-buffer [bool])

Sends a UDP datagram to a host specified in str-remotehost and to a port in int-remoteport. The info sent is in str-buffer.

No previous setup using net-connect/net-listen is necessary. net-send-udp returns immediately with the number of bytes sent and close the connection. If no net-receive-udp statement is waiting at the receiving side, then the datagram sent is lost. When using datagram communications over insecure connections it is recommended to setup a simple protocol between sender and receiver to insure delivery. UDP communications by it self does not guarantee reliable delivery as TCP/IP does.

example:
(net-send-udp "somehost.com" 3333 "Hello") => 5

net-send-udp is also suitable for sending binary information, i.e. the zero character or other non-visible bytes. For a more comprehensive example see net-receive-udp.

Optionally the sending socket can be put in broadcast mode by specifying true in bool:

(net-send-udp "192.168.1.255" 2000 "Hello" true) => 5

The UDP datagram will be sent to all nodes on the 192.168.1 network. Note that on some operating systems the network mask 255 alone without the true option will enable broadcast mode.

As an alternative net-connect and the "udp" option together with net-send-to can be used to talk to a UDP listener in a non-blocking fashion.



net-service

syntax: (net-service str-service str-protocol)

Makes a lookup in the services database and returns the standard port number for this service. On failure returns nil.

example:
(net-service "ftp" "tcp")      => 21
(net-service "finger" "tcp")   => 79


net-sessions

syntax: (net-sessions)

Returns a list of active listening and connection sockets.



new

syntax: (new sym-source-context sym-target-context [true])
syntax: (new sym-context)

In the first sym-source-context is the name of an existing context and sym-target-context is the name of a new context to be created just like the original, with the same names of variables and user-defined functions. If the context in sym-target-context already exists, then new symbols and definitions are added. Existing symbols are overwritten when the true option is specified, else the content of existing symbols will remain. This makes possible mixins of context objects. new returns the target context.

In the second syntax the existing context in sym-source-context gets copied into the current context as target context.

All references to symbols in the originating context will be translated to references in the target context. This way all functions and data structures referring to symbols in the original context will now refer to symbols in the target context.

example:
(new CTX 'CTX-2)      => CTX-2   

; force overwrite of existing symbols
(new CTX MyCTX true)  => MyCTX   

(set 'CTX:x 123)
(new CTX)             => MAIN ; copies x into MAIN
x                     => 123

(map new '(Ct-a Ct-b Ct-c))      ; merge into current

The first line in the example creates a new context CTX-2 having the exact structure as the original one. Note that CTX is not quoted because contexts evaluate to themselves but CTX-2 has to be quoted because it does not exist yet.

The second line merges the context CTX into MyCTX, any existing symbols of same name in MyCTX will be overwritten. Because MyCTX already exists, the quote before the context symbol can be omitted.

The last lines show how a foreign context does get merged into the current one and how map can be used to merge a list of contexts.

Context symbols need not to be mentioned explicitly but can be contained in variables:

example:
(set 'foo:x 123)
(set 'bar:y 999)

(set 'ctxa foo)
(set 'ctxb bar)

(new ctxa ctxb)

bar:x => 123
bar:y => 999)

The example refers to contexts in variables and merges context foo into into bar.

See also the function def-new for moving and merging single functions instead of entire contexts. See the function context for a more comprehensive example of new.



not

syntax: (not exp)

If exp evaluates to nil then true is returned else nil.

example:
(not true)              => nil
(not nil)               => true
(not '())               => true
(not (< 1 10))          => nil
(not (not (< 1 10)))    => true


normal

syntax: (normal float-mean float-stdev int-n)
syntax: (normal float-mean float-stdev)

In the first form normal returns a list if int-n of random continuously distributed floating point numbers with a mean of float-mean and a standard deviation of float-stdev. The random generator, which is used internally, can be seeded using seed.

example:
(normal 10 3 10)  => 
    (7 6.563476562 11.93945312 6.153320312 9.98828125
     7.984375 10.17871094 6.58984375 9.42578125 12.11230469)

In the second form normal returns a single normal distributed floating point number:

(normal 0 1) => 0.6630859375

See also random and rand for evenly distributed numbers, amb for randomizing evaluation in a list of expressions and seed for setting a different start point for pseudo random number generation.



now

syntax: (now [int-offset])

Returns information about the current date and time in a list of integer numbers. Optionally a timezone offset can be specified in int-offset in minutes, which is added or subtracted to the time before splitting it into its date values.

example:
(now)      

=> (2002 2 27 18 21 30 140000 57 3 300 0)

(apply date-value (now))  => 1014834090

The numbers give information about the following date time fields:

    year                (Gregorian calendar)

    month               (1 - 12)

    day                 (1 - 31)

    hour                (0 - 23) (UCT)

    minute              (0 - 59)

    second              (0 - 59)

    microsecond         (0 - 999999) 
                        OS-specific, millisecond resolution)

    day of current year (Jan 1st is 1)

    day of current week (1 to 7, starting Sunday)

    time zone offset in minutes west of GMT

    daylight savings time flag (0 or 1 on Linux/UNIX
                                bias in minutes on Win32)

The second example returns the UCT time value of seconds after 1970-1-1.

Note that hours are given in Universal Coordinated Time (UCT) from 0 to 23 and not adjusted for the local time zone. The resolution of the microsecond field depends on the operating system and platforms. On some platforms the last 3 digits of the microseconds field are always 0 (zero).

See also date, date-value, time and time-of-day.

Note that on SOLARIS the returned time offset value is not working correctly in some versions/platforms and may contain garbage values.

Note than on many platforms the daylight savings flag is not active and 0 even during daylight savings time.



nper

syntax: (nper num-interest num-pmt num-pv [num-fv int-type])

Calculates the number of payments required to pay a loan of num-pv with a constant interest rate of num-interest and payment num-pmt. The future value of the loan is assumed to be 0.0, if num-fv is omitted. If payment is at the end of the period int-type is 0 else 1. If int-type is omitted 0 is assumed.

example:
(nper (div 0.07 12) 775.30 -100000) => 239.9992828

The examples calculates the number of monthly payments required to pay a loan of $100,000 and a yearly interest rate of 7% with payments of $775.30.

See also fv, irr, npv, pmt and pv.



npv

syntax: (npv num-interest list-values)

Calculates the net present value of an investment with a fixed interest rate num-interest and a series of future payments and income in list-values. Payments are represented by negative values in list-values while income is represented by positive values in list-values

example:
(npv 0.1 '(1000 1000 1000)) 
    => 2486.851991

(npv 0.1 '(-2486.851991 1000 1000 1000)) 
    => -1.434386832e-08 ; ~ 0.0 (zero)

In the example an initial investment of $2481.85 would allow to draw income of $1000 after the end of the 1st, 2nd and 3rd year.

See also fv, irr, nper, pmt and pv.



nth

syntax: (nth int-index-1 [int-index-2 ...] list)
syntax: (nth int-index-1 [int-index-2 ...] array)
syntax: (nth int-offset str)

In the first version nth evaluates int-index to an index into list and returns the element found at the index. See also Indexing elements of strings and lists. Multiple indices may be specified to recursively access elements in nested lists. If there are more indices than nesting levels found, these indices are ignored. Up to 16 indices can be specified.

example:
(nth 0 '(a b c))      => a

(set 'names '(john martha robert alex)) 
        => (john martha robert alex)

(nth 2 names)         => robert

(nth -1 names)        => alex

(set 'persons '((john 30) (martha 120) ((john doe) 17)))

(nth 1 1 persons)     => 120

(nth 2 0 1 persons)   => doe

(nth -2 0 persons)    => martha

(nth 10 persons)      => ((john doe) 17)) ;; out of bounds
(nth -5 person)       => (john 30) ;; out of bounds

In the second version nth works on arrays just like on lists, but indices which are out of bounds will cause an error message.

example:
(set 'aArray (array 2 3 '(a b c d e f))) 

=> ((a b c) (d e f))


(nth 1 aArray)       =>  (d e f)

(nth 1 0 aArray)     => d

(nth -5 -3 aArray)   => out of bounds error

(nth 10 10) aArray)  => out of bounds error

In the third version nth returns the character found at the position int-index in str and returns it as a string.

example:
(nth 0 "newLISP")    => "n"

(nth 3 "newLISP")    => "L"

(nth -1 "newLISP")   => "P"

See also set-nth for other functions suitable for accessing multidimensional nested lists and arrays. See push and pop for other functions accessing multidimensional lists.

Note that since version 8.5 implicit indexing can be used as shorter form of nth. Implicit indexing is slightly faster than conventional indexing and can take an unlimited number of indices.

Note that nth works on character boundaries rather than byte boundaries when using the UTF-8 enabled version of newLISP.



nth-set

syntax: (nth-set int-nth-1 [ int-nth-2 ... ] list exp-replacement)
syntax: (nth-set int-nth-1 [ int-nth-2 ... ] array exp-replacement)
syntax: (nth-set int-nth-1 str str-replacement)

Works exactly like set-nth but returns the replaced element instead of the whole changed list expression. nth-set is much faster when replacing elements in larger lists or arrays. Up to 16 indices can be specified.



open

syntax: (open str-path-file str-access-mode [str-option])

The str-path-file is a file name, str-access-mode a string specifying the file access mode. open returns an integer, which is a file handle to be used on subsequent read or write operations on the file. On failure open returns nil. The access mode "write" creates the file if it doesn't exist, or it truncates an existing file to 0 bytes length.

The following strings are legal access modes:

"read" or "r" for read only access
"write" or "w" for write only access
"update" or "u" for read/write access
"append" or "a" for append read/write access
example:
(device (open "newfile.data" "write"))   => 5
(print "hello world\n")                  => "hello world"
(close (device))                         => 5

(set 'aFile (open "newfile.data" "read"))
(seek aFile 6)
(set 'inChar (read-char aFile))
(print inChar "\n")
(close aFile)

The first example uses open to set the device for print and writes the word "hello world" into the file newfile.data. The second example reads a byte value at offset 6 in the same file (ASCII value of 'w' : 119). Note that using close on (device) automatically resets device to 0 (zero).

As an additional str-option "non-block" or "n" can be specified after the "read" or "write" option. The non-blocking mode is only available on UNIX systems and can be useful when opening named pipes but is not required to do I/O on named pipes.

To create a named pipe in newLISP the exec or import function can be used:

example:
(exec "mkfifo myfifo")

;; or alternatively

(import "/lib/libc.so.6" "mkfifo")
(mkfifo "/tmp/myfifo" 0777)

The named pipe can now be used like a file with open, read-buffer and write-buffer.



or

syntax: (or exp-1 [exp-2 exp-3 ...])

Expressions exp-x are evaluated from left to right, until finding a result which does not evaluate to nil, or the empty list (), The result is the return value of the or expression.

example:
(set 'x 10)
(or (> x 100) (= x 10)) => true
(or "hello" (> x 100) (= x 10)) => "hello"
(or '())                   => nil
(or true)                  => true
(or)                       => nil


pack

syntax: (pack str-format exp-1 [exp-2 ... exp-n])

Pack one or more expressions exp-1 to exp-n into a binary format specified in the format string str-format and returns the binary structure in a string buffer. A symmetrical unpack function is used to unpack. pack and unpack are useful when reading and writing binary files (see read-buffer and write-buffer) or when unpacking binary structures from return values of imported 'C' functions with import.

The following characters are used int str-format:

c a signed 8 bit number
b an unsigned 8 bit number
d a signed 16 bit short number
u an unsigned 16 bit short number
ld a signed 32 bit long number
lu an unsigned 32 bit long number
f a float in 32 bit representation
lf a double float in 64 bit representation
sn a string of n null padded ASCII characters
nn n null characters
> switch to big endian byte order
< switch to little endian byte order

Note that newLISP only supports 32 bit signed integers and treats lu and ld the same way internally.

pack will convert all floats to integer types when passed to b,c,d,ld or lu formats. pack will also convert from integer to float type when passing integers to f and lf formats.

example:
(pack "c c c" 65 66 67) => "ABC"
(unpack "c c c" "ABC") => (65 66 67)

(pack "c c c" 0 1 2) => "\000\001\002"
(unpack "c c c" "\000\001\002") => (0 1 2)

(set 's (pack "c d u" 10 12345 56789))
(unpack "c d u" s) => (10 12345 56789)

(set 's (pack "s10 f" "result" 1.23))
(unpack "s10 f" s) => ("result\000\000\000\000" 1.230000019)

(set 's (pack "s3 lf" "result" 1.23))
(unpack "s3 f" s) => ("res" 1.23)

(set 's (pack "c n7 c" 11 22))
(unpack "c n7 c" s) => (11 22))

(unpack "b" (pack "b" -1.0)) => (255)
(unpack "f" (pack "f" 123)) => (123)

The last two statement shows how floating point numbers are converted to integers when required by the format spec.

The > and < specifiers ca be used to switch between little endian and big endian byte order when packing or unpacking:

(pack "d" 1)    => "\001\000"
(pack ">d" 1)   => "\000\001"

(pack "ld" 1)   => "\001\000\000\000"
(pack "<ld" 1)  => "\000\000\000\001"

Switching the byte order will affect all number formats with 16, 32 or 64 bit sizes.

The pack and unpack format need not to be the same; as in the following example:

(set 's (pack "s3" "ABC"))
(unpack "c c c" s) => (65 66 67)

The examples show spaces between the format specifiers. These are not required but can be used to improve readability.

See also address, get-int, get-char, get-string and unpack.



parse

syntax: (parse str-data [str-break int-option])

The string which results from evaluating str-data is broken up into string tokens which are returned in a list. When no str-break is given, parse tokenizes according newLISP's internal parse rules. A string may be specified in str-break for tokenizing only at the occurrence of string. If an int-option number is specified, a regular expression pattern may be specified in str-break.

When str-break is not specified, the maximum token size is 2048 for quoted strings and 256 for identifiers. In this case newLISP uses the same faster tokenizer it uses for parsing lisp source. If str-data is specified, there is no limitation on the length of tokens. A different algorithm is used splitting the source string str-data at the string in str-break.

example:
(parse "hello how are you")   => ("hello" "how" "are" "you")

(parse "one:two:three" ":")   => ("one" "two" "three")

(parse "one--two--three" "--") => ("one" "two" "three")

(parse "one-two--three---four" "-+" 0)

    => ("one" "two" "three" "four")

(parse "hello regular   expression 1, 2, 3" {,\s*|\s+} 0)

    => ("hello" "regular" "expression" "1" "2" "3")

The last two examples show a regular expression as the break string with the default option 0 (zero). Instead of curly brackets {, } quotes could have been used to limit the pattern, but in that case double backslashes would have to be used inside the pattern. The last pattern could be used for parsing CVS files. For option numbers for regular expressions see regex.

parse will return empty fields around separators as empty strings:

(parse "1,2,3," ",") => ("1" "2" "3" "")
(parse "1,,,4" ",")  => ("1" "" "" "4")
(parse "," ",")      => ("" "")

This behavior is needed when parsing records with empty fields.

See also regex for breaking up strings and find, regex, replace and search for other functions using regular expressions.



pipe

syntax: (pipe)

pipe creates an inter-process communications pipe and returns the read and write handles to it in a list.

example:

(pipe)    => (3 4)   ; 3 for read, 4 for writing

The pipe handles can be passed on to a child process or thread launched via process or fork for inter process communications.

Note that the pipe does not block on writing into it, but does block reading until bytes are available. A read-line blocks until a newline character is received. A read-buffer blocks when fewer characters than specified are available from a pipe that has not had the writing end closed by all processes.

More than one pipe can be opened if required.

newLISP can also use named pipes. See the description of open for further information.



pmt

syntax: (parse num-interest num-periods num-principal [num-future-value int-type])

Calculates the payment for a loan based on a constant interest num-interest and constant payments over num-periods time periods. num-future-value is the value of the loan at the end (typically 0.0). When paying at the end of each period num-type is 0 else 1. If omitted int-type is assumed to be 0 for payment at the end of a period.

example:
(pmt (div 0.07 12) 240 100000) => -775.2989356

The example calculates the payment of $775.30 for a loan of $100,000 and yearly interest rate of 7% calculated monthly and paid in 20 years or 20 * 12 = 240 monthly periods. The example illustrates the typical way payment is calculated for mortgages.

See also fv, irr, nper, npv, and pv.



pop

syntax: (pop list [int-index-1 [int-index-2 ...]])
syntax: (pop list [list-indices])

An element is extracted from the list found evaluating list. If a second parameter is present, the element at the index in int-index is extracted and returned. See also Indexing elements of strings and lists.

In the second version indices are specified in a list list-indices. This way pop works easily together with ref, which returns a list of indices.

pop changes the contents of the target list. The popped element is returned.

example:
(set 'pList '((f g) a b c "hello" d e 10))

(pop pList)        => (f g)
(pop pList)        => a
plist              => (b c "hello" d e 10)

(pop pList 3)      => d
(pop pList 100)    => 10
pList              => (b c "hello" e)

(pop pList -1)     => e
pList              => (b c "hello")

(pop pList -2)     => c
pList              => (b "hello")

(set 'pList '(a 2 (x y (p q) z)))

(pop pList -1 2 0) => p

; use indices in a list
(set 'pList '(a b (c d () e)))

(push 'x pList '(2 2 0))   => x
pList                      => (a b (c d (x) e))

(ref 'x pList)             => (2 2 0)

(pop pList '(2 2 0))       => x

See also push, which is the inverse operation to pop, and set-nth and nth, which can take multiple dimension indices into lists.



post-url

syntax: (post-url str-url str-content [str-content-type] )

A HTTP POST request is sent to the URL in str-url. POST requests are used to post information collected from web entry forms to a website. Most of the time the function post-url mimics what an Internet Web browser would do when sending information collected in an HTML form to a server, but it can also be used to upload files (see a HTTP reference). The function returns the page returned from the server in a string.

example:
(post-url "http://somesite.com/login.pl" 
          "user=johnDoe&pass=12345" 
          "application/x-www-form-urlencoded")

;; assumes default content type
(post-url "http://somesite.com/login.pl"
          "user=johnDoe&pass=12345")

The above example uploads a user name and password using a special format called application/x-www-form-urlencoded. Other content-types are possible using post-url to post other types of information, for example, files or binary data. See an HTTP reference for other content-type specifications and data encoding formats. When omitting the last parameter, post-url assumes application/x-www-form-urlencoded as the default content type.

See also get-url and put-url.



pow

syntax: (pow num-1 num-2 [num-3 ...])

Calculates num-1 to the power of num-2 and so forth.

example:
(pow 100 2)     => 10000
(pow 100 0.5)   => 10
(pow 100 0.5 3) => 1000


pretty-print

syntax: (pretty-print [int-length[str-tab]])

pretty-print reformats expressions for print, save or source. The first parameter int-length specifies the maximum line length, str-tab specifies the string used to indent lines. All parameters are optional. pretty-print returns the current settings or the new settings when one or both parameters are specified.

example:
(pretty-print)         => (64 " ") ;; default setting

(pretty-print 90 "\t") => (90 "\t")

(pretty-print 100)     => (100 "\t") 

The first example reports the default settings of 64 for the maximum line length and a TAB character for indenting. The third example changes the line length only.

Note that pretty-print cannot be used to prevent line breaks from being printed. To completely suppress pretty printing use the function string to convert the expression to a raw unformatted string i.e.:

example:
;; print without formatting

(print (string my-expression))	


primitive?

syntax: (primitive? exp)

exp is evaluated and tested if a primitive symbol. true or nil is returned, depending on the result.

example:
(set 'var define)
(primitive? var)        => true


print

syntax: (print exp-1 [exp-2 ... ])

All exp-1 ... are evaluated and printed to the current I/O device, which is the console window by default. See the built-in function device on how to specify a different I/O device.

List expressions are indented by the nesting levels of their opening parentheses.

Several special characters may be included in strings encoded with the escape character \:

\n the line feed character (ASCII 10)
\r the carriage return character (ASCII 13)
\t the tab character (ASCII 9)
\nnn where nnn is a decimal ASCII code between 000 and 255

example:
(print (set 'res (+ 1 2 3))) 
(print "the result is" res "\n")

"\065\066\067" => "ABC"

To finish printing with a line feed use println.



println

syntax: (println exp-1 [exp-2 ... ])

All exp-1 ... are evaluated and printed to the current I/O device, which is the console window by default. At the end a line feed is printed. See the built-in function device on how to specify a different I/O device. println works just like print but emits a line feed character at the end.

See also write-line print.



prob-chi2

syntax: (prob-chi2 num-chi2 num-df )

Returns the probability Q of an observed Chi-2 statistic in num-chi2 with num-df degrees of freedom to be equal or greater. prob-chi2 is derived from the Incomplete Gamma function gammai.

example:
(prob-chi2 10 6) => 0.1246520195


prob-z

syntax: (prob-z num-z)

Returns the probability of num-z not to exceed the observed value where num-z is a normal distributed value with a mean of 0.0 and a standard deviation of 1.0.

example:
(prob-z 0.0) => 0.5


process

syntax: (process str-command)
syntax: (process str-command int-pipe-in int-pipe-out [int-win32-option])

Using the first syntax process works similar to  !  but in a non-blocking fashion, launching a child-process specified in str-command and then returning immediately with the child process id or nil if a child process could not be created.

example:

(process "notepad") => 1894

In the second syntax standard input and output of the created process can be redirected to pipe handles. When remapping standard I/O of the launched application to a pipe, it is possible to communicate with the other application via write-line and read-line or write-buffer and read-buffer statements:

example:
;; Linux/UNIX
;; create pipes
(map set '(myin bcout) (pipe))
(map set '(bcin myout) (pipe))   

;; launch UNIX 'bc' calculator application
(process "bc" bcin bcout)

(write-buffer myout "3 + 4\n")   ; bc expects a linefeed

(read-line myin)  => "7"


;; bc can use bignums with arbitrary precision

(write-buffer myout "123456789012345 * 123456789012345\n")

(read-line myin)  => "15241578753238669120562399025"

;; Win32
(map set '(myin cmdout) (pipe))
(map set '(cmdin myout) (pipe))

(process "cmd" cmdin cmdout)     ; Win32 command shell

(write-line "dir c:\\*.bat" myout)

(read-buffer myin 'buff 2000)

(println buff)                   ; directory listing

On Win32 versions of newLISP a fourth optional parameter can be specified to control the display status of the application with int-win32-option. By default this is 1 for showing the applications windows, 0 for hiding it and 2 for showing it minimized on the Windows launch bar.

Not all applications usable interactive in a console are suited for remapping their standard I/O channels. Some times only one channel, in our out, can be remapped. In this case specify 0 zero for the unused channel. The following statement would only use the launched application's output:

(process "app" 0 out)

Two pipes should be used normally: one for communications to the child process and the other one for communications from the child process.

See also pipe and share for inter-process communications and semaphore for synchronization of several processes. See fork for starting separate newLISP threads on UNIX or Win32/Cygwin.



push

syntax: (push exp list [int-index-1[int-index-2 ...]])
syntax: (push exp list [list-indices])

The value of exp is inserted into the list list. If int-index is present, the element is inserted at that index. If the index is absent, the element is inserted at index 0, the first element. push is a destructive operation, which changes the contents of the target list. The element inserted is returned. See also Indexing elements of strings and lists.

If more than one int-index is present, the indices are used to access a nested list structure. Improper indices - those not matching list elements - are discarded.

The second version takes a list of list-indices but is otherwise identical to the first. In this way push works easily together with ref which returns a list of indices.

If list does not contain a list, list is automatically initialized to an empty list () before inserting exp.

Using repeatedly push to the end of a list using one int-index of -1 is optimized and as fast as pushing in front of a list with no index at all. This can be used to efficiently grow a list.

example:
; inserting in front
(set 'pList '(b c))     => (b c)
(push 'a pList)         => a
pList                   => (a b c)

; insert at index
(push "hello" pList 2)  => "hello"
pList                   => (a b "hello" c)

; optimized appending at the end
(push 'z pList -1)      => z    
pList                   => (a b "hello" c z)

; inserting lists in lists
(push '(f g) pList)     => (f g)
pList                   => ((f g) a b "hello" c z)

; inserting at negative index
(push 'x pList -3)      => x
pList                   => ((f g) a b "hello" x c z)

; using multiple indices
(push 'h pList 0 -1)    => h
pList                   => ((f g h) a b "hello" x c z)

; use indices in a list
(set 'pList '(a b (c d () e)))

(push 'x pList '(2 2 0))   => x
pList                      => (a b (c d (x) e))

(ref 'x pList)             => (2 2 0)

(pop pList '(2 2 0))       => x


; push on uninitialized symbol
; or symbol not containing a list
aVar                    => nil 

(push 999 aVar)         => 999 

aVar                    => (999)

See also pop, which is the inverse operation to push, and set-nth, nth-set and nth, which all can take multiple dimension indices into lists.



put-url

syntax: (put-url str-url str-content)

The HTTP PUT protocol is used to transfer information in str-content to a file specified in str-url. The lesser known HTTP PUT mode is frequently used for transferring web pages from HTML editors to Web servers. In order to use PUT mode the web server's software must be configured correctly. On the Apache web server use the 'Script PUT' directive in the section where directory access rights are configured.

example:

(put-url "http://asite.com/myFile.txt" "Hi there")

(put-url "http://asite.com/webpage.html" 
    (read-file "webpage.html"))

The first example creates a file myFile.txt on the target server and store the text string 'Hi there' in it. In the second example a local file webpage.html is transferred to asite.com.

On an Apache web server the following could be configured in httpd.conf.

example:
<Directory /www/htdocs>
Options All
Script PUT /cgi-bin/put.cgi
</directory>

The script put.cgi would contain code to receive content via STDIN from the web server. The following is a working put.cgi written in newLISP for the Apache web server:

example:
#!/usr/home/johndoe/bin/newlisp
#
#
# get PUT method data from CGI STDIN 
# and write data to a file specified
# int the PUT request
# 
#


(print "Content-type: text/html\n\n")

(set 'cnt 0)
(set 'result "")

(if (= "PUT" (env "REQUEST_METHOD"))
    (begin
      (set 'len (integer (env "CONTENT_LENGTH")))
      (while (> cnt len)
          (set 'n (read-buffer (device) 'buffer len))
          (if (not n) (set 'cnt len) 
            (begin 
              (inc 'cnt n)
              (set 'result (append result buffer)))))
      (set 'path (append 
              "/usr/home/johndoe" 
              (env "PATH_TRANSLATED")))
      (set 'path (append path ".txt")) ;; security
      (write-file path result)))

(exit)

Note that the script appends ".txt" to the path to avoid the CGI execution of uploaded malicious scripts. Note also, that the 2 lines where the file path is composed may work differently in your web server environment. Check environment variables passed by your web server for composition of the right file path.

put-url returns content returned by the put.cgi script.

See also the functions get-url and post-url, which also can be used to upload files when formatting form data as "multipart/form-data".



pv

syntax: (pv num-int num-nper num-pmt [num-fv int-type])

Calculates the present value of a loan with constant interest rate num-interest and constant payment num-pmt after num-nper number of payments. The future value num-pmt is assumed 0.0 if omitted. If payment is at the end of each period 0 is assumed for int-type else 1.

example:
(pv (div 0.07 12) 240 775.30)) => 100000.1373

In the example a loan, which would be paid off (future value = 0.0) in 240 payments of $775.30 and a constant interest rate of 7% per year, would start out at $1000,000.14.

See also fv, irr, nper, npv, and pmt.



quote

syntax: (quote exp)

exp is returned without being evaluated, as if quoted.

example:
(quote x)                 => x
(quote 123)               => 123
(quote (a b c))           => (a b c)
(= (quote x) 'x)          => true


quote?

syntax: (quote? exp)

exp is evaluated and tested if quoted. true or nil is returned depending on the result.

example:
(set 'var ''x)          => 'x
(quote? var)            => true

Note that in the set statement ''x is quoted twice because its first quote is lost during the evaluation of the set assignment.



rand

syntax: (rand int-range [int-N])

The expression in int-range is evaluated and a random number in the range 0 - (int-range - 1) is generated. When passing 0 (zero) the internal random generator is initialized using the current value of the time function. Optionally a second parameter can be specified to return a list of length int-N of random numbers.

example:
(dotimes (x 100) (print (rand 2))

(rand 3 100) => (2 0 1 1 2 0 .... )

This first line in the example prints equally distributed 0's and 1's. The second line produces a list of 100 integers: 0,1 and 2 equally distributed. See also random and normal for the generation of floating point random numbers and seed for varying the initial seed for random number generation.



random

syntax: (random float-offset float-scale int-n)
syntax: (random float-offset float-scale)

In the first form random returns a list of int-n evenly distributed floating point numbers scaled (multiplied) by float-scale and added offset of float-offset. The starting point of the internal random generator can be seeded using seed.

example:
(random 0 1 10) => 
    (0.10898973 0.69823783 0.56434872 0.041507289 0.16516733
     0.81540917 0.68553784 0.76471068 0.82314585 0.95924564)

When used in the second form, random returns a single evenly distributed number:

(random 10 5) => 11.0971

See also normal and rand.



read-buffer

syntax: (read-buffer int-file sym-buffer int-size [str-wait])

Reads from a file specified in int-file a maximum of int-size bytes into a buffer in sym-buffer. Any data referenced by the symbol sym-buffer previous to reading is deleted. newLISP automatically allocates a correct sized buffer in sym-buffer if less the int-size is read. The handle in int-file was previously returned from an open statement. The symbol sym-buffer contains data of type string after the read operation.

Optionally a string to wait for can be specified in str-wait. read-buffer will read a maximum amount of bytes specified in int-size or return earlier if str-wait was found in the data. The wait-string is part of the returned data.

Returns the number of bytes read or nil on failure.

example:
(set 'handle (open "aFile.ext" "read"))
(read-buffer handle 'buff 200)

Reads 200 bytes in to a symbol buff from the file aFile.ext.

(read-buffer handle 'buff 1000 "password:")

Reads 1000 bytes or until the string password: is encountered. The string password: will be part of the data returned.

See also write-buffer.



read-char

syntax: (read-char int-file)

Reads a byte from a file specified by the file handle in int-file. The file handle is obtained from a previous open operation. Each read-char advances the file pointer by one byte. On end of file nil is returned.

example:
(define (slow-file-copy from-file to-file)
(set 'in-file (open from-file "read"))
(set 'out-file (open to-file "write"))
(while (set 'chr (read-char in-file))
    (write-char out-file chr))
    (close in-file)
    (close out-file)
    "finished")

See read-line and device for reading whole text lines at a time. Note that newLISP supplies a fast built-in function copy-file for copying files.

See also write-char.



read-file

syntax: (read-file str-file-name)

Reads a file in str-file-name in one swoop and returns a string buffer containing the data.

example:
(write-file "myfile.enc" 
    (encrypt (read-file "/home/lisp/myFile") "secret"))

The file myfile is read, then encrypted using the password "secret" and written back into a new file "myfile.enc" in the current directory.

See also write-file.



read-key

syntax: (read-key)

Reads a key from the keyboard and returns an integer value. For navigation keys more than one read-key calls have to be made. For keys representing ASCII characters the return value is the same on all OSs but for navigation keys and other control sequences like function keys, the return values may differ on different OSs and configurations.

example:
(read-key)     => 97   ; after hitting the A key
(read-key)     => 65   ; after hitting the shifted A key
(read-key)     => 10   ; after hitting [enter] on Linux
(read-key)     => 13   ; after hitting [enter]on Win32

(while (!= (set 'c (read-key)) 27) (println c))

The last example an be used to check return sequences from navigation and function keys. The [ESC] key is used to break out of the while loop.

Note that read-key will not work from the newLISP-tk front-end or any other application running newLISP over a TCP/IP port connection, and read-key will not work on Mac OSX.



read-line

syntax: (read-line [int-file])

Reads a string from the current I/O device delimited by a line feed character (ASCII 10). There is no limitation to the length of the string which can be read. The line-feed character is not part of the returned string. The line always breaks on a line-feed and swallows the line feed. A line breaks on carriage-return (ASCII 13) only if followed by line feed and both characters are discarded. An ASCII 13 alone only breaks and is swallowed if it is last character in the stream.

By default the current device is the keyboard (device 0). See the built-in function device for specifying a different I/O device (for example, a file). Optionally a file handle can be specified in int-file obtained from a previous open statement.

The last buffer contents from a read-line operation can be retrieved using current-line.

example:
(print "Enter a num:")
(set 'num (integer (read-line)))

(set 'in-file (open "afile.dat" "read"))
(while (read-line in-file)
        (write-line))   
(close in-file)

The first example reads input from the keyboard and converts it to a number. In the second example a file is read, line by line and displayed on the screen. The write-line statement takes advantage of the fact that the result from the last read-line operation is stored in a system internal buffer. When using write-line without argument, it writes the contents of the last read-line buffer to the screen.

See also current-line for retrieving this buffer.



ref

syntax: (ref exp list)

ref searches for expression exp in list and returns a list of integer indices or an empty list if the exp cannot be found. ref can work together with push and pop, which also can take lists of indices.

example:

(set 'pList '(a b (c d () e)))

(push 'x pList '(2 2 0))   => x
pList                      => (a b (c d (x) e))

(ref 'x pList)             => (2 2 0)

(ref '(x) pList)           => (2 2)

(ref '(c d (x) e) pList)   => (2)

(ref 'foo pList)           => ()

(pop pList '(2 2 0))       => x

Using just push, pop and ref any list can be constructed or modified at any place using just one statement.



regex

syntax: (regex str-pattern str-text [int-option])

Performs a Perl Compatible Regular Expression (PCRE) search on str-text with the pattern specified in str-pattern. The same regular expression pattern matching is also supported in the functions find, parse, replace and search when using these functions on strings.

regex returns nil if no match was found. It returns a list with the matched strings and substrings and the start and length of each string inside the text. The offset numbers can be used for subsequent processing.

regex also sets the variables $0, $1, $2 ... etc. to the expression and sub-expressions found. These variables or their equivalent expressions ($ 0) ($ 1) ($ 2) ... can be used in other LISP expressions just like any other symbol in newLISP for further processing.

example:
(regex "b+" "aaaabbbaaaa")          => ("bbb" 4 3)

; case-insensitive search option 1
(regex "b+" "AAAABBBAAAA" 1)        => ("BBB" 4 3) 

(regex "[bB]+" "AAAABbBAAAA" )      => ("BbB" 4 3)

(regex "http://(.*):(.*)" "http://nuevatec.com:80") 

=>
("http://nuevatec.com:80" 0 22 "nuevatec.com" 7 12 "80" 20 2)

$0 => "http://nuevatec.com:80"
$1 => "nuevatec.com"
$2 => "80"

(dotimes (i 3) (println ($ i)))
=>
http://nuevatec.com:80
nuevatec.com
80

The second example shows the usage of extra options. The following example is more complex parsing out two sub expressions, which where marked by parenthesis in the search pattern. In the last example the expression and sub-expressions are retrieved using the system variables $0 to $2 or their equivalent expression ($ 0) to ($ 2).

When using quotes " " for delimiting strings and backslashes are required in the regular expression pattern, then the backslash must be doubled. As an alternative brackets { ... } or text tags [text] ... [/text] can be used to delimit text strings. In this case no extra backslashes are required.

Characters escaped by a backslash in newLISP like the quote \" or \n need not to be doubled in a regular expression pattern which itself is delimited by quotes.

;; double backslash for parenthesis (special char in regex)
(regex "\\(abc\\)" "xyz(abc)xyz")           => ("(abc)" 3 5)  

;; one backslash for quote (special char in newLISP
(regex "\"" "abc\"def")                     => ("\"" 3 1)     

;; brackets as delimiters
(regex {\(abc\)} "xyz(abc)xyz")             => ("(abc)" 3 5)  

;; brackets as delimiters and quote in pattern
(regex {"} "abc\"def")                      => ("\"" 3 1)     

;; text tags as delimiters, good for multi-line text in CGI
(regex [text]\(abc\)[/text] "xyz(abc)xyz")  => ("(abc)" 3 5)  
(regex [text]"[/text] "abc\"def")           => ("\"" 3 1) 

When using {,} curly brackets or text tags [text], [/text] instead of quotes " " for delimiting the pattern string, a simple backslash is enough and the pattern and string are passed in raw form to the regular expression routines. When using curly brackets inside a pattern itself delimited by curly brackets, then the inner brackets must be balanced:

;; brackets inside brackets are balanced
(regex {\d{1,3}} "qwerty567asdfg")   => ("567" 6 3) 

The following constants can be used for int-option. Several options can be combined using a binary or '|'. The uppercase names are the names as used in the PCRE regex documentation and could be predefined in init.lsp. The last option is a newLISP custom option only to be used in replace, it can be combined with PCRE options.

  PCRE_CASELESS        1 ; treat uppercase like lowercase
  PCRE_MULTILINE       2 ; limit search at a newline like Perl's /m
  PCRE_DOTALL          4 ; . (dot) also matches newline
  PCRE_EXTENDED        8 ; ignore whitespace except inside char class
  PCRE_ANCHORED       16 ; anchor at the start
  PCRE_DOLLAR_ENDONLY 32 ; $ matches at end of string, not before newline
  PCRE_EXTRA          64 ; additional functionality currently not used
  PCRE_NOTBOL        128 ; first char not start of line, ^ shouldn't match
  PCRE_NOTEOL        256 ; last char not end of line, $ shouldn't match
  PCRE_UNGREEDY      512 ; invert greediness of quantifiers
  PCRE_NOTEMPTY     1024 ; empty string considered invalid
  PCRE_UTF8         2048 ; pattern and strings as UTF-8 characters

  REPLACE_ONCE    0x8000 ; replace only one occurrence
                         ; only for use in replace

Note that regular expression syntax is very complex and feature rich with many special characters and forms. Please consult a book or the PCRE manual pages at for more detail. Most PERL books or introductions to LINUX or UNIX also contain chapters about regular expressions. See also http://www.pcre.org for further references and manual pages.



remove-dir

syntax: (remove-dir str-path)

Removes the directory, whose path-name is specified in str-path. The directory must be empty for remove-dir to succeed. On failure nil is returned.

example:
(remove-dir "temp")

Removes the directory temp in the current directory.



rename-file

syntax: (rename-file str-path-old str-path-new)

Renames a file or directory entry given in a path-name in str-path-old to the name given in str-path-new. Returns nil or true depending on a successful operation.

example:
(rename-file "data.lisp" "data.backup")


replace

syntax: (replace exp-key list exp-replacement)
syntax: (replace str-key str-data exp-replacement)
syntax: (replace str-pattern str-data exp-replacement int-option)
syntax: (replace exp list)

List replacement

If the second argument is a list then replace replaces all elements in a list list equal to the expression in exp-key. The element is replaced with exp-replacement. replace is destructive, changing the list which is passed to it. replace returns the changed list. The number of replacements made is contained in the system variable $0.

String replacement without regular expression

If all arguments are strings, replace replaces all occurrences of str-key in str-data with the evaluated exp-replacement and returns the changed string. The expression in exp-replacement is evaluated for every replacement. The number of replacements made is contained in the system variable $0.

Regular expression replacement

The presence of a fourth parameter indicates that an regular expression search should be performed with a regular expression pattern specified in str-pattern and an option number specified in int-option, i.e. 1 (one) for case insensitive search or 0 (zero) for a standard Perl compatible regular expression search (PCRE). See regex for details. The changed string is returned. By default replace replaces all occurrences of a search string even if a beginning of line specification is in the search pattern, because after each replace a new search is started at a new position in str-data. Setting the the option bit 0x8000 in in-option will force replace to replace only the first occurrence.

replace with regular expressions also sets the internal variables $0 $1 $2 ... etc. with the contents of the expressions and sub-expressions found. These can be used to do replacements depending on the content found during replacement. The symbols $0 $1 $2 ... can be used in expressions just like any other symbols. If the replacement expression evaluates to something else than a string, no replacement is made. As an alternative the contents of these variables can also be accessed by using ($ 0) ($ 1) ($ 2) ... etc. This method allows indexed access, i.e: ($ i), where i is an integer.

List removal

The last form of replace has only two arguments an expression expr and list This form removes all expr found in list.

example:
(set 'aList '(a b c d e a b c d))
(replace 'b aList 'B)              => (a B c d e a B c d)
aList => (a B c d e a B c d)
$0 => 2                            ; number of replacements

(set 'str "this isa sentence")
(replace "isa" str "is a")         => "this is a sentence"

;; using the option parameter to employ regular expressions

(set 'str "ZZZZZxZZZZyy")          => "ZZZZZxZZZZyy"
(replace "[x|y]" str "PP" 0)       => "ZZZZZPPZZZZPPPP"
str                                => "ZZZZZPPZZZZPPPP"

;; using system variables for dynamic replacement

(set 'str "---axb---ayb---")
(replace "(a)(.)(b)" str (append $3 $2 $1) 0) 
                        => "---bxa---bya---"

str                     => "---bxa---bya---"

;; using the 'replace once' option bit 0x8000

(replace "a" "aaa" "X" 0) => "XXX"

(replace "a" "aaa" "X" 0x8000) => "Xaa"

;; URL translation of hex codes with dynamic replacement

(set 'str "xxx%41xxx%42")
(replace "%([0-9A-F][0-9A-F])" str 
               (char (integer (append "0x" $1))) 1)

str => "xxxAxxxB"

;; removing elements from a list

(set 'lst '(a b a a c d a f g))
(replace 'a lst)                   => (b c d f g)
lst                                => (b c d f g)

$0                                 => 4

See also set-nth and replace-assoc for other functions changing an element in a list.

See find, parse, regex and search for other functions using regular expressions.



replace-assoc

syntax: (replace-assoc exp-key list-assoc exp-replacement)

Replaces an association element with exp-key in an association list-assoc with exp-replacement. An association list is a list whose elements are in turn lists, whose first element serves as a key.

example:
(set 'aList '((a 1 2 3)(b 4 5 6)(c 7 8 9)))

(replace-assoc 'b aList '(q "I am the replacement")) 
       => ((a 1 2 3)(q "I am the replacement")(c 7 8 9))

aList  => ((a 1 2 3)(q "I am the replacement")(c 7 8 9))

replace-assoc uses the system variable $0 for the association found. This can be used in the replacement expression:

(set 'lst '((a 1)(b 2)(c 3))) 

(replace-assoc 'b lst (list 'b (+ 1 (last $0))))

lst => ((a 1)(b 3)(c 3))

replace-assoc returns the changed list and is a destructive operation changing the contents of the list.

See also assoc for accessing association lists.



reset

syntax: (reset)

reset returns to the top level of evaluation, switches the trace mode off, turns the command-line mode on and switches to the MAIN context / name-space. Reset restores the top level variable environment using the saved variable environments on the stack. reset also fires an error "user reset - no error". This behavior can be used when writing error handlers.

reset may return memory, which was claimed by newLISP, to the operating system. reset walks through the entire cell space (which may take a few seconds in a heavily loaded system).

reset occurs automatically after an error when break mode is set to nil.



rest

syntax: (rest list)
syntax: (rest str)

Returns all the items of a list or a string except the first. rest is equivalent to cdr or tail in other LISP dialects.

example:
(rest '(1 2 3 4))              => (2 3 4)
(rest '((a b) c d))            => (c d)
(set 'aList '(a b c d e))      => (a b c d e)
(rest aList)                   => (b c d e)
(first (rest aList))           => b
(rest (rest aList))            => (d e)
(rest (first '((a b) c d)))    => (b)

In the second version rest returns all but the first character of a string str in a string.

example:
(rest "newLISP")               => "ewLISP"
(first (rest "newLISP"))       => "e"

See also first and last.

Note that an implicit rest is available for lists. See chapter Implicit rest and slice.

Note that rest works on character boundaries rather than byte boundaries when using the UTF-8 enabled version of newLISP.



reverse

syntax: (reverse list)
syntax: (reverse string)

In the first form the list is reversed and returned. reverse is destructive changing the original list.

example:
(set 'l '(1 2 3 4 5 6 7 8 9))

(reverse l) => (9 8 7 6 5 4 3 2 1)
l => (9 8 7 6 5 4 3 2 1)

In the second form reverse is used to reverse the order of characters in a string.

example:

(set 'str "newLISP")

(reverse str) => "PSILwen"
str => "PSILwen"

See also sort.



rotate

syntax: (rotate list [int-count])

The list in is rotated and returned. Optionally a count can be specified in int-count to rotate more than one position. If int-count is positive the rotation is to the right, if int-count is negative the rotation is to the left. If no int-count is specified rotate rotates 1 to the right. rotate is a destructive function which changes the contents of the original list.

example:
(set 'l '(1 2 3 4 5 6 7 8 9))

(rotate l)     => (9 1 2 3 4 5 6 7 8)
(rotate l 2)   => (7 8 9 1 2 3 4 5 6)

l => (7 8 9 1 2 3 4 5 6)

(rotate l -3)  => (1 2 3 4 5 6 7 8 9)


save

syntax: (save str-file [sym ... ])

Saves the contents of the newLISP workspace to a file str-file in textual form. save is the inverse function to load such, that using load on files created with save results in the complete same state of newLISP, as before the save took place.

If a sym is supplied only the definition of that symbol is saved. If sym evaluates to a context, all symbols in that context are saved. More than one symbol can be specified, and symbols and context symbols can be mixed.

Each symbol is saved by means of a set - statement or, if the symbol contains a lambda or lambda-macro function by means of define or define-macro statements.

Symbols containing nil will not be saved.

save returns true on completion.

example:
(save "save.lsp")

(save "/home/myself/myfunc.LSP" 'my-func) 

(save "mycontext.lsp" 'mycontext) 

; multiple args
(save "stuff.lsp" 'aContext 'myFunc 'otherVar 'Acontext)

Saving the context MAIN saves all contexts, as all context symbols are part of the context MAIN.

Note that symbols made using sym and which are not compatible with the normal syntax rules for symbols, are serialized correctly since version 8.5.8 of newLISP. This means that contexts containing hash symbols can be saved like any other context.

See also load, which is the inverse operation to save and source, which saves a symbol to a string instead of a file.



search

syntax: (search int-file str-search [int-options])

Searches a file specified by its handle in int-file for a string in str-search.  int-file can be obtained from a previous open file. After the search the file pointer is positioned at the beginning of the searched string or at the end of the file if nothing is found. The options flags can be specified in int-options to perform a PCRE regular expressions search. See the function regex for details. Search returns the position of the found string or nil if nothing is found.

When using the regular expressions options flag, patterns found are stored in the system variables $0 to $15.

example:
(set 'file (open "init.lsp" "read"))
(search file "define")
(print (read-line file) "\n")
(close file)

The file init.lsp is opened and searched for the string define.

For other functions using regular expressions see find, parse, regex and replace.



seed

syntax: (seed int-seed)

Seeds the internal random generator generating numbers for amb, normal, rand and random with the number specified in int-seed. Note that the random generator used in newLISP is the C-library function rand(). All randomizing functions in newLISP are based on this function.

example:
(seed 12345)

(seed (date-value))

After using seed with the same number, the random generator starts the same sequence of numbers. This facilitates debugging when randomized data are involved. Using seed the same random sequences can be generated over and over again.

The second example is useful to guarantee a different seed any time the program starts.



seek

syntax: (seek int-file [int-position])

Sets the file pointer to a new position in the file specified by int-file to int-position. The new position is expressed as an offset from the beginning of the file, 0 (zero) meaning the beginning of the file. If no int-position is specified then seek returns the current position in the file. If int-file is 0 (zero) than on BSD seek will return the number of characters printed to STDOUT on LINUX and Win32 it will return -1. On failure seek returns nil. When int-position is set to -1, then seek sets the file pointer to the end of the file.

example:
(set 'file (open "myfile" "read"))      => 5 
(seek file 100)                         => 100
(seek file)                             => 100
(seek file -1)  ; seek to EOF


select

syntax: (select list list-selection)
syntax: (select list [int-index_i ... ])

syntax: (select string list-selection)
syntax: (select string [int-index_i ... ])

In the first two forms select picks one or more elements from a list using one or more indices specified in list-selection or the int-index_i.

example:
(set 'lst '(a b c d e f g))

(select lst '(0 3 2 5 3)) => (a d c f d)

(select lst '(-2 -1 0))   => (f g a)

(select lst -2 -1 0)      => (f g a)

In the second two forms select picks one or more characters from a string using one or more indices specified in list-selection or the int-index_i.

example:
(set 'str "abcdefg") 

(select str '(0 3 2 5 3)) => "adcfd"

(select str '(-2 -1 0))   => "fga"

(select str -2 -1 0)      => "fga"

Selected elements can be repeated and do not have to appear in order, although this speeds up processing. Changing the order in list-selection or int-index_i can be used to rearrange elements.



semaphore

syntax: (semaphore)
syntax: (semaphore int-id)
syntax: (semaphore int-id int-wait)
syntax: (semaphore int-id int-signal)
syntax: (semaphore int-id 0)

A semaphore is an interprocess synchronization object that maintains a count between zero and some maximum value. A semaphore is useful in controlling the access to a shared resource. A semaphore is set to signaled when its count is greater then zero and non-signaled when its count is zero.

A semaphore is created using the first syntax and returns an integer which is the semaphore id used subsequently as int-id when calling the semaphore function. Initially the semaphore has a value of zero, which is the non-signaled state.

When making a call to a semaphore with a negative value in int-wait, which would try to decrement the semaphore beyond zero, the function call will block until an other process or thread signals the semaphore with a positive value in int-signal. Calls to the semaphore with int-wait or int-signal effectively try to increment or decrement the semaphore value by a positive or negative value specified in int-signal or int-wait. As the value of a semaphore must never fall below zero the function call will block when trying to go beyond zero. I.e. when the semaphore has a value of zero any call to it with a negative number will block until another process or thread increases the value again with a positive int-signal.

To inquire the value of a semaphore the second syntax is used calling semaphore with only the int-id. This form is not available on Win32.

Supplying a 0 zero as the last argument will release system resources for the semaphore, which then is no longer available. Any pending waits on this semaphore in other child threads or processes will be released.

On Win32 only parent and child processes can share a semaphore. On Linux/UNIX independent processes can share a semaphore.

example:
;; counter thread output in bold

(define (counter n)
	(println "counter started")
	(dotimes (x n)
		(semaphore sid -1)
		(println x)))

;; hit extra <enter> to make the prompt come back
;; after output to the console from counter thread

> (set 'sid (semaphore))

> (semaphore sid) => 0

> (fork (counter 100))
counter started
> (semaphore sid 1)
0
> (semaphore sid 3)
1
2
3
> (semaphore sid 2)
4
5
>

after acquiring the semaphore in sid it has a value of 0, the non-signaled state. When starting the thread counter it will block after the initial start message and wait in the semaphore call. The -1 is trying to decrement the semaphore, which is not possible because it's value is already zero. Now in the interactive main parent process the semaphore is signaled by raising its value by 1. This de-blocks the semaphore call in the counter thread, which now can decrement the semaphore from 1 to 0 and execute the print statement. When arriving at the semaphore call again, it will block because the semaphore is already in the wait 0 state.

Subsequent calls to semaphore with numbers greater than 1 give the counter thread the opportunity to decrement the semaphore several times before blocking.

More than one thread could participate in controlling the semaphore and more than one semaphore can be created. The maximum number of semaphores is contolled by a system wide kernel setting on UNIX like operating systems.

See also the functions fork for starting a new thread and share for sharing information between threads. For a more comprehensive example using semaphore to synchronize threads, see the example prodcons.lsp in the Appendix or examples/ directory in the source distribution or examples and modules package of newLISP.



sequence

syntax: (sequence num-start num-end [num-step])

Generates a sequence of numbers from num-start to num-end and with a optional step size of num-step. When num-step is omitted the value 1 (one) is assumed. The generated numbers are always floating point numbers.

example:
(sequence 0 1 0.2) => (0 0.2 0.4 0.6 0.8 1)
(sequence 2 0 0.3) => (2 1.7 1.4 1.1 0.8 0.5 0.2)

Note that the step size must be set positive, even if sequencing from a higher to a lower number.

See also series for generating geometric sequences.



series

syntax: (series num-start num-factor num-count)

Creates a geometric sequence with num-count elements starting with the element in num-start. Each subsequent element is multiplied by num-factor. The generated numbers are always floating point numbers.

example:
(series 2 2 5)    => (2 4 8 16 32)
(series 1 1.2 6)  => (1 1.2 1.44 1.728 2.0736 2.48832)
(series 10 0.9 4) => (10 9 8.1 7.29)
(series 0 0 10)   => (0 0 0 0 0 0 0 0 0 0)
(series 99 1 5)   => (99 99 99 99 99)

See also sequence for generating arithmetic sequences.



set

syntax: (set sym-variable exp [ ... ])

Evaluates both arguments, then assigns the result of exp to the symbol found in sym-variable. The set expression returns the result of the assignment. The assignment is done by copying the contents of the right side in to the symbol. The old contents of the symbol is deleted. Trying to change the contents of the symbols nil, true or a context symbol results in an error message. set can take multiple argument pairs.

example:
(set 'x 123)            => 123
(set 'x 'y)             => y
(set 'x "hello")        => "hello"

y                       => "hello"

(set 'alist '(1 2 3))   => (1 2 3)


(set 'x 1 'y "hello")   => "hello"   ;; multiple arguments

x                       => 1
y                       => "hello"

The symbol for assignment could be the result from another newLISP expression:

(set 'lst '(x y z))    => (x y z)

(set (first lst) 123)  => 123

x                      => 123

Symbols can be set to lambda or lambda-macro expressions. This operation is equivalent to using define or define-macro.

(set 'double (lambda (x) (+ x x))) => (lambda (x) (+ x x))

is equivalent to:
(define (double x) (+ x x)) => (lambda (x) (+ x x))

is equivalent to:
(define double (lambda (x) (+ x x))) => (lambda (x) (+ x x))

See also constant, which works like set, but protects the symbol from subsequent alteration. See setq and set! which doe not need the variable symbol to be quoted.



setq, set!

syntax: (setq sym-variable exp)

Works just like set, but the variable in sym-variable does not have to be quoted. Like set setq can take multiple arguments. setq and set! are the same function.

example:
(setq x 123)       => 123

; multiple args

(setq x 1 y 2 z 3) => 3 

x  => 1
y  => 2
z  => 3


set-locale

syntax: (set-locale [str-locale] [int-category])

Reports or switches to a different locale on your operating system or platform. When used without arguments the current used locale is reported. When specifying str-locale that locale is switched to with all category options turned on (LC_ALL). An empty string in str-locale is used to switch to the default locale used on the current platform. set-locale returns the current settings or nil if the requested change could not be performed.

example:
(set-locale)     ; report current locale

(set-locale "")  ; set default locale of your platform

By default newLISP starts up with the POSIX 'C' default locale. This guarantees an identical behaviour of newLISP on any platform locale:

; after newLISP start up

(set-locale)    => "C"

In int-category integer numbers may be specified as category options for fine tuning certain aspects of the locale, like number display, date display etc. The numbers used vary from system to system. The options valid on your platform can be found in a 'C' include file locale.h. This file defines constants like LC_ALL, LC_NUMERIC, LC_MONETARY etc. When using set-locale without the option number, then LC_ALL is assumed, which turns on all options for that locale.

Note that the locale also controls the decimal separator in numbers. The default 'C' locale uses the decimal dot, but most other locales use a decimal comma. Since version 8.4.4 newLISP will parse decimal comma numbers correctly.

Note that using set-locale does not change the behavior of regular expressions in newLISP. To localize the behavior of PCRE (Perl Compatible Regular Expressions) in newLISP, it has to be compiled with different character tables. See the file LOCALIZATION in the newLISP source distribution for details.

See also the manual chapter Switching the locale.



set-nth

syntax: (set-nth int-nth-1 [ int-nth-2 ... ] list exp-replacement)
syntax: (set-nth int-nth-1 [ int-nth-2 ... ] array exp-replacement)
syntax: (set-nth int-nth-1 str str-replacement)

Sets the nth in int-nth element in a list with the evaluation of exp-replacement and returns the changed list. The replaced list element can be found in the system variable $0. set-nth is a destructive operation, which changes the original list. More than one index can be specified to recursively traverse nested list structures. An index out of bound always picks the last or first element. When an index can no longer traverse list, the current element is changed to the replacement expression. Up to 16 indices can be specified.

The second form works identically to the first but on arrays instead of lists and the system variable $0 will not be set. Out of bounds indices will cause an out of bounds error message.

In the third form the int-nth character in str is replaced with the string in str-replacement.Indices out of bounds will pick the first or last character for replacement and the system variable $0 is set to the replaced character.

example:
;;;;;;;;;;; usage on lists ;;;;;;;;;;;;

(set 'aList '(a b c d e f g))
(set-nth 2 aList "I am the replacement") 
    => (a b "I am the replacement" d e f g)

aList => (a b "I am the replacement" d e f g)

$0    => c

(set 'aList '(a b (c d (e f g) h) i)))
(set-nth 2 2 0 aList 'x)

aList  => (a b (c d (x f g) h) i)
$0    => e

(set-nth -2 2 -1 aList 99)
=> (a b (c d (x f 99) h) i)

$0    => g

The second form uses set-nth to change the contents of arrays.

example:
;;;;;;;;;;; usage on arrays ;;;;;;;;;;;;

(set 'myarray (array 3 4 (sequence 1 12)))
=> ((1 2 3 4) (5 6 7 8) (9 10 11 12))

(set-nth 2 3 myarray 99)        
=> ((1 2 3 4) (5 6 7 8) (9 10 11 99))

(set-nth -2 1 myarray "hello")  
=> ((1 2 3 4) (5 "hello" 7 8) (9 10 11 99))

(set-nth 1 myarray (array 4 '(a b c d)))    
=> ((1 2 3 4) (a b c d) (9 10 11 99))

When replacing whole rows like in the last example, care must be taken to replace it as an array. See also the array functions array, array? and array-list.

In the third form the int-nth character in str is replaced with the string in str-replacement.

example:
;;;;;;;;;;; usage on strings ;;;;;;;;;;;;

(set-nth 0 "abcd" "xyz")  => "xyzbcd"
$0                        => "a"

(set-nth -1 "abcd" "xyz") => "abcxyz"
$0                        => "d"

set-nth uses the system variable $0 for the element found in lists and strings. This can be used in the replacement expression:

(set 'lst '(1 2 3 4))

(set-nth 1 lst (+ $0 1))

lst => '(1 3 3 4)

(set-nth 1 "abcd" (append $0 $0)) => "abbcd"

See also the nth-set, which work like set-nth but returns the replaced element instead of the whole changed expression and is mush faster when doing replacements on a larger lists or string buffers.

See also nth and push and pop for other functions suitable for accessing multidimensional nested lists or arrays (nth).



share

syntax: (share)
syntax: (share int-address-or-handle)
syntax: (share int-address-or-handle exp-value)

For communicating between several newLISP processes or threads, newLISP can access shared memory. Using share without any parameters requests a page of shared memory from the operating system services. On Win32 this page is 4k but may be different on Linux/UNIX.  share without any parameters returns a memory address on Linux/UNIX and a handle on Win32. The memory address or handle can be assigned to a variable for later reference.

To set the contents of shared memory use the third syntax of share supplying a shared memory address on Linux/UNIX or a handle in Win32 in int-address-or-handle and an integer, float or string expression in exp-value. Using this syntax the value supplied in exp-value is also the return value;

To access the contents of shared memory use the second syntax of share supplying only the shared memory address or handle. The return value will be an integer or floating point number, a string or nil or true. If the memory has not been set to a value before nil will be returned.

Memory can only be shared between parent and child processes or threads, but not between independent processes.

example:
(set 'num (share))
(set 'str (share))

(share num 123) => 123

(share str "hello world") => "hello world"
(share str)		  => "hello world"

(share mVar 123) => 123
(share mVar)     => 123

(share mVar true) => true
(chare mVar)      => true

For a more comprehensive example of using shared memory in a multi-threaded Linux/UNIX application see the example prodcons.lsp in the Appendix or in the examples/ directory of the source distribution

Note that shared memory access between different threads or processes should be synchronized using a semaphore. Simultaneous access to shared memory can crash the process/thread running.

To find out the maximum length of a string buffer which could be stored in a shared memory address do the following:

(length (share (share) (dup " " 1000000))) => 4087

The statement tries to initialize a shared memory address to 100,000 bytes, but only 4087 will be initialized as a string buffer. The page size of this platform is 4096 bytes, which is 4087 plus 8 bytes of header information for type and size plus one terminating byte for displayable strings.

More than one numbers or string can be stored in one memory page using offsets added to the main segment address when working on Linux/UNIX:

example:
;; Linux/UNIX only

(set 'num-1 (share))
(set 'num-2 (+ num-1 12))
(set 'num-3 (+ num-2 12))
(set 'str-1 (+ num-3 12))

(share num-1 123)
(share num-2 123.456)
 ...

(share num-1) => 123
(share num-3) => 123.456
 ...

;; etc

For numbers reserve 12 bytes for strings reserve 12 bytes plus the length of the string plus 1 for a terminating zero-byte.For the boolean values nil and true 4 bytes should be reserved.

Note that a shorter string could accidentally be overwritten with a longer string. Therefore shared strings should be stored after other shared number fields or reside on there own shared memory page.

Note that the functions get-int, get-float get-string and get-char as well as pack and unpack could also be used to access contents from a shared memory page. This low-level address requires precise knowledge of the type of information stored, but allows a very compact storage of information without type/header information in a string buffer.

example:
;; Linux/UNIX and Win32

(set 'mem (share))

(mem share (pack "s5 ld lf" "hello" 123 123.456))
(unpack "s10 ls lf" (mem share))  => ("hello" 123 123.456)

On Linux/UNIX supplying a wrong share address can cause newLISP to crash.



signal

syntax: (signal int-signal sym-handler)
syntax: (signal int-signal  'nil)
syntax: (signal int-signal)

Sets a user defined handler in sym-handler for a signal specified in int-signal. If 'nil is specified the signal will default to the initiliazed behaviour in newLISP.

Different signals are available on different OS platforms and Linux/UNIX flavors. The numbers to specify in int-signal also differ from platform to platform. Valid values can be extracted normally from a file found in /usr/include/sys/signal.h or /usr/include/signal.h.

Some signals make newLISP exit even after a user-defined handler has been specified and executed (i.e. siganl SIGKILL). This behaviour too may be different on a different platform.

example:
(constant 'SIGINT 2)
(define (ctrlC-handler) (println "ctrl-C has been pressed"))

(signal SIGINT 'ctrlC-handler)

; now press ctrl-C
; the following line will appear

ctrl-C has been pressed

On Win32 the above example would exit newLISP but the handler would be executed first. On most Linux/UNIX newLISP would stay loaded and the prompt would appear after hitting the [enter] key.

Note that the signal SIGKILL (9 on most platforms) will always terminate the application regardless of an exisiting signal handler.

The signal could have been sent from another shell on the same computer:

kill -s SIGINT 2035

In this example 2035 is the process id of the running newLISP.

The signal could have been sent from another newLISP application:

(constant 'SIGINT 2)
(import "libc.so" "kill")

(kill 2035 SIGINT)

When importing kill make always sure it receives integer numbers for the signal number. Use int to convert if required.

When newLISP receives the signal while evaluating another function, it will still receive the signal and the handler function will be executed:

(constant 'SIGINT 2)
(define (ctrlC-handler) (println "ctrl-C has been pressed"))

(signal SIGINT 'ctrlC-handler)

(while true (sleep 300) (println "busy"))

; generates following output
busy
busy
busy
ctrl-C has been pressed
busy
busy
...

Specifying only a signal number will return the symbol of the current user-defined handler function or return nil.

The user defined signal handler can pass the the signal number as a parameter.

(define (signal-handler sig)
	(println "received signal: " sig))

; set all signals from 1 to 8 to the same handler	
(for (s 1 8) 
	(signal s 'signal-handler))

In this example all signals from 1 to 8 are set to the same handler.



silent

syntax: (silent [expr-1] [ expr-2 ...])

Evaluates one or more expressions in expr-1 ... similar to begin, but suppresses console output of the return value and the following prompt. silent is often used when communicating from a remote application with newLISP, i.e.: GUI front-ends or other applications controlling newLISP, and the return value is not of interest.

Silent mode is reset when returning to a prompt, this way it can also be used without arguments in a batch of expressions. When in interactive mode hit [enter] twice after a statement with silent to get the prompt back.

example:
(silent (my-func))    ; same as next

(silent) (my-func)    ; same effect as previous


sin

syntax: (sin num)

The sine function is calculated from num and the result is returned.

example:
(sin 1)                     => 0.8414709838
(set 'pi (mul 2 (acos 0)))  => 3.141592654
(sin (div pi 2))            => 1


sleep

syntax: (sleep int-milli-seconds)

sleep gives up CPU time to other processes for the amount of milliseconds specified in int-milli-seconds.

example:
(sleep 1000)    ; sleeps 1 second

On some platforms sleep is only available with full seconds resolution. In this case the parameter int-milli-seconds will be rounded to the nearest full second.



slice

syntax: (slice list int-index [int-length])
syntax: (slice str int-index [int-length])

In the first form slice copies a sublist from a list. The original list is left unchanged. The sublist extracted starts at index int-index and has a length of int-length. If int-length is -1, or if the parameter is omitted then all elements to the end of the list are copied.

See also Indexing elements of strings and lists.

example:
(slice '(a b c d e f) 3 2)    => (d e)
(slice '(a b c d e f) 2 -1)   => (c d e f)
(slice '(a b c d e f) -4 3)   => (c d e)

In the second form a part of the string in str is extracted. int-index contains the start index, int-length contains the length of the substring. If no int-length is specified, everything to the end is extracted. slice works also on string buffers containing binary data like 0's (zeros). See also Indexing elements of strings and lists.

example:
(slice "Hello World" 6 2)   => "Wo"
(slice "Hello World" 0 5)   => "Hello"
(slice "Hello World" 6)     => "World"
(slice "newLISP" -4 2)      => "LI"

Note that an implicit slice is available for lists. See chapter Implicit rest and slice.

Note that rest always works on byte boundaries rather than character boundaries when using the UTF-8 enabled version of newLISP. This way slice can be used to manipulate binary content.



sort

syntax: (sort list)
syntax: (sort list func-compare)

In the first syntax all members in list are sorted in ascending order. Anything may be sorted regardless of the type of members of the list. When members are lists then each list element is recursively compared. If two expressions of different type are compared, then the lower type is sorted before the higher type in the following order:

  Atoms: nil, true, integer or float, string, symbol, primitive

  Lists: quoted expression, list, lambda , lambda-macro

The sort is destructive, changing the order of the elements in the original list. The return value of sort is a copy of the sorted list.

In the second syntax a comparison operator or user defined function or anonymous function can be supplied. The functor or operator can be given with or without a preceding quote.

example:
(sort '(v f r t h n m j))       => (f h j m n r t v)
(sort '((3 4) (2 1) (1 10)))    => ((1 10) (2 1) (3 4))
(sort '((3 4) "hi" 2.8 8 b))    => (2.8 8 "hi" b (3 4))

(set 's '(k a l s))
(sort s)                        => (a k l s)  

(sort '(v f r t h n m j) '>)    => (v t r n m j h f)
;; the quote can be ommitted since version 8.4.5
(sort '(v f r t h n m j) >)     => (v t r n m j h f)
(sort s <)                      => (a k l s)
(sort s >)                      => (s l k a)  
s                               => (s l k a)

;; define a comparison function
(define (comp x y) 
    (> (last x) (last y)))
    
(set 'db '((a 3) (g 2) (c 5)))

(sort db comp) =>  ((c 5) (a 3) (g 2))

;; use an anonymous function
(sort db (fn (x y) (> (last x) (last y))))


source

syntax: (source symbol)

Returns the source to bind a symbol in a string. source works similar to save but the contents of the symbol is not saved to a file but returned as a string. The string returned is the source necessary to set or define the symbol.

example:
(define (double x) (+ x x))

(source 'double)  => "(define (double x)\n  (+ x x))\n\n"

Similar to save the formatting of line breaks and leading spaces or tabs can be controlled using the pretty-print function.



sqrt

syntax: (sqrt num)

The square root is calculated from the expression in num and the result is returned.

example:
(sqrt 10)      => 3.16227766
(sqrt 25)      => 5


starts-with

syntax: (starts-with str str-key [nil] )
syntax: (starts-with list [expr] )

In the first version starts-with checks if a string str starts with a key string in str-key. true or nil is returned depending on outcome. Optionally nil can be specified for case insensitive string comparisons.

example:
(starts-with "this is useful" "this")     => true
(starts-with "this is useful" "THIS")     => nil
(starts-with "this is useful" "THIS" nil) => true

In the second version starts-with checks if a list starts with the list element in expr. true or nil is returned depending on outcome.

example:
(starts-with '(1 2 3 4 5) 1)              => true
(starts-with '(a b c d e) 'b)             => nil
(starts-with '((+ 3 4) b c d) '(+ 3 4))   => true

See also ends-with.



string

syntax: (string exp-1 [ exp-2 ... exp-n ])

Translates anything which results from evaluating exp-1 ... into a string. If more than one expressions are specified the resulting strings are concatenated.

example:
(string 'hello)          => "hello"
(string 1234)            => "1234"
(string '(+ 3 4))        => "(+ 3 4)"
(string (+ 3 4) 8)       => "78"
(string 'hello " " 123)  => "hello 123"

If a buffer passed to string contains \000 (zeros), only the string up to the first terminating zero will be copied:

(set 'buff "ABC\000\000\000") => "ABC\000\000\000"

(length buff)                 => 6

(string buff)                 => "ABC"

(length (string buff))        => 3

See also append for concatenating strings and join for concatenating strings and specifying the joining strings in between. See source for converting a lambda expression in its newLISP source string representation.



string?

syntax: (string? exp)

exp is evaluated and tested if a string. true or nil is returned, depending on the result.

example:
(set 'var "hello")
(string? var)           => true


sub

syntax: (sub num-1 [num-2 ... ])

The expressions in num-1, num-2... are successively subtracted. sub performs mixed type arithmetic and handles integers and/or floating point numbers, but always returns floating point numbers. If only 1 argument is supplied, its sign is reversed. Any floating point calculation with NaNalso returns NaN.

example:
(sub 10 8 0.25)    => 1.75
(sub 123)          => -123


swap

syntax: (swap num-1 num-2 list)
syntax: (swap num-1 num-2 str)

In the first form the elements at indices num-1 and num-2 in list are swapped and the changed list is returned.

In the second form the characters at indices num-1 and num-2 in str are swapped and the changed string is returned.

swap is a destructive operation changing the contents of the list or string.

example:
(set 'lst '(a b c d e f))

(swap 0 5 lst)              => '(f b c d e a)
lst                         => '(f b c d e a)

(swap 0 -1 lst)             => '(a b c d e f)
lst                         => '(a b c d e f)

(swap 3 4 "abcdef")         => "abcedf"


sym

syntax: (sym string [context nil-flag] )
syntax: (sym number [context nil-flag] )
syntax: (sym symbol [context nil-flag] )

Translates the first argument in string, number or symbol into a symbol and returns the symbol. Optionally a context can be specified in context or the current context is used when doing symbol lookup or creation. If the symbol does not exist it gets created. If the context is specified by a quoted symbol and the context does not exist, it also gets created. If the context specification is unquoted then the context is the name specified or the context specification is a variable containing the context.

symbol can create symbols in the symbol table, which are not legal symbols in newLISP source code, like numbers or names containing special characters, like parenthesis, colons etc.. This makes symbol usable as a function for associative memory access similar to hash table access in other scripting languages. A shorter writing of symbol is sym. Both are functionally identical.

Note that contexts containing illegal symbols when serialized to a file with save cannot be loaded back correctly, because (load ..) assumes legal newLISP syntax of symbols.

As a third optional parameter nil can be specified to suppress symbol creation if the symbol is not found. In this case sym or sym returns nil if the symbol looked up does not exist. Using this last form symbol can be used to check for the existence of a symbol.

example:
(sym "some")             => some
(set (sym "var") 345)    => 345
var                      => 345
(sym "aSym" 'MyCTX)      => MyCTX:aSym
(sym "aSym" MyCTX)       => MyCTX:aSym ; unquoted context

(sym "foo" MyCTX nil)    => nil ; 'foo does not exist
(sym "foo" MyCTX)        => foo ; 'foo is created
(sym "foo" MyCTX nil)    => foo ; foo now exists

Because the function sym or symbol returns the symbol looked up or created, expressions with symbol can be embedded directly in other expressions which use symbols as arguments. The following example show the usage of sym as a hash-like function for associative memory access and using symbol configurations which are not legal newLISP symbols:

example:
;; using sym for simulating hash tables

(set (sym "John Doe" 'MyDB') 1.234)
(set (sym "(" 'MyDB) "parenthesis open")
(set (sym 12 'MyDB) "twelve")

(eval (sym "John Doe" 'MyDB))       => 1.234
(eval (sym "(" 'MyDB))              => "parenthesis open"
(eval (sym 12 'MyDB))               => "twelve"

;; delete a symbol from a symbol table or hash
(delete (symbol "John Doe" 'MyDB))  => true

The last statement shows how a symbol is eliminated using delete.

The third syntax allows using symbols instead of strings for the symbol name in the target context. In this case symbol will extract the name from the symbol and use it as the name string for the symbol in the target context:

example:
(symbol 'myVar 'FOO) => FOO:myVar

(define-macro (def-context)
  (dolist (s (rest (args)))
    (symbol s (first (args)))))

(def-context foo x y z)

(symbols foo) => (foo:x foo:y foo:z)

The macro def-context shows how this could be used to create a macro which creates contexts and their variables in a dynamic fashion.



symbol?

syntax: (symbol? exp)

The expression exp is evaluated and symbol? returns true only if the value is a symbol, otherwise returns nil.

example:
(set 'x 'y)                    => y

(symbol? x)                    => true 

(symbol? 123)                  => nil

(symbol? (first '(var x y z))) => true

The first statement sets the contents of x to the symbol y. The second statement than checks the contents of x. The last example checks the first element of a list.



symbols

syntax: (symbols [sym-context])
syntax: (symbols [context])

Returns a sorted list of all symbols in the current context when given without parameter. If a context symbol is specified symbols defined in that context are returned.

example:
(symbols)       ; list of all symbols in current context
(symbols 'CTX)  ; list of symbols in context CTX
(symbols CTX)   ; the quote can be omitted
(set 'ct CTX)   ; assign context to a variable
(symbols ct)    ; list of symbols in context CTX

The quote can be omitted because contexts evaluate to themselves.



sys-error

syntax: (sys-error)

Reports error numbers generated by the underlying OS newLISP is running on. The error numbers reported may differ on the platforms newLISP has been compiled for. Consult the platforms 'C' library information, i.e. the GNU libc reference. Most errors reported refer to system resources like, files, semaphores etc..

Whenever a function in newLISP in the system resources area returns nil sys-error can be checked for the underlying reason. For file operations sys-error may be set for non-existing files or wrong permissions when accessing the resource. Another cause of error may be the exhaustion of certain system resources like file handles or semaphores.



example:
;; trying to open a non-existing file
(open "blahbla" "r") => nil

(sys-error)          => 2

(sys-error 0)        => 0  ; clear errno

The error number can be cleared giving a 0 as optional argument.



sys-info

syntax: (sys-info)

Returns a list of internal resource statistics. The list has 8 integers reporting the following status:

  0 - Number of LISP cells
  1 - Maximum number of LISP cells constant
  2 - Number of symbols
  3 - Evaluation/recursion level
  4 - Environment stack level
  5 - Maximum call stack constant
  6 - Version number as an integer constant
  7 - Operating System constant:
      linux=1, bsd=2, osx=3, solaris=4, cygwin=5, win32=6
      the highest bit 7 will be set for UTF-8 versions (add 128)
      bit 6 will be added for library versions (add 64)

The numbers from 0 to 7 indicate the option offset in the returned list.

example:
(sys-info)   => (291 268435456 269 1 0 1024 8402 6)

The number for the maximum of LISP cells can be changed via the -m command-line switch. For each 1 megabyte of LISP cell memory 64k memory cells can be allocated. The maximum call stack depth can be changed using the -s command-line switch.



tan

syntax: (tan num)

The tangent function is calculated from num and the result is returned.

example:
(tan 1)                       => 1.557407725
(set 'pi (mul 2 (asin 1)))    => 3.141592654
(tan (div pi 4))              => 1


throw

syntax: (throw exp)

This functions works together with catch. throw forces the return of a previous catch statement and puts the exp into the result symbol of catch.

example:

(define (throw-test)
    (dotimes (x 1000) 
        (if (= x 500) (throw "interrupted"))))

(catch (throw-test) 'result) => true

result => "interrupted"

(catch (throw-text))         => "interrupted"

The last example shows a shorter form of catch, which returns the throw result directly.

throw is useful to break out of a loop or for early return from user defined functions or expression blocks. In the following example the begin block will return X if (foo X) is true else Y will be returned:

(catch (begin
    ...
    (if (foo X) (throw X) Y)
    ...
))

throw will not cause an error exception. For throwing user error exceptions use throw-error.



throw-error

syntax: (error expr)

Causes a user defined error exception with text provided evaluating expr:

example:
(define (foo x y)
	(if (= y 0) (throw-error "first parameter cannot be 0"))
	(+ x y))

(foo 1 2)    => 3

(foo 0 2)        ; causes error user error exception

user error : first parameter cannot be 0
called from user defined function foo

The user error can be handled like any other error exception using user define error handlers and error-event or a form of catch which can capture error exceptions.



time

syntax: (time exp)

Evaluates the expression in exp and returns the time spent on evaluation in milli seconds.

example:
(time (myprog x y z)) => 450

In the example 450 milliseconds were spent to evaluate (myprog x y z).

See also date, date-value, time-of-day and now.



time-of-day

syntax: (time-of-day)

Returns the time in milliseconds since start of current day.

See also date, date-value, time and now.



timer

syntax: (timer sym-event-handler num-seconds [int-option])
syntax: (timer)

Starts a one-shot timer firing off the Unix signal SIGALRM, SIGVTALRM or SIGPROF after the time in seconds specified in num-seconds has passed. When the timer fires it calls the user defined function in sym-event-handler.

On Linux/UNIX optionally a 0, 1 or 2 can be specified to control how the timer counts. With default option 0 real time is measured, 1 mesaures only the time the CPU spends processing in the process or thread owning the timer and 3 is a combination of both, called profiling time. See the UNIX man page for setitimer() for details.

The event handler can start the timer again to achieve a continuos flow of events. Since version 8.5.9 seconds can be defined as floating point numbers with a fractional part, i.e. 0.25 for 250 milli seconds.

Defining 0 (zero) as time shuts the running timer down and prevents it from firing.

timer without any arguments returns the symbol of the current event handler. When a timeout in num-seconds was already set, then when specifying 0 or another time the number of seconds left from the previous alarm will be returned.

example:
(define (ticker) 
    (println (date)) (timer 'ticker 1.0))

> (ticker)
Tue Apr 12 20:44:48 2005       ; first execution of ticker
ticker                         ; return value from ticker
> Tue Apr 12 20:44:49 2005     ; first timer event
Tue Apr 12 20:44:50 2005       ; second timer event ...
Tue Apr 12 20:44:51 2005
Tue Apr 12 20:44:52 2005
Tue Apr 12 20:44:53 2005
Tue Apr 12 20:44:54 2005
Tue Apr 12 20:44:55 2005

The example shows an event handler ticker defined, which starts the timer again after each event.

Note that a timer cannot interrupt one on-going built-in function. The timer interrupt gets registered by newLISP, but a timer handler cannot run until one expression is evaluated and the next one starts. To use timer to interrupt an ongoing I/O operation, follow the frequently used pattern below using net-select to test if a socket is ready for reading:

example:
define (interrupt)
    (set 'timeout true))
        
(set 'listen (net-listen 30001))
(set 'socket (net-accept listen))
        
(timer 'interrupt 10)
        
(until (or timeout done)
    (if (net-select socket "read" 100000)
        (begin
            (read-buffer socket 'buffer 1024)
            (set 'done true)))
)
                                                                                
(if timeout
    (println "timeout")
    (println buffer))
                                                                              
(exit)

In this example the (until ...) loop will run until something could be read from socket or until 10 seconds have passed and the timeout variable is set.



trace

syntax: (trace [exp])

Tracing is switched on when exp evaluates to anything but nil or an empty list (). When no argument is supplied trace evaluates to true or nil depending on the current trace mode.

When trace mode is switched on, newLISP goes into a debugging mode, displaying the function currently executed and highlighting the current expression upon entry and exit. The highlighting is done by bracketing the expression between two '#' characters. This can be changed to different characters using trace-highlight Upon exit from the expression the result of its evaluation is also reported.

If an expression occurs more then once in a function, always the first occurrence of in the executing function will be highlighted (bracketed).

At each entry and exit of an expression newLISP execution stops with a prompt line:

[-> 2] (s)tep (n)ext (q)uit >

At the prompt s, n or q can be entered to step into or just execute the next expression. Any other expression can also be entered at this point for evaluation; for example, entering the name of a variable would evaluate to its contents. In this way the contents of variables can be checked during debugging, or the value of variables can be set to different values.

example:
;; switches newLISP into debugging mode
(trace true)    => true 

;; the debugger will show each step
(my-func a b c)

;; switched newLISP out of debugging mode
(trace nil)     => nil 

To set break points where newLISP should interrupt normal execution and go into debugging mode, put (trace true) statements into the lisp code where execution should switch on the debugger.

See also debug, which is a shortcut for the above example.



trace-highlight

syntax: (trace-highlight str-pre str-post [str-header str-footer ] )

Sets the characters or strings of characters used to enclose expressions during trace. By default "#" is used to enclose the expression highlighted in trace mode. This can be changed to different characters or strings of up to 7 characters. If the console window accepts terminal control characters, this can be used to display the expression in a different color, bold or reverse etc.:

Optionally two more string can be specified for str-header str-footer which control the separator and prompt. There is a maximum of 15 characters for the header and 31 for the footer

example:
;; active expressions are enclosed in >>and <<

(trace-highlight ">>" "<<") 
             
;; 'bright' color on a VT100 or similar terminal window

(trace-highlight "\027[1m" "\027[0m")   

The first example replace the default "#" with a ">>" and "<<". The second example works on most LINUX shell windows and may not work in a console window under Win32 or CYGWIN, depending on terminal mode configured.



transpose

syntax: (transpose matrix ])

Transposes a matrix by reversing the rows and columns and converts all cells to floating point numbers. Any kind of list-matrix can be transposed. Matrices are rectangularized by filling in nil and omitting elements were appropriate. Matrix dimensions are calculated using the number of rows in the original matrix for columns and the number of elements in the first row as number of rows in the transposed matrix.

example:
(set 'A '((1 2 3) (4 5 6)))
(transpose A)                     => ((1 4) (2 5) (3 6))
(transpose (list (sequence 1 5))) => ((1) (2) (3) (4) (5))

(transpose '((a b) (c d) (e f)))  => ((a c e) (b d f))

See also the matrix operations invert and multiply.



trim

syntax: (trim str [ str-char ])
syntax: (trim str [ str-left-char str-right-char ])

The first syntax trims a string str from both sides stripping the leading and trailing characters as given in str-char. If no character is given in str-char the space character is assumed. trim returns the new string.

The second syntax can trim different characters from both sides or trim only one side if an empty string is specified for the other side.

example:
(trim "   hello  ")              => "hello"
(trim "----hello-----" "-")      => "hello"
(trim "00012340" "0" "")         => "12340"
(trim "1234000" "" "0")          => "1234"
(trim "----hello=====" "-" "=")  => "hello"


unicode

syntax: (unicode str)

Converts ASCII/UTF-8 character strings in str to UCS-4 encoded Unicode of 4 byte integers per character. The function is only available on UTF-8 enabled versions of newLISP.

example:
(unicode "new") 

=> "n\000\000\000e\000\000\000w\000\000\000\000\000\000\000"


(utf8 (unicode "new")) => "new"

On big endian CPU architectures the byte order will be reversed from high to low. Both unicode and the utf8 functions are the inverse of each other. These functions are only necessary if UCS-4 Unicode is in use. Most systems use UTF-8 encoding only.



unique

syntax: (unique list)

Returns a unique version of list with all duplicates removed.

example:
(unique '(2 3 4 4 6 7 8 7)) => (2 3 4 6 7 8)

Note that the list does not need to be sorted, but a sorted list makes unique perform faster.

See also set functions difference and intersect.



unless

syntax: (unless exp-condition exp-1 [exp-2])

unless is equivalent to (if (not exp-condition exp-1 [exp-2])). If the value of exp-condition is nil or the empty list (), exp-1 is evaluated; otherwise exp-2 is evaluated. example:

(set 'x 50)                            => 50
(unless (< x 100) "big" "small")    => "small"
(set 'x 1000)                          => 1000
(unless (< x 100) "big" "small")    => "big"


unpack

syntax: (unpack str-format str-addr-packed)

Unpacks a binary structure in str-addr-packed into lisp variables using the format in str-format. unpack is the reverse operation to pack. Note that str-addr-packed may also be an integer number representing a memory address. This facilitates unpacking structures returned from imported shared library functions.

The following characters may define a format:

c a signed 8 bit number
b an unsigned 8 bit number
d a signed 16 bit short number
u an unsigned 16 bit short number
ld a signed 32 bit long number
lu an unsigned 32 bit long number
f a float in 32 bit representation
lf a double float in 64 bit representation
sn a string of n null padded ASCII characters
nn n null characters
> switch to big endian byte order
< switch to little endian byte order

example:
(pack "c c c" 65 66 67) => "ABC"
(unpack "c c c" "ABC") => (65 66 67)

(set 's (pack "c d u" 10 12345 56789))
(unpack "c d u" s) => (10 12345 56789)

(set 's (pack "s10 f" "result" 1.23))
(unpack "s10 f" s) => ("result\000\000\000\000" 1.230000019)

(set 's (pack "s3 lf" "result" 1.23))
(unpack "s3 f" s) => ("res" 1.23)

(set 's (pack "c n7 c" 11 22))
(unpack "c n7 c" s) => (11 22))

The > and < specifiers ca be used to switch between little endian and big endian byte order when packing or unpacking:

;; on a little endian system (i.e. Intel CPUs)
(set 'buff (pack "d" 1)) => "\001\000" 

(unpack "d" buff)        => (1)
(unpack ">d" buff)       => (256)

Switching the byte order will affect all number formats with 16, 32 or 64 bit sizes.

The pack and unpack format need not to be the same; as in the following example:

(set 's (pack "s3" "ABC"))
(unpack "c c c" s) => (65 66 67)

The examples show spaces between the format specifiers. These are not required but can improve readability.

See also address, get-int, get-char, get-string and pack.



until

syntax: (until exp-condition body)

The condition in exp-condition body is evaluated. If the result is nil or the empty list () the expressions in body is evaluated. Evaluation is repeated until an exp-condition results in a value other than nil or the empty list (). The result of the last expression evaluated is the return value of the while expression. until works like (while (not ...)).

example:
(device (open "somefile.txt" "read"))
(set 'line-count 0)
(until (not (read-line)) (inc 'line-count))
(close (device))
(print "the file has " line-count " lines\n")

See also do-until which will test the condition after evaluation of the body expressions.



upper-case

syntax: (upper-case str)

Returns a copy of the string in str converted to uppercase. International characters are converted correctly.

example:
(upper-case "hello world")      => "HELLO WORLD"

See also lower-case.



utf8

syntax: (unicode str)

Converts UCS-4 encoded Unicode of 4 byte integers per character in str into UTF-8 character strings in str to . The function is only available on UTF-8 enabled versions of newLISP.

example:
(unicode "new") 

=> "n\000\000\000e\000\000\000w\000\000\000\000\000\000\000"

(utf8 (unicode "new")) => "new"

The utf8 function can also be used to test for the presence of UTF-8 enabled newLISP:

(if utf8 (do-utf8-version-of-code) (do-ascii-version-of-code))

On big endian CPU architectures the byte order will be reversed from high to low. Both utf8 and the unicode functions are the inverse of each other. These functions are only necessary if UCS-4 Unicode is in use. Most systems use UTF-8 Unicode encoding only.



wait-pid

syntax: (wait-pid int-pid [int-options])

Waits for a child process specified in int-pid to end. The child process was previously started with process or fork. When the child process specified in int-pid ends, a status value describing the termination reason for the child process or thread is returned. The interpretation of the returned status value is different in Linux and different in other flavors of UNIX. Consult the Linux/UNIX man pages for the waitpid command (without the hyphen used in newLISP) for further information.

When specifying -1 for int-pid then status information of any child process started is returned. When specifying 0 only child processes in the same process group as the calling process are watched. Any other negative value for int-pid reports child processes in the same process group as specified with a negative sign in int-pid.

This function is only available on Linux and other UNIX like operating systems or on a CYGWIN compiled version of newLISP on Win32. Optionally an option can be specified in int-option. See Linux/UNIX documentation for details on options.

example:
(set 'pid (fork (my-thread)))

(set 'status (wait-pid pid)) ; wait until my-thread ends

(println "thread: " pid " has finished with status: " status)

The process my-thread is started and the main program blocks in the wait-pid call until my-thread has finished.



while

syntax: (while exp-condition body)

The condition in exp-condition is evaluated. If the result is not nil or the empty list () the expressions in body is evaluated. Evaluation is repeated until an exp-condition results in nil or the empty list (). The result of the last body expression evaluated is the return value of the while expression.

example:
(device (open "somefile.txt" "read"))
(set 'line-count 0)
(while (read-line) (inc 'line-count))
(close (device))
(print "the file has " line-count " lines\n")

See also do-while, which evaluates the condition after evaluating the body expressions.



write-buffer

syntax: (write-buffer int-file sym-buffer [int-size])
syntax: (write-buffer int-file str-buffer [int-size])

syntax: (write-buffer str-device sym-buffer [int-size])
syntax: (write-buffer str-device str-buffer [int-size])

Using the first syntax write-buffer writes int-size bytes from a buffer in sym-buffer or str-buffer to a file specified in int-file. int-file was obtained previously from a file open operation. If int-size is not specified, all data in sym-buffer or str-buffer is written. write-buffer returns the number of bytes written or nil on failure.

The string buffer symbol can be used with or without quoting a symbol.

example:
(set 'handle (open "myfile.ext" "write"))
(write-buffer handle 'data 100)

;; string buffer w/o quote
(write-buffer handle data 100)   
(write-buffer handle "a quick message\n")

The code in the example writes 100 bytes to the file myfile.ext from the contents in data.

Using the second syntax write-buffer appends contents from a string specified in sym-buffer or str-buffer to the string specified in str-device, which acts like a stream device.

example:
;; fast in-place string appending
(set 'str "")
(dotimes (x 5) (write-buffer str "hello"))

str    => "HelloHelloHelloHelloHello")

;; much slower method of string concatenation
(dotimes (x 5) (set 'str (append str "hello")))

The example appends a string in str. This method is much faster then using append when concatenating to a string in place.

See also read-buffer.



write-char

syntax: (write-char int-file int-byte)

Writes a byte specified in int-byte to a file specified by the file handle in int-file. The file handle is obtained from a previous open operation. Each write-char advances the file pointer by one byte.

example:
(define (slow-file-copy from-file to-file)
    (set 'in-file (open from-file "read"))
    (set 'out-file (open to-file "write"))
    (while (set 'chr (read-file in-file))
        (write-char out-file chr))
     (close in-file)
    (close out-file)
    "finished")

See print and device for writing bigger portions of data at a time. Note that newLISP already supplies a faster built-in function copy-file.

See also read-char.



write-file

syntax: (write-file str-file-name str-buffer)

Writes a file in str-file-name with contents in str-buffer in one swoop and returns the number of bytes written.

example:
(write-file "myfile.enc"
    (encrypt (read-file "/home/lisp/myFile") "secret"))

The file myfile is read, then encrypted using the password secret and written back into a new file myfile.enc in the current directory.

See also read-file.



write-line

syntax: (write-line [str] [int-file])
syntax: (write-line [str] [str-device])

The string in str and the line termination character(s) are written to the console or a file. If no file handle is specified using int-file, write-line writes to the current device which is normally the console screen. When omitting all parameters, write-line writes the contents of the last read-line to the screen.

example:
(write-line "hello there")

(set 'out-file (open "myfile" "write"))
(write-line "hello there" out-file)
(close out-file)

(set 'myFile (open "init.lsp" "read")
(while (read-line myFile) (write-line))

;; using a string device:

(set 'str "")
(dotimes (x 4) (write-line "hello" str))

str => "hello\r\nhello\r\nhello\r\nhello\r\n"   ; on Win32

str => "hello\nhello\nhello\nhello\n"   ; on  Linux/UNIX

The first example puts a string out on the current device, which is probably the console window (device 0). The second example opens / creates a file, writes a line to it and closes the file. The third example shows the usage of write-line without arguments. The contents of init.lsp is written to the console screen.

In the second syntax a string can be specified as a device in str-device, similar as used in write-buffer. When writing to a string device the string in str-device gets appended by str and the line termination character(s).



xml-error

syntax: (xml-error)

Returns a list of error information from the last xml-parse operation or nil, if no error occurred. The first element contains text describing the error, the second element is a number indicating the last scan position in the source XML text starting at 0 (zero).

example:
(xml-parse "<atag>hello</atag><fin")  => nil

(xml-error) => ("expected closing tag: >" 18)


xml-parse

syntax: (xml-parse string-xml [int-options])

Parses a string containing XML 1.0 compliant well formed XML. No DTD validation is performed. DTDs (Document Type Declarations) and processing instructions are skipped. Nodes of type ELEMENT, TEXT, CDATA and COMMENT are parsed. A newLISP list structure is returned. When an element node does not have attributes or child nodes, empty lists are contained instead. Attributes are returned as association lists which can be accessed using assoc. When xml-parse fails caused by malformed XML, nil is returned and xml-error can be used to access error information.

example:
(set 'xml 
  "<person name='John Doe' tel='555-1212'>nice guy</person>")

(xml-parse xml) 
=>
(("ELEMENT" "person" 
  (("name" "John Doe") 
   ("tel" "555-1212"))
  (("TEXT" "nice guy"))))

Modifying the translation process.

Optionally int-options can be supplied for suppressing whitespace, empty attribute lists and comments and for transforming tags from strings into symbols. Another function: xml-type-tags serves for translating the XML tags. The following options numbers can be used:

Number Option
1suppress whitespace text tags
2suppress empty attribute lists
4suppress comment tags
8translate string tags into symbols
16add SXML (S-expression XML) attribute tags

Options can be combined by adding the numbers, i.e. 3 would combine the options for suppressing whitespace text tags/info and empty attribute lists.

The following sequence of examples shows how the different options can be used:

XML source:
    <?xml version="1.0" ?>
    <DATABASE name="example.xml">
    <!--This is a data base of fruits-->
        <FRUIT>
	        <NAME>apple</NAME>
		    <COLOR>red</COLOR>
		    <PRICE>0.80</PRICE>
        </FRUIT>

        <FRUIT>
            <NAME>orange</NAME>
            <COLOR>orange</COLOR>
            <PRICE>1.00</PRICE>
        </FRUIT>

        <FRUIT>
           <NAME>banana</NAME>
           <COLOR>yellow</COLOR>
           <PRICE>0.60</PRICE>
        </FRUIT>
    </DATABASE>

Parsing without any options:
(xml-parse (read-file "example.xml"))

=>

 (("ELEMENT" "DATABASE" (("name" "example.xml")) (("TEXT" "\r\n\t") 
    ("COMMENT" "This is a data base of fruits") 
    ("TEXT" "\r\n\t") 
    ("ELEMENT" "FRUIT" () (("TEXT" "\r\n\t\t") ("ELEMENT" "NAME" () 
       (("TEXT" "apple"))) 
      ("TEXT" "\r\n\t\t") 
      ("ELEMENT" "COLOR" () (("TEXT" "red"))) 
      ("TEXT" "\r\n\t\t") 
      ("ELEMENT" "PRICE" () (("TEXT" "0.80"))) 
      ("TEXT" "\r\n\t"))) 
    ("TEXT" "\r\n\r\n\t") 
    ("ELEMENT" "FRUIT" () (("TEXT" "\r\n\t\t") ("ELEMENT" "NAME" () 
       (("TEXT" "orange"))) 
      ("TEXT" "\r\n\t\t") 
      ("ELEMENT" "COLOR" () (("TEXT" "orange"))) 
      ("TEXT" "\r\n\t\t") 
      ("ELEMENT" "PRICE" () (("TEXT" "1.00"))) 
      ("TEXT" "\r\n\t"))) 
    ("TEXT" "\r\n\r\n\t") 
    ("ELEMENT" "FRUIT" () (("TEXT" "\r\n\t\t") ("ELEMENT" "NAME" () 
       (("TEXT" "banana"))) 
      ("TEXT" "\r\n\t\t") 
      ("ELEMENT" "COLOR" () (("TEXT" "yellow"))) 
      ("TEXT" "\r\n\t\t") 
      ("ELEMENT" "PRICE" () (("TEXT" "0.60"))) 
      ("TEXT" "\r\n\t"))) 
    ("TEXT" "\r\n"))))

The TEXT elements containing only white space make the output very confusing. As the database in example.xml only contains data, we can suppress white space and comments with option (+ 1 3):


Filtering white space TEXT, COMMENT tags and empty attribute lists:
 (xml-parse (read-file "example.xml") (+ 1 2 4))

 =>

 (("ELEMENT" "DATABASE" (("name" "example.xml")) ( 
    ("ELEMENT" "FRUIT" () (
      ("ELEMENT" "NAME" (("TEXT" "apple"))) 
      ("ELEMENT" "COLOR" (("TEXT" "red"))) 
      ("ELEMENT" "PRICE" (("TEXT" "0.80"))))) 
    ("ELEMENT" "FRUIT" (
      ("ELEMENT" "NAME" (("TEXT" "orange"))) 
      ("ELEMENT" "COLOR" (("TEXT" "orange"))) 
      ("ELEMENT" "PRICE" (("TEXT" "1.00"))))) 
    ("ELEMENT" "FRUIT" (
      ("ELEMENT" "NAME" (("TEXT" "banana"))) 
      ("ELEMENT" "COLOR" (("TEXT" "yellow"))) 
      ("ELEMENT" "PRICE" (("TEXT" "0.60"))))))))

The resulting output looks much more readable, but still can be improved by using symbols instead of strings for the tags "FRUIT", "NAME", "COLOR" and "PRICE", and by suppressing the XML type tags "ELEMENT" and "TEXT" completely using the xml-type-tags directive:

Suppressing XML type tags with xml-type-tags and translating string tags into symbol tags:
  ;; suppress all XML type tags for TEXT and ELEMENT
  ;; instead of "CDATA" use cdata instead of "COMMENT" use !--

  (xml-type-tags nil 'cdata '!-- nil) 

  ;; turn on all options for suppressing white space and empty
  ;; attributes, translate tags to symbols

  (xml-parse (read-file "example.xml") (+ 1 2 8))

  =>

  ((DATABASE (("name" "example.xml")) 
    (!-- "This is a data base of fruits") 
    (FRUIT (NAME "apple") (COLOR "red") (PRICE "0.80")) 
    (FRUIT (NAME "orange") (COLOR "orange") (PRICE "1.00")) 
    (FRUIT (NAME "banana") (COLOR "yellow") (PRICE "0.60"))))

Specifying nil for the TEXT and ELEMENT XML type tags makes them disappear. At the same time parenthesis of the child node list are removed so that child nodes now appear as members of the list starting with the tag symbol translated from the string tags "FRUIT", "NAME" etc.

Parsing into SXML (S-expressions XML) format:

Using xml-type-tags to suppress all XML-type tags and using the option numbers 1, 4, 8 and 16, SXML formatted output can be generated:

  (xml-type-tags nil nil nil nil)
  (xml-parse (read-file "example.xml") (+ 1 4 8 16))

  =>

  ((DATABASE (@ (name "example.xml")) 
    (FRUIT (NAME "apple") (COLOR "red") (PRICE "0.80")) 
    (FRUIT (NAME "orange") (COLOR "orange") (PRICE "1.00")) 
    (FRUIT (NAME "banana") (COLOR "yellow") (PRICE "0.60"))))

Note that using the option number 16 a @ symbol is added to attributes lists.

See also xml-type-tags for further information on XML parsing.



xml-type-tags

syntax: (xml-type-tags [expr-text-tag expr-cdata-tag expr-comment-tag expr-element-tags])

The XML type tags "TEXT" "CDATA" "COMMENT" and "ELEMENT" can be replaced with something else specified in the parameters or suppressed completely.

Note that xml-type-tags only suppresses or translates the tags themselves but not suppress or modify the tagged information. The latter would be done using option numbers in xml-parse.

Using xml-type-tags with out any parameters returns the current type tags:

example:
(xml-type-tags)   => ("TEXT" "CDATA" "COMMENT" "ELEMENT")

(xml-type-tags nil 'cdata '!-- nil)

The first example just shows the current used type tags. The second example specifies suppression of the "TEXT" and "ELEMENT" tags and shows cdata and !-- instead of "CDATA" and "COMMENT".





newLISP APPENDIX

Error codes

    not enough memory                  1
    environment stack overflow         2
    call stack overflow                3
    problem accessing file             4
    not an expression                  5
    missing parenthesis                6
    string token too long              7
    missing argument                   8
    number or string expected          9
    value expected                    10
    string expected                   11
    symbol expected                   12
    context expected                  13
    symbol or context expected        14
    list expected                     15
    list or symbol expected           16
    list or string expected           17
    list or number expected           18
    array expected                    19
    array, list or string expected    20
    lambda expected                   21
    lambda-macro expected             22
    invalid function                  23
    invalid lambda expression         24
    invalid macro expression          25
    invalid let parameter list        26
    problem saving file               27
    division by zero                  28
    matrix expected                   29
    wrong dimensions                  30
    matrix is singular                31
    syntax in regular expression      32
    throw without catch               33
    problem loading library           34
    import function not found         35
    symbol is protected               36
    error number too high             37
    regular expression                38
    missing end of text [/text]       39
    mismatch in number of arguments   40
    problem in format string          41
    data type and format don't match  42
    invalid parameter: 0.0            43
    invalid parameter: NaN            44
    symbol not in MAIN context        45
    symbol not in current context     46
    array index out of bounds         47
    user error                        48
    user reset -                      49




TCP/IP and UDP Error Codes

 0: No error
 1: Cannot open socket
 2: Host name not known
 3: Not a valid service
 4: Connection failed
 5: Accept failed
 6: Connection closed
 7: Connection broken
 8: Socket send() failed
 9: Socket recv() failed
10: Cannot bind socket
11: Too much sockets in net-select
12: Listen failed
13: Badly formed IP
14: Select failed
15: Peek failed
16: Not a valid socket



Example tcp/ip client

#!/usr/bin/newlisp

;;  client for  client/server demo
;;
;;  USAGE: client hostName
;;
;; 'hostName' contains a string with the name or IP number
;; of the computer running the server application
;;
;; The client prompts for input and sends it to the
;; server which sends it back converted to uppercase
;;
;; The server has to be started first in a different
;; terminal window or on a different computer.
;;
;; v 1.1 changes for changed 'main-args'
;; v 1.2 direct form of net-send
;;

(define (net-client-receive socket , buf)
  (net-receive socket 'buf 256)
  (print "\n" buf "\ninput:")
  (if (= buf "bye bye!") (exit))
  (net-send socket (read-line)))

(define (client host-computer)
  (set 'socket (net-connect host-computer 1111))
  (if (not socket) 
    (print "could not connect, is the server started?\n") 
    (while true (net-client-receive socket))))

(set 'params (main-args))
(if (< (length params) 3) 
  (begin 
    (print "USAGE: client hostName\n")
    (exit)))

(client (nth 2 params))
(exit)

;; eof ;;




Example tcp/ip server

#!/usr/bin/newlisp

;; server for client/server demo
;;
;; USAGE: server
;;
;; Start the client program in a different
;; terminal window or on a different computer
;; See the 'client' file for more info.
;;
;; v 1.1 direct form of net-send
;;

(define (net-server-accept listenSocket)
(while online (begin
    (set 'connect (net-accept listenSocket)) 
	(net-send connect "Connected!\n")
	(while (net-server-receive connect)))))

(define (net-server-receive socket , str)
  (net-receive socket 'str 256)
  (print socket ":" str "\n")
  (if (= str "quit") 
   (begin 
    (net-send socket "bye bye!") 
    (net-close socket) nil) 
   (net-send socket (upper-case str))))

(define (server)
  (if (not (set 'socket (net-listen 1111))) 
   (print "Listen failed:\n" (net-error)) 
   (begin
	(set 'online true)
   	(print "\nServer started\n")
	(net-server-accept socket)
	)))

(server)

; eof ;




Example UDP client

#!/usr/bin/newlisp

; demo client for non-blocking UDP communications
;
; start the server program udp-server.lsp first
;
; note, that net-listen in UDP mode only binds the socket
; to the local address, it does not 'listen' as in TCP/IP
; v.1.0

(set 'socket (net-listen 10002 "" "udp"))
(if (not socket) (println (net-error)))
(while (not (net-error))
	(print "->")
	(net-send-to "127.0.0.1" 10001 (read-line) socket)
	(net-receive socket 'buff 255)
	(println "=>" buff))

; eof




Example UDP server

#!/usr/bin/newlisp

; demo server for non-blocking UDP communications
;
; start this program then start the client udp-client.lsp
;
; note, that net-listen in UDP mode only binds the socket
; to the local address, it does not 'listen' as in TCP/IP
; v.1.0

(set 'socket (net-listen 10001 "" "udp"))
(if socket (println "server listening on port " 10001)
	(println (net-error)))
(while (not (net-error))
	(set 'msg (net-receive-from socket 255))
	(println "->" msg)
        (net-send-to (nth 1 msg) (nth 2 msg) 
        	(upper-case (first msg)) socket))

;; eof




Example threads - consumer, producer

#!/usr/bin/newlisp

# prodcons.lsp -  Producer/consumer
#
# usage of 'fork', 'wait-pid', 'semaphore' and 'share'

(if (> (& (last (sys-info)) 0xF) 4) 
	(begin
		(println "this will not run on Win32")
		(exit)))

(constant 'wait -1 'signal 1 'release 0)

(define (consumer n)
	(set 'i 0)
	(while (< i n)
		(semaphore cons-sem wait)
		(println (set 'i (share data)) " <-")
		(semaphore prod-sem signal))  
	(exit))
		
(define (producer n)
	(for (i 1 n)
		(semaphore prod-sem wait)
		(println "-> " (share data i))
		(semaphore cons-sem signal))   
	(exit))

(define (run n)
	(set 'data (share))	
	(share data 0)

	(set 'prod-sem (semaphore)) ; get semaphores
	(set 'cons-sem (semaphore))

	(set 'prod-pid (fork (producer n))) ; start threads
	(set 'cons-pid (fork (consumer n)))
	(semaphore prod-sem signal) ; get producer started

	(wait-pid prod-pid) ; wait for threads to finish
	(wait-pid cons-pid) ; 
	(semaphore cons-sem release) ; release semaphores
	(semaphore prod-sem release))


(run 10)

(exit)








Example pop3.lsp


;; pop3.lsp - subroutines for mail retrieval
;;
;;  USAGE:
;;
;;  ;; include the pop3 module
;;  (load "/usr/share/newlisp/pop3.lsp")
;;
;;  (POP3:get-all-mail "user" "password" "pop.my-isp.com" "messages/")
;;
;;  loads down all messages and puts them in a directory "messages/"
;;  
;;
;;  (POP3:get-new-mail "user" "password" "pop.my-isp.com" "messages/")
;;
;;  loads down only new messages
;;
;;
;;  (POP3:delete-old-mail "user" "password" "pop.my-isp.com")
;;
;;  deletes messages, which have not been read
;;
;;
;;  (POP3:delete-all-mail "user" "password" "pop.my-isp.com")
;;
;;  deletes all messages
;;
;;
;;  (POP3:get-mail-status "user" "password" "pop.my-isp.com")
;;
;;  gets a list of status numbers (totalMessages, totalBytes, lastRead)
;;
;;
;;  (POP3:get-error-text)
;;
;;  gets error message for failed all/new/status function
;;
;;
;;
;;  version 1.8
;;        


(context 'POP3)

(set 'debug-flag nil)

(define (get-all-mail userName password pop3server mail-dir)
    (and 
        (connect pop3server)
        (logon userName password)
        (set 'status (get-status))
        (set 'no-msgs (nth 2 status))
        (if (> no-msgs 0)
          (get-messages 1 no-msgs mail-dir)
          true)
        (log-off)))

(define (get-new-mail userName password pop3server mail-dir)
    (and 
        (connect pop3server)
        (logon userName password)
        (set 'status (get-status true))
        (if (<= (first status) (nth 2 status))
          (get-messages (first status) (nth 2 status) mail-dir)
          true)
        (log-off)))

(define (get-mail-status userName password pop3server)
    (and 
        (connect pop3server)
        (logon userName password)
        (set 'status (get-status true))
        (log-off)
        status))

(define (delete-old-mail userName password pop3server)
    (and
        (connect pop3server)
        (logon userName password)
        (set 'status (get-status true))
        (if (> (first status) 1) 
            (for (msg 1 (- (first status) 1) ) (delete-message msg))
            true)
        (log-off)
        (first status)))

(define (delete-all-mail userName password pop3server)
    (and
        (connect pop3server)
        (logon userName password)
        (set 'status (get-status))
        (if (> (last status) 0)
            (for (msg 1 (last status) ) (delete-message msg))
            true)
        (log-off)
        (last status)))

;; receive request answer and verify
;;
(define (net-confirm-request)
    (if (net-receive socket 'rcvbuff 512 "+OK")
        (begin
	    (if debug-flag (println rcvbuff))
            (if (find "-ERR" rcvbuff) 
                (finish rcvbuff)
                true))
        nil))

(define (net-flush)
	(if socket
		(while (> (net-peek socket) 0) 
			(net-receive socket 'junk 256)
			(if debug-flag (println junk) )))
	true)

;; connect to server
;;
(define (connect server)
    (set 'socket (net-connect pop3server 110))
    (if (and debug-flag socket) (println "connected on: " socket) )
    (if (and socket (net-confirm-request))
        (net-flush)
        (finish "could not connect")))

;;
(define (logon userName password)
    (and
        (set 'sndbuff (append "USER " userName "\r\n"))
        (net-send socket 'sndbuff)
	(if debug-flag (println "sent: " sndbuff) true)
        (net-confirm-request)
        (net-flush)
        (set 'sndbuff (append "PASS " password "\r\n"))
        (net-send socket 'sndbuff)
	(if debug-flag (println "sent: " sndbuff) true)
        (net-confirm-request)
        (net-flush)
        (if debug-flag (println "logon successful") true)))


;; get status and last read
;;
(define (get-status last-flag)
    (and
        (set 'sndbuff "STAT\r\n")
        (net-send socket 'sndbuff)
	(if debug-flag (println "sent: " sndbuff) true)
        (net-confirm-request)
        (net-receive socket 'status 256)
	(if debug-flag (println "status: " status) true)
        (net-flush)
	(if last-flag 
            (begin
                (set 'sndbuff "LAST\r\n")
                (net-send socket 'sndbuff)
	        (if debug-flag (println "sent: " sndbuff) true)
                (net-confirm-request)
                (net-receive socket 'last-read 256)
	        (if debug-flag (println "last read: " last-read) true)
                (net-flush))
            (set 'last-read "0"))
        (set 'result (list (integer (first (parse status)))))
	(if debug-flag (println "parsed status: " result) true)
        (push (integer (nth 1 (parse status))) result)
        (push (integer (first (parse last-read))) result)
        result))


;; get a message
;;
(define (retrieve-message , message)
	(set 'finished nil)
	(set 'message "")
	(while (not finished)
		(net-receive socket 'rcvbuff 16384)
		(set 'message (append message rcvbuff))
		(if (find "\r\n.\r\n" message) (set 'finished true)))
	(if debug-flag (println "received message") true)
	message)


;; get all messages
;;
(define (get-messages from to mail-dir)
   (if (ends-with mail-dir "/") (set 'mail-dir (chop mail-dir)))
   (if (if (not (directory? mail-dir)) (make-dir mail-dir) true)
       (begin
          (set 'mail-dir (append mail-dir "/"))
          (for (msg from to)
               (if debug-flag (println "getting message " msg) true)
	       (set 'sndbuff (append "RETR " (string msg) "\r\n"))
	       (net-send socket 'sndbuff)
	       (if debug-flag (println "sent: " sndbuff) true)
	       (set 'message (retrieve-message))
               (if debug-flag (println (slice message 1 200)) true)
               (set 'istr (get-message-id message))
	       (set 'istr (append mail-dir "ME-" istr))         
               (if debug-flag (println "saving " istr) true)
               (write-file istr message)
               (if (not (rename-file istr (append istr ".pop3")))
	           (delete-file istr)))))
    true) ; other parts of pop3 rely on 'true' return

;; delete messages
;;
(define (delete-message msg)
    (and
        (set 'sndbuff (append "DELE " (string msg) "\r\n"))
        (net-send socket 'sndbuff)
	(if debug-flag (println "sent: " sndbuff) true)
        (net-confirm-request)))

;; get-message-date was
;; changed to get-message-id
;; v 1.4: CaveGuy

(define (get-message-id message)
    (set 'ipos (+ (find "id <| id |\tid " message 1) 5)
	 'iend (find "@|;|\n|\r| |\t" (slice message ipos) 1))
    (if debug-flag 
	(print "Message ID: " (slice message ipos iend) "\n"))
    (set 'istr (slice message ipos iend)) )


;; log off
;;
(define (log-off)
    (set 'sndbuff "QUIT\r\n")
    (net-send socket 'sndbuff)
    (if debug-flag (println "sent: " sndbuff) true)
    (net-receive socket 'rcvbuff 256)
    (if debug-flag (println rcvbuff) true)
    true)

;; report error and finish
;;
(define (finish message)
    (if (ends-with message "+OK")
      (set 'message (chop message 3)))
    ;(print "<h3>" message "</h3>")
    (set 'mail-error-text message)
    (if debug-flag (println "ERROR: " message) true)
    (if socket (net-flush))
    (if socket (log-off))
    nil)

(define (get-error-text) mail-error-text)

(context 'MAIN)


;;(if (not(POP3:get-all-mail "user" "password" "my-isp.com" "mail"))
;;    (print (POP3:get-error-text)) true)


;;(POP3:get-new-mail "user" "password" "my-isp.com" "mail")
;;(print (POP3:get-mail-status ""user" "password" "my-isp.com")
;;(exit)

;; eof





Example smtp.lsp


;;  smtp.lsp - routines for sending mail
;;
;;  v.1.1 cleanup and comments
;;  v.1.2 better error reporting when (set 'debug-flag true)
;;  v.1.3 inserted empty line before body
;;  v.1.4 forgot to check for "\r\n" in confirm request
;;        rearranged function calls for shorter code
;;        USAGE was incomplete
;;  v.1.5 changes sys-info version ref
;;

(context 'SMTP)

(set 'debug-flag nil)

;; this is the main function to use
;;
;;  USAGE:
;;
;;  ;; include the smtp module
;;  (load "/usr/share/newlisp/smtp.lsp")
;;
;;   (SMTP:send-mail "jdoe@asite.com" "somebody@isp.com" "" "Greetings"
;;                   "How are you today? - john doe -" "smtp.asite.com")
;;
;;   will send mail from address: jdoe@asite.com
;;                    to address: somebody@isp.com
;;                  subject line: Greetings
;;                  message body: Hoe are you today? - john doe-
;;                     smtp host: smtp.asite.com
;;

(define (send-mail mail-from mail-to mail-subject mail-body SMTP-server)
    (and
        (set 'from-hostname (nth 1 (parse mail-from "@")))
        (set 'socket (net-connect SMTP-server 25))
        (confirm-request "2")
        (net-send-get-result (append "HELO " from-hostname) "2")
        (net-send-get-result (append "MAIL FROM: " mail-from) "2")
        (net-send-get-result (append "RCPT TO: " mail-to) "2")
        (net-send-get-result "DATA" "3")
        (mail-send-header)
        (mail-send-body)
        (confirm-request "2")
        (net-send-get-result "QUIT" "2")
        (or (net-close socket) true)))

(define (confirm-request conf)
   (and
    (net-receive socket 'recvbuff 256 "\r\n")
    (if debug-flag (println recvbuff) true)
    (starts-with recvbuff conf)))
  
(define (net-send-get-result str conf)
   (set 'send-str (append str "\r\n"))
   (if debug-flag (println "sent: " send-str)) 
   (net-send socket 'send-str)
   (if conf (confirm-request conf) true))

(define (mail-send-header)
    (net-send-get-result (append "TO: " mail-to))
    (net-send-get-result (append "FROM: " mail-from))
    (net-send-get-result (append "SUBJECT: " mail-subject))
    (net-send-get-result (append "X-Mailer: newLISP v." 
    				(string (nth -2 (sys-info)))))) 

(define (mail-send-body )
    (net-send-get-result "")
    (dolist (lne (parse mail-body "\r\n")) 
        (if (= lne ".") 
            (net-send-get-result "..")
            (net-send-get-result lne)))
    (net-send-get-result "."))

(define (get-error-text)
    recvbuff)

(context 'MAIN)

;; eof





Example ftp

;; ftp.lsp - module for newLISP for FTP transfers
;;
;; v.1.0
;;
;; v.1.1 will not hang on wrong file permissions
;;       changed position of STAT
;;
;; v.1.2 accept "" instead of "."  for sub directory
;;
;; example:
;;
;; (FTP:put "somebody" "secret" "host.com" "subdir" "file")  ;; upload
;;
;; (FTP:get "somebody" "secret" "host.com" "subdir" "file")  ;; download
;;
;; returns 'true' on success else 'nil' and check the variable FTP:result
;; for the last result message from the ftp host
;;
;; to set debug mode, which shows all dialog with the server:
;;
;; (set 'FTP:debug-flag true)
;;
;;
;;

(context 'FTP)

;; debugging mode
(set 'debug-mode nil)

;; mode of transfer
(define GET 1)
(define PUT 2)

(define (get user-id password host subdir file-name)
    (transfer user-id password host subdir file-name GET))


(define (put user-id password host subdir file-name)
    (transfer user-id password host subdir file-name PUT))


(define (transfer user-id password host subdir file-name mode)
  (if (= subdir "") (set 'subdir "."))
  (and
    (connect-to host 21)
    (send-get-result (append "USER " user-id "\r\n") "3")
    (send-get-result (append "PASS " password "\r\n") "2")
    (send-get-result (append "CWD " subdir "\r\n") "2")
    (send-get-result "TYPE I\r\n" "2")
    (set 'buff (send-get-result "PASV\r\n" "2"))
    (regex {(\d+),(\d+),(\d+),(\d+),(\d+),(\d+)} buff)
    (set 'port (+ (* 256 (integer $5)) (integer $6)))
    (set 'ip (string $1 "." $2 "." $3 "." $4))
    (set 'socket2 (net-connect ip port))

    (if (= mode PUT)
        (and
            (check-file file-name)
            (net-send socket (append "STOR " file-name "\r\n"))
            (send-get-result "STAT\r\n" "1")
            (set 'fle (open file-name "r"))
            (while (> (read-buffer fle 'buffer 512) 0)
                (if debug-mode (print "."))
                (net-send socket2 buffer 512))
            (close fle)) true)

    (if (= mode GET)
        (and
            (net-send socket (append "RETR " file-name "\r\n"))
            (send-get-result "STAT\r\n" "1")
            (set 'fle (open file-name "w"))
            (while (net-receive socket2 'buffer 512)
                (if debug-mode (print "."))
                (write-buffer fle buffer))
            (close fle)) true)

    (or (net-close socket2) true)
    (net-send socket "QUIT\r\n")
    (or (net-close socket) true)))


(define (send-get-result str code)
    (net-send socket str)
    (if debug-mode (println "sent:" str))
    (net-receive socket 'result 256 "\r\n")
    (if debug-mode (println result))
    (if (starts-with result code) result))


(define (connect-to host port)
    (set 'FTP:result nil)
    (set 'socket (net-connect host port))
    (if socket
        (net-receive socket 'result 256 "\r\n")
        (begin
            (set 'result "could not connect")
            nil)))    
    
(define (check-file file-name)
    (if (file? file-name)
        true
        (begin
            (set 'result (append file-name " does not exist"))
            nil)))

(context 'MAIN)

;; test
;
;(set 'FTP:debug-mode true)
;
;(FTP:put "userid" "password" "site.com" "tmp" "testfile")
;
;(FTP:get "userid" "password" "site.com" "tmp" "testfile")
;
;(exit)

;; eof




Example httpd web server


#!/usr/bin/newlisp
;
; httpd - web server v.4.0
; handles cgi but no cookies
;
; does GET and POST requests
;
; USAGE: httpd portNo rootDir
;
; EXAMPLE Linux: httpd 80 /home/httpd/html/
; 
; EXAMPLE Win32: newlisp.exe httpd 80 /home/httpd/html/
;

(context 'HTTPD)

(define version "4.0")

(define debug-flag nil)

(set 'os (& 0xF (last (sys-info))))

(set 'exe-extensions '(
	"cgi"
	"lsp"))

(set 'default-files '("index.html" "index.cgi"))

(set 'mime-types '(
  ("txt" "text/plain")
  ("html" "text/html")
  ("shtml" "text/html")
  ("htm" "text/html")
  ("gif" "image/gif")
  ("jpg" "image/jpeg")
  ("jpeg" "image/jpeg")
  ("png" "image/png")
  ("jar" "application/java-archive")
  ("class" "application/java")
  ("pdf" "application/pdf")))


(set 'cgi-header (append
    "HTTP/1.0 200 OK\r\n"
    "Server: newLISP v." 
    (string (nth -2 (sys-info))) 
    " HTTPD v." version "\r\n"))

(define (startServer port dir)
  (if (not (set 'socket (net-listen (integer port)))) 
    (print "Listen failed: " (net-error) "\n") 
    (begin
      (set 'online true)
        (set 'root-dir dir)
        (print "Server started listening on port: " port "\n")
        (print "Root directory: " root-dir "\n")
        (if (not (change-dir root-dir))
		(begin
			(println "Could not change to: " root-dir)
			(exit)))
        (net-server-accept socket))))

(define (net-server-accept listenSocket)
  (while online 
    (if (set 'connection (net-accept listenSocket))
      (begin
        (if (net-receive connection 'buff 2024 "\r\n\r\n")
          (begin
            (process-http-request buff)
            (net-close connection)))))))

(define (process-http-request request)
  (set 'request-type (first (parse request)))
  (if debug-flag (print request))
  (log-request request)
  (case request-type
    ("GET" (process-GET-request request))
    ("POST" (process-POST-request request))
    ("HEAD" (process-HEAD-request request))
    (true (html-error 400 "Cannot handle request"))))


(define (process-GET-request request)
  (set 'query (nth 1 (parse (first (parse request "\r\n")) " ")))

  (if (starts-with query "http://" nil) 
    (begin
      (set 'query (slice query 7))
      (set 'query (slice query (find "/" query)))))

  (set 'query (slice query 1))
  (if (= query "") 
    (begin
      (set 'query (first default-files))
      (dolist (fle default-files)
        (if (file? fle) (set 'query fle)))))

  (if (set 'pos (find "?" query))
    (begin
      (set 'queryData (slice query (+ pos 1)))
	(env "QUERY_STRING" queryData)
	 (set 'query (first (parse query "?")))
      (execute-file query (append queryData "\r\n")))
    (begin	
	(env "QUERY_STRING" "")
      (if (find {.*\.\..*} query 0)
        (html-error 405 "Access not allowed")
	  (if (has-exe-extension query)
		(execute-file query "")
  		(send-file query))))))


(define (process-POST-request request)
  (if (find ".*content-length:(.*)" request 1)
    (begin
        (set 'contentLength (integer (trim $1)))
        (set 'postData (receive-POST-data contentLength))) 
    (set 'postData (net-receive connection 'data 1024)))
  (if debug-flag (print postData "\n"))
  (set 'query (nth 1 (parse (first (parse request "\r\n")))))
  (if (find {.*\.\..*} query 0)
    (html-error 405 "Access not allowed")
    (execute-file query postData)))

(define (receive-POST-data len)
  (set 'page '(""))
  (set 'receivedBytes 0)
  (set 'bytes 0)
  (while (and bytes (< receivedBytes len))
    (if (set 'bytes (net-receive connection 'data len))
	(inc 'receivedBytes bytes))
    (push data page))
  ; drain socket 
  (while (net-select connection "read" 500)
	(net-receive connection 'data 1024))
  (join (reverse page)))

(define (process-HEAD-request request)
  (html-error 400 "Cannot handle request"))

(define (has-exe-extension fileName)
  (find (extension fileName) exe-extensions))

(define (extension fname)
  (if (find ".*\\.(.*)" fname 0) 
   (trim $1) ""))

(define (send-file fileName)
  (set 'ext (extension fileName))
  (if (not (set 'mime-type (assoc ext mime-types)))
    (html-error 405 "Filetype not allowed")
    (begin
      (set 'buffer (read-file fileName))
      (if (not buffer)
        (html-error 404 (append "File not found: " fileName) )
        (begin
          (set 'header (make-header mime-type fileName))
          (net-send connection header)
          (net-send connection buffer))))))

(define (make-header mimeType fileName)
  (append "HTTP/1.0 200 OK\r\n"
          "Server: newLISP HTTPD v." version "\r\n"
          "Content-type: " (nth 1 mimeType) "\r\n"
          "Content-length: "
          (string (first (file-info fileName)))
          "\r\n\r\n"))

(define (execute-file fileName data)
  (if (starts-with fileName "/") (set 'fileName (slice fileName 1)))
  (if (not (file? (append "./" fileName)))
    (html-error 404 (append "File not found: ./" fileName) )
    (begin
      (if (or (= os 5) (= os 6))
        (set 'procStr (append "newlisp ./" fileName " > /tmp/pcgi" ));win32
        (set 'procStr (append "./" fileName " > /tmp/pcgi" )))       ;UNIX
      (if debug-flag (println procStr))
      (exec procStr data)
      (set 'buffer (read-file "/tmp/pcgi"))
      (replace "\r\r\n" buffer "\r\n")
      (set 'header "HTTP/1.0 200 OK\r\n")
      (if (not buffer)
        (html-error 400 "Cannot handle request")
        (begin
            (net-send connection cgi-header)
            (net-send connection buffer))))))

(define (log-request request)
  (print (date (apply date-value (now))) " " 
    (first (net-peer connection)) " "
    (first (parse request "\r\n")) "\n" ))
  
(define (html-error error-no error-txt)
  (set 'header "HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n")
  (set 'message (append
    "<HTML><H1>newLISP v." 
    (string (nth -2 (sys-info))) " 
    HTTPD v." version "<BR>"
    "Error: "  (string error-no) " " 
    error-txt "
</H1></HTML>")) (set 'buffer (append header message )) (net-send connection buffer)) (context 'MAIN) ### MAIN ENTRY POINT ### (set 'params (main-args)) (if (< (length params) 3) (begin (print "USAGE: httpd portNumber rootDirectory\n") (exit))) (print (HTTPD:startServer (nth 2 params) (nth 3 params))) (exit) # eof




Example infix expression parser

;; infix.lsp - parses an infix, prefix and postfix expressions in a 
;;             string and returns a newLISP expression, which can be
;;             evaluated, captures syntax errors
;;
;; version 1.6
;;
;; USAGE:  (INFIX:xlate expression-str)
;;
;; when 'nil is returned then the error message is in 'result
;; else when 'true is returned the newLISP expression is in result
;;        
;;
;; EXAMPLES:
;;
;; (INFIX:xlate "3 + 4") => (add 3 4) ;; parses infix
;; (INFIX:xlate "+ 3 4") => (add 3 4) ;; parses prefix s-expressions
;; (INFIX:xlate "3 4 +") => (add 2 4) ;; parses postfix
;;
;; (INFIX:xlate "3 + * 4") => "ERR: missing argument for +"
;;
;; (eval (INFIX:xlate "3 + 4")) => 7
;;
;; (INFIX:xlate "(3 + 4) * (5 - 2)")  => (mul (add 3 4) (sub 5 2))
;;
;; (INFIX:xlate "(a + b) ^ 2 + (a - b) ^ 2") 
;;    => (add (pow (add a b) 2) (pow (sub a b) 2))
;;
;; (INFIX:xlate "x = (3 + sin(20)) * (5 - 2)")  
;;    => (set! x (mul (add 3 (sin 20)) (sub 5 2)))
;;
;; (INFIX:xlate "x = (3 + sin(10 - 2)) * (5 - 2)")  
;;    => (set! x (mul (add 3 (sin (sub 10 2))) (sub 5 2)))
;;
;; 
;; note that the parser requires operators, variables and constants
;; surrounded by spaces except where parenthesis are used.
;;

;; operator priority table
;; (token operator arg-count priority)
;;
(context 'INFIX)

(set 'operators '(
  ("=" set! 2 2) 
  ("+" add 2 3) 
  ("-" sub 2 3) 
  ("*" mul 2 4) 
  ("/" div 2 4)
  ("^" pow 2 5)
  ("sin" sin 1 9)
  ("cos" cos 1 9)
  ))


(define (xlate str)
  (if (catch (infix-xlate str) 'result)
    result                     ;; if starts with ERR: is error else result
    (append "ERR: " result)))  ;; newLISP error has occurred


(define (infix-xlate str)
  (set 'tokens (parse str))
  (set 'varstack '())
  (set 'opstack '())
  (dolist (tkn tokens)
	(case tkn
        ("(" (push tkn opstack))
        (")" (close-parenthesis))
        (true (if (assoc tkn operators)
                  (process-op tkn)
                  (push tkn varstack)))))
  (while (not (empty? opstack))
        (make-expression))

  (set 'result (first varstack))
  (if (or (> (length varstack) 1) (not (list? result)))
    (throw "ERR: wrong syntax")
    result))


;; pop all operators and make expressions
;; until an open parenthesis is found
;;
(define (close-parenthesis)
 (while (not (= (first opstack) "("))
    (make-expression))
 (pop opstack))
  

;; pop all operator, which have higher/equal priority
;; and make expressions
;;
(define (process-op tkn)
  (if (not (empty? opstack))
      (while (<= (lookup tkn operators 3) 
                    (lookup (first opstack) operators 3))
        (make-expression)))
  (push tkn opstack))

;; pops an operator from the opstack and makes/returns an
;; newLISP expression
;;
(define (make-expression)
  (set 'expression '())
  (if (empty? opstack) 
        (throw "ERR: missing parenthesis"))
  (set 'ops (pop opstack))
  (set 'op (lookup ops operators 1))
  (set 'nops (lookup ops operators 2))
  (dotimes (n nops)
    (if (empty? varstack) 
    	(throw (append "ERR: missing argument for " ops)))
    (set 'vars (pop varstack))
    (if (atom? vars)
            (if (not (or (set 'var (float vars))
			 (and (legal? vars) (set 'var (symbol vars))) ))
                (throw (append vars "ERR: is not a variable"))
                (push var expression))
            (push vars expression)))
  (push op expression)
  (push expression varstack))

(context 'MAIN)
    
;; eof ;;





GNU Free Documentation License

Version 1.2, November 2002

Copyright (C) 2000,2001,2002 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.



0. PREAMBLE

The purpose of this License is to make a manual, textbook, or other functional and useful document "free" in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others.

This License is a kind of "copyleft", which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software.

We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference.

1. APPLICABILITY AND DEFINITIONS

This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The "Document", below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as "you". You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law.

A "Modified Version" of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language.

A "Secondary Section" is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document's overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them.

The "Invariant Sections" are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it is not allowed to be designated as Invariant. The Document may contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none.

The "Cover Texts" are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words.

A "Transparent" copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not "Transparent" is called "Opaque".

Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML, PostScript or PDF designed for human modification. Examples of transparent image formats include PNG, XCF and JPG. Opaque formats include proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine-generated HTML, PostScript or PDF produced by some word processors for output purposes only.

The "Title Page" means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, "Title Page" means the text near the most prominent appearance of the work's title, preceding the beginning of the body of the text.

A section "Entitled XYZ" means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as "Acknowledgements", "Dedications", "Endorsements", or "History".) To "Preserve the Title" of such a section when you modify the Document means that it remains a section "Entitled XYZ" according to this definition.

The Document may include Warranty Disclaimers next to the notice which states that this License applies to the Document. These Warranty Disclaimers are considered to be included by reference in this License, but only as regards disclaiming warranties: any other implication that these Warranty Disclaimers may have is void and has no effect on the meaning of this License.

2. VERBATIM COPYING

You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3.

You may also lend copies, under the same conditions stated above, and you may publicly display copies.

3. COPYING IN QUANTITY

If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and the Document's license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects.

If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages.

If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computer-network location from which the general network-using public has access to download using public-standard network protocols a complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public.

It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document.

4. MODIFICATIONS

You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version:

  • A. Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions (which should, if there were any, be listed in the History section of the Document). You may use the same title as a previous version if the original publisher of that version gives permission.
  • B. List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modifications in the Modified Version, together with at least five of the principal authors of the Document (all of its principal authors, if it has fewer than five), unless they release you from this requirement.
  • C. State on the Title page the name of the publisher of the Modified Version, as the publisher.
  • D. Preserve all the copyright notices of the Document.
  • E. Add an appropriate copyright notice for your modifications adjacent to the other copyright notices.
  • F. Include, immediately after the copyright notices, a license notice giving the public permission to use the Modified Version under the terms of this License, in the form shown in the Addendum below.
  • G. Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document's license notice.
  • H. Include an unaltered copy of this License.
  • I. Preserve the section Entitled "History", Preserve its Title, and add to it an item stating at least the title, year, new authors, and publisher of the Modified Version as given on the Title Page. If there is no section Entitled "History" in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the previous sentence.
  • J. Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the "History" section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission.
  • K. For any section Entitled "Acknowledgements" or "Dedications", Preserve the Title of the section, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein.
  • L. Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles.
  • M. Delete any section Entitled "Endorsements". Such a section may not be included in the Modified Version.
  • N. Do not retitle any existing section to be Entitled "Endorsements" or to conflict in title with any Invariant Section.
  • O. Preserve any Warranty Disclaimers.

If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version's license notice. These titles must be distinct from any other section titles.

You may add a section Entitled "Endorsements", provided it contains nothing but endorsements of your Modified Version by various parties--for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard.

You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one.

The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version.

5. COMBINING DOCUMENTS

You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers.

The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work.

In the combination, you must combine any sections Entitled "History" in the various original documents, forming one section Entitled "History"; likewise combine any sections Entitled "Acknowledgements", and any sections Entitled "Dedications". You must delete all sections Entitled "Endorsements."

6. COLLECTIONS OF DOCUMENTS

You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects.

You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document.

7. AGGREGATION WITH INDEPENDENT WORKS

A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, is called an "aggregate" if the copyright resulting from the compilation is not used to limit the legal rights of the compilation's users beyond what the individual works permit. When the Document is included in an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document.

If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half of the entire aggregate, the Document's Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the whole aggregate.

8. TRANSLATION

Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License, and all the license notices in the Document, and any Warranty Disclaimers, provided that you also include the original English version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the original version of this License or a notice or disclaimer, the original version will prevail.

If a section in the Document is Entitled "Acknowledgements", "Dedications", or "History", the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title.

9. TERMINATION

You may not copy, modify, sublicense, or distribute the Document except as expressly provided for under this License. Any other attempt to copy, modify, sublicense or distribute the Document is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.

10. FUTURE REVISIONS OF THIS LICENSE

The Free Software Foundation may publish new, revised versions of the GNU Free Documentation License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. See http://www.gnu.org/copyleft/.

Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License "or any later version" applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation.








GNU GENERAL PUBLIC LICENSE

Version 2, June 1991

Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.



PREAMBLE

The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too.

When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.

To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.

For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.

We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.

Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.

Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.

The precise terms and conditions for copying, distribution and modification follow.



GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".

Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.

1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.

You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.

2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:

a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.

b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.

c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)

These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.

Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.

In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.

3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:

a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,

b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,

c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)

The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.

If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.

4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.

5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.

6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.

7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.

If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.

It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.

This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.

8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.

9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.

Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.

10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.



NO WARRANTY

11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.





END OF TERMS AND CONDITIONS