Introduction
Deprecated functions
Command line options and directories
Shared library module for Linux/BSD
DLL module for Win32 versions
Evaluating newLISP expressions
Lambda expressions in newLISP
nil, true, cons and () in newLISP
Destructive versus non-destructive functions
Dynamic and lexical scoping
Contexts
Programming with context objects
Arrays
Hash tables
Customization, localization and UTF-8
Commas in parameter lists
purelisp.lsp, the consistency of newLISP
Linking newLISP source and executable
Syntax of symbol variables and numbers
Data types and names in the reference
Indexing elements of strings, lists and arrays
List processing, flow control and integer arithmetic
Bit operators
Floating point math and special functions
Matrix functions
Array functions
Financial math functions
Time and date functions
String and conversion functions
File and I/O operations
Processes, pipes and threads
File and directory management
System functions and predicates
Socket TCP/IP and UDP Network API
!+-*/<>= A B C D E F G I J L M N O P Q R S T U W X
Error Codes
TCP/IP and UDP Error Codes
TCP/IP Client Example
TCP/IP Server Example
UDP Client Example
UDP Server Example
Threads, consumer - producer
POP3 Example
SMTP Example
FTP Example
HTTPD Web Server Example
Infix Expression Parser
GNU Free Documentation License
GNU General Public License
newLISP focuses on the very core components of LISP: Lists, Symbols and Lambda expressions. To these core elements newLISP adds arrays, dynamic scoping of variables and lexically separated namespaces via contexts.
The result is an easier to learn LISP, even smaller than most 'Scheme' implementations, but with over 250 built-in functions, only about 140k 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 (namespaces). Contexts can be used to create isolated, protected expansion packages for newLISP and for prototype based object oriented programming.
Lambda expressions and user-defined functions in newLISP can be manipulated like any other list expression.
Variables, built-in functions and user-defined functions share the same namespace and can be manipulated by the same functions. Functions are available to protect symbols from accidental changes.
Contexts in newLISP facilitate the development of bigger applications in newLISP composed from different independent developed modules with their own lexically separated namespace. Contexts can also be copied and dynamically assigned to variables during runtime and passed as parameters. In this way contexts can serve as dynamically created objects packaging symbols and methods and with lexical separation of their namespaces.
Like Scheme newLISP evaluates the operator element of a list expression.
newLISP's efficient red-black-tree symbol implementation can handle millions of symbols without degrading performance. Contexts can hold symbol-value pairs simulating hashtables. Functions are available for iterative access of symbols in contexts.
newLISP allocates and reclaims memory automatically without the typical kind of garbage collection. Only under error conditions does newLISP resort to garbage collection. Excepting symbols and built-in primitives, each object is referenced only once in the system and is always passed by value. Memory is automatically deallocated when dereferencing objects. This results in predictable and repeatable processing times. newLISP's unique memory management makes it the fastest interactive LISP available.
Many of newLISP's built-in functions are polymorphic in type, accepting a variety - and sometimes all - 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 (nth, set-nth, push, pop) can access multidimensional lists to modify, insert or delete any element in a complex nested LISP list or array structure .
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 TCP/IP and UDP socket interface makes 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 this distribution.
The newLISP source distribution can be compiled for LINUX, FreeBSD, MacOSX/Darwin, Solaris, CYGWIN, and WIN-32.
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.
newLISP-tk is a replacement of the older native Win32 version of newLISP. As newLISP can be compiled on most operating systems including Win32 and 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.
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 or environment, please contact http://nuevatec.com for different arrangements.
newLISP tries to stay current in functionality offered and small in executable size and memory footprint. The following functions will be removed in newLISP v.8.2.0. All have a functional replacement.
All functions marked as deprecated in earlier versions have been removed. All deprecated functions have replacements with identical or similar functionality. These are the deprecated functions and their replacements:
getenv | get an environment variable. Use the equivalent (env var) instead. |
putenv | put an environment variable. Use the equivalent (env var value) instead. |
environ | Get all environment variables. Use the equivalent (env) instead. |
match for strings | Match a pattern string and a string. Use the functional similar find or regex instead. |
collect | Collect elements from a list, use type polymorph select instead. |
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).
newlisp -s 4000 newlisp 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.
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 memory usage.
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.
To also suppress return values from evaluations use silent.
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 to run the process in the background. Now connect with telnet:
telnet localhost 1234
If connected, the newLISP sign-on banner and prompt appear.
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 logfile 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.
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 logfile 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 tag have to appear each on separate lines.
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.
newlisp -h
On LINUX, BSD, and OSX, the initialization file is /usr/share/newlisp/init.lsp. On Win32, it's init.lsp, installed in the same directory, c:\newlisp, as newlisp.exe. 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 strictly 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 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.
On Win32 systems all files are installed in one directory, by default C:\newlisp\. If a init.lsp file is present, it should be in the same directory where newlisp.exe resides.
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.
On Win32 platforms newLISP can be compiled as a DLL (Dynamic Link Library). In this way newLISP function can be made available to other programs using this platform, e.g., MS Excel, 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.
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.
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.
newLISP has two types of basic arithmetic operators: +, -, *, / perform integer arithmetic converting all parameters passed to integers, while the functions add, sub, mul and div convert all arguments passed 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 :
(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 +, -, *, /.
Note that all looping variables in the functions dotimes and for are floating point numbers.
But care must be taken when using functions imported from libraries, which take integer arguments, because after redefining +, -, *, /, numbers, which are the result of arithmetic operations could be passed to imported library functions in double floating point when a integer format is required. In this case floating point numbers can be converted to integers using integer. Likewise integer numbers returned can be transformed to double floats using float:
(import "mylib.dll" "foo") ; importing 'C' int foo(int x) (foo (integer x)) ; make sure argument is passed as integer (foo (float y)) ; force argument to be passed as double float
Note that most newLISP users leave =, -, *, / defined as integer operators and use add, sub, mul and div explicitly when required.
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 and may have different delimiters:
"hello" => "hello" "\032\032\065\032" => " A " "\t\r\n" => "\t\r\n" {this "is" a string} => "this \"is\" a string" ;; [text], [/text] tags for text longer 2048 bytes [text]this too[/text] => "this too"
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 quote is often used to protect an expression from evaluation, e.g., when referring to a symbol itself instead of its contents.
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
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.
When evaluating from the command line, the evaluation result is printed in the console window.
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.
Lambda expressions in newLISP evaluate to themselves and can always be treated as lists:
(set 'double (lambda (x) (+ x x)) (set 'double (fn (x) (+ x x)) ;; alternative syntax (last double) => (+ x x) ;; treat lambda as a list
This would not be possible in other LISPs, where lambda evaluates to a new data type function or closure and its inside is not accessible anymore after evaluating. The previous example would cause an error in Common Lisp or Scheme. In newLISP a lambda expression always stays a lambda list data type. 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 can be seen as a special subtype lambda list of 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. Many of the differences between how macros with define-macro work in newLISP and how they work in other LISPs are rooted in the details outlined here.
Just like in other LISPs Lambda expressions in newLISP can be applied or mapped to parameters to work as user-defined or 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
But unlike other LISPs 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 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
Treating lambda expressions always as lists and not as a special function data type after evaluation gives newLISP greater flexibility when constructing, changing, or analyzing lambda expressions at run time.
This increases the power of functional abstraction in newLISP. Functional abstraction is one of the distinguishing features of LISPs compared to other programming languages.
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 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
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! | sets 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 |
When the content of variables or lists is changed, newLISP automatically discards unused data objects during evaluation, and each data object is referenced only once (except for symbols and built-in primitives). This makes periodic garbage collection unnecessary.
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).
Contexts in newLISP constitute different namespaces. Each namespace 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. Since version 7.2.7 contexts can also be copied and dynamically assigned to variables or passed as parameters during runtime. Because contexts have their own lexically separated namespaces, 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 here 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 need not be created by the user.
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
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.
Global symbols and built-in functions symbols can be overwritten inside a context by explicitly prefixing them with the context symbol:
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.(context 'Account) (define (Account:new ...) ...) (context 'MAIN)
Since newLISP version 8.2.6 global symbols from MAIN are serialized correctly when using save or source.
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
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.
As contexts are lexically isolated from each other and can hold variables and methods, they can be used for 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 template 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 template context using the function new. Note that OO programming purists would use getter and setter functions to access object variables. This is not recommended 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.
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.
Dynamic context variables can be used inside a context. This can be used to create object classes with a make-new method. This make-new method can be used to initialize variables in the instantiated object:
(constant (global 'Class) context) ;; just for 'looks' (Class '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
A context can contain a user defined function or macro with the same name as the context. A function like this is called a default function. When trying to apply a context as a function, newLISP will execute this default function. example:
(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) (context 'fubar) ;; definition of previously declared default function (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.
Serializing a software object is the process of making it persistent by converting it to a 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 file mycontext.lsp (load "mycontext.lsp") ; loads MyCtx into memory
Multiple context objects can be saved in one statement. See the function save for details.
Arrays is 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 frontend, 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.
Like with 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.
newLISP has no built-in hash tables but can simulate hash tables very efficiently with symbols. The file hash.lsp from the distribution displayed here contains functions for creating and managing hash tables in an object oriented fashion:
;; ;; 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 ;; ;; 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) ;; use default function as constructor (new 'MAIN:HASH this))) ;; use new to copy ;; in the new context 'this' will point to it (constant 'put (lambda (key value) (set (symbol key this) value))) (constant 'get (lambda (key) (eval (symbol key this)))) (constant 'keys (lambda () (map name (difference (symbols this) ;; subtract illegal keys (append '(this put get key keys value values) (list (symbol (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 ...).
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 'squareroot' (constant 'imprime print) ;; Spanish for 'print' ...
newLISP can switch to the locale used on your platform and operating system. Upon startup, newLISP attempts to set the ISO C standard default 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.
newLISP can be compiled as an UTF-8 enabled application. UTF-8 is a multibyte 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:
export LC_CTYPE=en_US.UTF-8
The following procedure now can be used to check UTF-8 support: After starting newLISP type the following in newLISP:LC_CTYPE=en_US.UTF-8 xterm
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.(char 937) ;; displays Greek upper case omega (lower-case (char 937)) ;; displays lower case omega
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 |
collect | collect and permute elements from a list or string |
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 in str
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 behaviour.
Two new functions are available to convert between 4-byte size Unicode (UCS-4) and and multibyte 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
(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 for another possibility to declare and initialize local variables.
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 prepended "_" 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)))))
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:
newlisp link.lsp
(link "newlisp.exe" "uppercase.exe" "uppercase.lsp")Or on LINUX/BSD type:
(link "newlisp" "uppercase" "uppercase.lsp")
uppercase "convert me to uppercase"This will print:
CONVERT ME TO UPPERCASEin 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 uppercaseThis will give the file executable permission. On Win32 this step is not necessary.
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 behaviour of newLISP's internal parser.
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 symbol can be used to create symbols which are not legal as newLISP variables but useful for creating hash like lookup dictionaries:
(set (symbol 1) 123) => 123 (eval (symbol 1)) => 123 1 => 1 (+ 1 2) => 3
The 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.
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
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."
true, nil, (<= X 10)
123, 5, (* X 5)
1.234, (div 10 3), (sin 1)
((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
"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 text, i.e. HTML. [/text])
Since version 7.1.0 the delimiters [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.
'xyz, (first '(+ - /)), '*, '- , 'someSymbol,
Most of the time context symbols in this manual start with an uppercase letter for easier distinction from normal symbols.MyContext, aCtx
+, add, (first '(add sub)), (lambda (x) (+ x x))
(a b c "hello" (+ 3 4))
1 7.8 nil (+ 3 4) "Hi" (+ a b)(print result) (do-this)(do-that) 123
Elements of strings (characters) or elements of lists or arrays are specified in some functions by an int-index. The (positive) indexes run 0,1,...,N-2,N-1 where N is the number of elements in the list. If the 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, and an index less than -N returns the first when in lists, but out of bounds indices in arrays will cause an error message.
+, -, *, /,% integer arithmetic <, >, =, compare any data type: less, greater, equal <=, >=, != compare any data type: less-equal, greater-equal, not-equal 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 collect collect and permute elements from a list or string 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 namespace/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 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 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 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 shift left, bit shift right & bitwise and | bitwise inclusive or ^ bitwise exclusive or ~ bitwise not
abs calculate the absolute value of a number acos calculate the arccosine 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 crit-chi2 calculate the Chi square for a given probability crit-z calculate the normal distributed Z for a given probability cos calculate the cosine of a number dec decrement a number div divide floating point or integer numbers exp calculate the exponential e to a number 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 generate a list of normal distributed floating point numbers pow calculate x to the power of y prob-chi2 calculate the cumulated probability of an observed Chi square prob-z calculate the cumulated probability of a Z value sequence generate a list sequence of numbers series create a list with 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
invert return the inversion of a matrix multiply multiply to matrices transpose return the transposition of a matrix
array create and initialize an array with up to 8 indices 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 set-nth change the element and returns the changed array
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
date converts a date-time value to a string date-value time in seconds since 1970-1-1 00:00:00 for given 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
add get the 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 collect collect and permute elements from a list or 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-integer get an integer from a memory address get-string get a string from a memory address int integer 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 symbol 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 xml-error return last XML parse error xml-parse parse a XML document xml-type-tags show or modify XML type tags
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. get-url read a file or page from the web load load / evaluate LISP code from a file open open a file for reading or writing post-url post info to an URL address. print to the console or a device println print to the console or a device with line feed put-url upload a page to an URL address. 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-line read a line from the console or file save save the workspace, context or symbol to a file in LISP format search searches a file for a string seek set or read a file position write-buffer write binary data to a file 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
! 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 (not on Win32) 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
change-dir change to a different current 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 attribute information make-dir make a new directory remove-dir remove an empty directory rename-file rename a file or directory
atom? check if expression is an atom array? check if expression is an array break set or inquire break mode catch evaluate an expression and catch errors context create or switch to a different namespace 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 the Operating System environment or set or get an environment variable. 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 in other contexts than MAIN import import a function from a shared library integer? check if expression is an integer lambda? check if a lambda expression 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 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 trace set or inquire trace mode trace-highlight set enclosing strings for expressions in trace
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 returns the local IP and port number for a connection net-lookup returns the name for an IP-number net-peer returns the remote host IP and port number for a net-connect net-peek returns the number of character ready to read at a socket 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 to a remote host on a socket connection net-send-to sends a UDP datagram to a remote host on an open connection net-send-udp sends a UDP datagram to a remote host and closes connection net-service translates a service name to a port number net-sessions returns a list of currently open connections
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.
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).
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.
example:Atoms: nil, true, integer or float, string, symbol, primitive Lists: quoted list/expression, list/expression, lambda , lambda-macro
(< 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
The result of evaluating 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:
example:( >> 0x80000000 1) => 0xC0000000 ; not 0x04000000 !
(<< 1 3) => 8 (<< 1 2 1) => 8 (>> 1024 10) => 1 (>> 160 2 2) => 10
A bitwise and operation is performed on the evaluation of int-1 with the evaluation of int-2 and then successively with int-3 etc.
example:(& 0xAABB 0x000F) => 11 ; which is 0xB
A bitwise or operation is performed on the evaluation of int-1 with the evaluation of int-2 and then successively with int-3 etc.
example:(| 0x10 0x80 2 1) => 147
A bitwise xor operation is performed on the evaluation of int-1 with the evaluation of int-2 and then successively with int-3 etc.
example:(^ 0xAA 0x55) => 255
A bitwise not operation on the evaluation of int is performed reversing all bits.
example:(format "%X" (~ 0xFFFFFFAA)) => "55" (~ 0xFFFFFFFF) => 0
Returns the absolute value of a number in num.
example:(abs -3.5) => 3.5
The expression in num is evaluated and the arccosine function is calculated from the result.
example:(acos 1) => 0
All the numbers num-1, num-2, ... are evaluated and 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
Returns the 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-integer (address 1234)) => 1234 (get-float (address 1.234)) => 1.234
The function address is useful when passing integers or double floating point numbers to imported library routines by address. 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-integer and get-float.
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
In the first form append works on lists and evaluates all list-n ... . The members of the resulting lists are taken in succession to form a new list. 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 resulting from evaluating 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 to an existing string in place.
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.
Accesses an argument list, which is passed to the current evaluating define-macro lambda expression. This is useful when defining functions 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.
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))) ; replace a whole row => ((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))))) ;;
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))
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
The expression in num is evaluated and the arcsine function is calculated from the result.
example:(asin 1) => 1.570796327
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.
The expression in num is evaluated and the arctangent function is calculated from the result.
example:(atan 1) => 0.7853981634
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 ; 1/4 Pi or 45 degree (div (acos 0) (atan2 1 1)) => 2 (atan2 0 -1) => 3.141592654 ; Pi (= (atan2 1 2) (atan (div 1 2))) => true
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 (see define or define-macro) are not atoms.
example:(atom? '(1 2 3)) => nil (and (atom? 123) (atom? "hello") (atom? 'foo)) => true (atom? ''foo) => nil
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.
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
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)
(betai 0.5 3 8) => 0.9453125
The 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, i.e. the F distribution to test variance ratios, or the distribution of the Students t test statistic for comparing means. See also the binomial function.
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.
(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
If exp is supplied, break mode is switched off if the value is nil or the empty list (); otherwise break mode is switched on. If exp is not supplied, no switching occurs, and break returns true only if break mode is on and nil otherwise. Break mode causes newLISP to enter (or stay in) trace / debug mode when an error occurs. This allows checking the status of variables in trace mode while still in the function where the error occurred.
example:(break true) => true (break) => true
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.
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.
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. See throw for forcing a catch interrupt without error condition.
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.
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.
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 in a list
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)
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).
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.
Similar to if, the evaluation of a body expression using cond depends on evaluating a conditional expression. More than one condition can be tested 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 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.
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)
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.
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 symbols defined in main, thereby overriding the symbols in main.
context? is a predicate which returns true only if exp names the current 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
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")
The expression in num is evaluated, and the cosine function is calculated from the result.
example:(cos 1) => 0.5403023059 (set 'pi (mul 2 (acos 0))) => 3.141592654 (cos pi) => -1
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.
Calculates the critical minimum Chi-square for a given confidence probability num-probability and degrees of freedom num-df for testing of the significance of a null hypothesis in statistics.
example:(crit-chi2 0.99 4) => 13.27670443
Calculates the critical normal distributed Z value for a given probability num-probability for testing of statistical significance and confidence intervals.
example:(crit-z 0.999) => 3.090232372
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 (match ";;*" (current-line)) (write-line)))
This displays all lines in file INIT.LSP starting with ;;.
In the first 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.
The second syntax returns the date/time string representation for the local time zone of the current time.
example:(date (apply date-value (now))) => "Fri Oct 29 09:56:58 2004" (date 0) => "Wed Dec 31 16:00:00 1969" (date) => "Fri Oct 29 09:56:58 2004"
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.
See also date-value, time-of-day, time and now.
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 (dat-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 (+ (/ (apply date-value (now)) -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.
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))
The numerical value resulting from the evaluation of sym is decremented by 1 or by the optional number num and 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 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.
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 a define expression is always the result of the last evaluation made.
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 expressions may be used by itself as an anonymous function without being defined into a symbol:
((lambda ( x y) (* x y)) 2 3) => 6
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 the symbols nil, true and context symbols causes an error message.
Note that when 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 (foo x y) (inc x)) (set 'y 999) (foo 'y 123) => 124 y => 999 ; y is still 999
When trying to modify the content of 'y inside the function it modifies 123 to 124 not 99 to 1000. This is a disadvantage of dynamic scoping in passing symbol references to user-defined functions. Normally this is only a problem when using macros where everything is passed unevaluated by reference by default.
The problem can be avoided by putting user-defined functions in their own context. This way, when called from the outside, a symbol clash never occurs.
Defines a new macro sym-name with optional arguments sym-param1 .... 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-param1 ... without evaluating the arguments first. Then the body-1 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 close 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 (version 8.2.5 or later required):
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.
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.
Deletes a symbol symbol or a context in context with all contained symbols from newLISP's symbol table. When the expression in bool evaluates to nil, references to the symbol in symbol or context are changed to nil when the symbol is deleted. When 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) => 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.
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 directory.
int evaluates to a I/O device number, which is 0 (zero) for the default STD I/O console window, or is 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.dat" (close (device)) => true
Note that using close on device automatically resets device to 0 (zero).
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.
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, then a 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:.
Checks if a disk node is a directory. Returns true or nil depending on outcome.
(directory? "/etc") => true (directory? "/usr/bin/emacs") => nil
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
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 ; x has still its old value 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.
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.
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 no memory overhead (dotree (s 'SomeCTX) (print s " ")) ;; since v.7.1.0 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. The second line in the example would do the same but slower and using much more memory.
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.
exp is evaluated and 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.
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 characters in it, the safer will the encryption be. 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")) => "9\017I\000E ... " (encrypt secret "my secret key") => "A secret message"
The second example encrypts a whole file:
(write-file "myfile.enc" (encrypt (read-file "myfile") "29kH67*"))
In the first version ends-with tests if a string in str-org 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
See also starts-with.
In the first syntax without parameters the Operating System's environment is retrieved as a list with string elements 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 it 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 and 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.
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 error-number function 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
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 error codes in the appendix and error-event.
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 error codes in the appendix and error-event.
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.
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.
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 return nil. Note that this function only works as described when using newLISP as a standalone application not controlled by the Tcl/Tk front-end in newLISP-tk.
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.
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)
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
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:
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) ;; equivalent to: (apply expand '((a b c) a b) 2) => ((1 c) 1 c)
expand reduces it's parameter list similar to apply.
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")
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.
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:
example:size, mode, device mode, user id, group id, access time modification time creation time
(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 creation date for the directory /etc is retrieved.
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 mat exists but not have the permissions to read from or write to it by the current user.
example:(if (file? "afile") (set 'fileNo (open "afile" "read")))
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.
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.
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"
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.
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.
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 integer for parsing integer numbers.
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
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.
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-integer (pack "f" 1.23)) => 1067282596 (unpack "f" (pack "ld" (flt 1.2345))) => (1.230000019)
The last to statements illustrate the inner workings of flt.
See also import for importing libraries.
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. 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.
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 or 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.
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. integer, 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:
Other text may be filled between, before and after the format specs.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
(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"
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 else 1 for payment at the end of each period. 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.
Calculates the Incomplete Gamma function of value a and b in num-a and num-b.
example: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:(gammai 4 5) => 0.7349740847
Q(Chi2|df) = Q(df/2, Chi2/2) = gammai(df/2, Chi2/2)
See also prob-chi2.
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))
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-integer, get-float, get-string and pack, unpack.
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-integer, get-char, get-string and pack, unpack.
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-integer (foo)) => 123 (foo-b) => 456
Note that get-integer 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.
Gets a character string from an address specified in int-address. The function is useful when using imported shared library functions with import.
example:Consider the previous 'C' function in a shared library returning a character pointer (address to a string).char * foo(void) { char * result; result = "ABCDEFG"; return(result); }
(import "mylib.so" "foo") (print (get-string (foo))) => "ABCDEFG"
See also get-char, get-integer, get-float and pack, unpack
Note that get-string can crash the system if the wrong address is specified.
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.
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 globalized. global returns the last globalized symbol.
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 globalizing a previous function definition.
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.
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.
Imports a function str-function-name from a shared library named in str-lib-name. The functions address, get-char, get-integer, 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.
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 <77E8C0A6> (import "user32.dll" "MessageBoxA") => MessageBoxA <77E38CAE> (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 " ") ; reserve space (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 " ") ; reserve space (set 'lpNum (pack "lu" (length str))) ;; get size in a buffer lpNum (GetComputerNameA str lpNum) ;; call the function 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 primitive, which can be used to assign to a different name for the primitive.
(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) 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.
The numerical value resulting from the evaluation of sym is incremented by 1 or by the optional number num and 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.
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.
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 if specified 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.
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:(integer "123") => 123 (integer " 123") => 123 (integer "a123" 0) => 0 (integer (trim " 123")) => 123 (integer "0xFF") => 255 (integer "055") => 45 (integer "1.567") => 1 (integer? 1.00) => nil (integer? (integer 1.00)) => true (integer "1111" 0 2) => 15 ; base 2 conversion (integer "0FF" 0 16) => 255 ; base 16 conversion (integer 'xyz) => nil (integer 'xyz 0) => 0 (integer nil 123) =>l 123 (integer "abc" "not a number") => => "not a number" (print "Enter a num:") (set 'num (integer (read-line)))
See also float for converting to floating point numbers.
integer? returns true only if the value of exp is an integer; otherwise it returns nil. example:
(set 'num 123) => 123 (integer? num) => true
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.
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.
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.
Given a list of strings list-of-strings, join catenates 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.
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 information about lambda expressions.
Returns the last element of a list or a string. list remains unchanged.
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"
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
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 ])
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
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 () *)
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
Loads and translates newLISP from a source file specified in one or 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
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.
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
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.
true is returned only if the value of exp is a lambda-macro; otherwise nil is returned.
example:(define-macro (set! lv rv) (set lv (eval rv))) (macro? set!) => true
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.
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 this script with different command line parameters.
Creates a directory as specified in a path-directory-name 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.
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---).
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 ingnored.
A pattern in list-pattern is matched against a list in list-match and the matching expressions are returned in a list. The two wild card characters ? and * can be used in list-pattern.
Both 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 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 version previous to 8.2.3 showing all list elements in the returned result. This old mode will be deprecated in a future version.
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.
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.
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.
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.
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.
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
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.
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"
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.
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.
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)
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.
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.
When specifying "multi" or "m" as a third parameter for str-mode, a socket for UDP multicast 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 multicast mode in net-connect not actually establishes a connection to the target multicast address, but only put the socket into UDP multicasting mode. On the receiving side use net-listen together with the UDP multicast 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 multicast address in the Class D range of multicast 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.
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: Bad formed IP 13: Listen failed 14: Peek failed 15: Select failed
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.
(net-listen port "192.168.1.54") ;; listen on a specific address
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.
If the option string str-mode is specified as "multi" or "m" net-listen returns a socket suitable for multicasting. In this case str-ip-addr contains one of the multicast 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 multicast 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.
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.
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"
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.
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.
Receives data on the socket int-socket into a string contained in sym-buffer. A maximum of int-num-bytes are received. net-receive returns the number of bytes read. If the connection broke down nil is returned.
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.
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.
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.
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.
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.
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) (net-send sock buf) ;; a string buffer can be used directly (net-send sock "bye bye")
The first net-send sends the string "hello there" the second net-send sends only the string "hello".
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.
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.
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
Returns a list of active listening and connection sockets.
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 (new CTX MyCTX true) => MyCTX ; force overwrite of existing symbols (set 'CTX:x 123) (new CTX) => MAIN ; copies x into MAIN x => 123 (map new '(Ct-a Ct-b Ct-c)) ; merge a list of contexts 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.
If exp evaluates to true then nil is returned else true.
example:(not true) => nil (not nil) => true (not (< 1 10)) => nil (not (not (< 1 10))) => true
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.
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) (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) timezone offset in minutes west of GMT (typically divisible by 60) daylight savings time flag (0 or 1)
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 last returned time offset value is not working correctly in some versions/platforms and may contain garbage values.
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.
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.
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 message (nth 10 10) aArray) => out of bounds error message
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.
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.
The str-path-file evaluates to a file name, str-access-mode evaluates to a string specifying the file access mode. open evaluates to an integer, which is the operating systems file handle. On failure 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 accessexample:
"write" or "w" for write only access
"update" or "u" for read/write access
"append" or "a" for append read/write access
(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
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.
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 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
Note that newLISP only supports 32 bit signed integers and treats lu and ld the same way internally.
Since version 8.3 pack will convert all floats to integer types when passed to b,c,d,ld or lu formats. pack already converted from integer to float type when passing integers to f and lf formats before version 8.3.
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 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 since version 8.1.0 of newLISP.
See also address, get-integer, get-char, get-string and unpack.
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. Since version 7.1.0 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 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 behaviour 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 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.
newLISP can also use named pipes. See the description of open for further information.
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.
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.
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.
.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 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 (string my-expression)) ;; prints without formatting
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
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 \:
example:
\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
(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.
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.
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
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
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 (map set '(myin bcout) (pipe)) ; create pipes and get handles (map set '(bcin myout) (pipe)) (process "bc" bcin bcout) ; launch UNIX 'bc' calculator application (write-buffer myout "3 + 4\n") ; bc expects a linefeed (read-line in) => "7" ;; bc can use bignums with arbitrary precision (write-buffer myout "123456789012345 * 123456789012345\n") (read-line in) => "15241578753238669120562399025" ;; Win32 (map set '(myin cmdout) (pipe)) (map set '(cmdin myout) (pipe)) (process "bc" cmdin cmdout) ; launch Win32 command shell (write-line "dir c:\\*.bat" myout) (read-buffer myin 'buff 2000) (println 'buff) ; prints 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.
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.
example:(set 'pList '(b c)) => (b c) (push 'a pList) => a pList => (a b c) (push "hello" pList 2) => "hello" pList => (a b "hello" c) (push 'z pList -1) => z pList => (a b "hello" c z) (push '(f g) pList) => (f g) pList => ((f g) a b "hello" c z) (push 'x pList -3) => x pList => ((f g) a b "hello" x c z) (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 aVar => nil (push 999 aVar) => 999 aVar => (999)
See also pop, which is the inverse operation to push, and set-nth and nth, which can take multiple dimension indices into lists.
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")) ;; this is for 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.
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.
exp is returned without being evaluated, as if quoted. Note that before version 6.5.23 quote evaluated exp first. The current new behavior is consistent with Scheme and Common Lisp.
example:(quote x) => x (quote 123) => 123 (quote (a b c)) => (a b c) (= (quote x) 'x) => true
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.
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.
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
Reads from a file specified in int-file , int-size bytes into a buffer in sym-buffer. Any data referenced by the symbol sym previous to reading is deleted. newLISP automatically allocates a correct sized buffer in sym-buffer. The handle in int-file was previously returned from an open statement. The symbol sym-buffer is of type string after the read operation.
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.
See also write-buffer.
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.
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.
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 as in previous versions of newLISP. 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 then swallow both. A 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 by 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 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.
Performs a Perl Compatible Regular Expression (PCRE) search on str-text with the pattern specified in str-pattern. Optionally the type of regular expression syntax can be described using int-option. This version of regular expression support is new in newLISP version 6.5.3 and 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 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"
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. On the last three lines the found expression and sub-expressions are retrieved using the system variables $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.
See also the simpler to use match for matching string patterns while breaking the string into different elements
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.
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")
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 (previous to v.7.2.4 the number of changes made). The number of replacements made is contained in the system variable $0.
String replacement without regular expressionIf 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 replacementThe 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 removalThe 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.
Replaces an association element with exp-key in an association list-assoc with exp-replacement. An association list is a list whose element are itself 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))
Since version 7.2.3 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 (previous to v. 7.2.4 the changed element) and is a destructive operation, which changes the contents of the list it is acting on.
See also assoc for accessing association lists.
reset returns to the top level of evaluation, switches the break and trace modes off (nil) turns the command-line mode on (true), and switches to the MAIN context (namespace). Reset restores the top level variable environment using the saved variable environments on the stack. After error conditions not all variables might be restored correctly, current local-state variables are returned to their state before the lambda function started. reset also fires an error "user reset - no error". This behavior can be used when writing error handlers.
reset returns 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). Normally memory is automatically freed for newLISP's internal use but is not always given back to the operating systems heap. This enables an application to track the maximum memory usage of an application using sys-info, but on reset this memory is made available for the OS.
reset occurs automatically after an error when break mode is set to nil.
Returns all the items of a list or a string except the first. The operand is not changed. 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"
In the first form the list is reversed and returned. reverse is destructive in the sense that the original list is changed.
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.
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)
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. Since version 6.3 local state variables appearing in anonymous
lambda expressions are also saved.
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. Since version 7.0.3 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.
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.
See also load, which is the inverse operation to save and source, which saves a symbol to a string instead of a file.
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. Since version 7.1.0 options flags can be specified in int-options and a PCRE regular expressions search is done. See the function regex for details. Search returns the position of the found string or nil if nothing is found.
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.
Seeds the internal random generator generating numbers for rand, random and normal with the number specified in int-seed. Note that the random generator used in newLISP is the C-library function rand(). The newLISP functions rand, random and normal are based on this function.
example:(seed 12345)
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.
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. Ff 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 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
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.
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 nonsignaled 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 nonsignaled 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.
example:;; counter thread output in bold (define (counter n) (println "counter started") (dotimes (x n) (semaphore sid -1) (println x))) ;; hit extrato 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 nonsignaled 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.
As per version 8.2.1 of newLISP the semaphore function is only available on Linux and UNIX.
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/modules package of newLISP.
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.
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.
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. Since version 6.5.28 set can take multiple arguments.
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.
is equivalent to:(set 'double (lambda (x) (+ x x))) => (lambda (x) (+ x x))
is equivalent to:(define (double x) (+ x x)) => (lambda (x) (+ x x))
(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.
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
Reports or switches to a different locale on your platform / operating system. 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
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 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.
Sets the nth in int-nth element in a list with the evaluation of exp-replacement and returns the changed list. 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 element. When an index can no longer traverse a 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.
In the third form the int-nth character in ste is replaced with the string in str-replacement.
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.
Indices out of bounds will refer to the first or last element in a list but will cause an out of bounds error message in arrays.
In the third form the int-nth character in ste is replaced with the string in str-replacement. Out of bounds indices will refer to the first or last character position in the string.
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. 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 faster when doing replacements on a large list.
See also nth and push and pop for other functions suitable for accessing multidimensional nested lists or arrays (nth).
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 if the memory has not been set to a value before.
example:(set 'num (share)) (set 'str (share)) (share num 123) => 123 (share str "hello world") => "hello world" (share mVar 123) => 123
For a more comprehensive example of using shared memory in a multithreaded Linux/UNIX application see the example prodcons.lsp in the Appendix or in the examples/ directory of the source distribution
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.
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-integer, 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)
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
The expression in num is evaluated and the sine function is calculated from the result and returned.
example:(sin 1) => 0.8414709838 pi => 3.141592654 (sin (div pi 2)) => 1
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.
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"
slice replaces the sublist and substring.
Sorts the list given in list in ascending or descending order depending on the symbol in sym. Specify ascending order with '< and descending order with '>. If sym is not specified sorting is 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.
example:(sort '(v f r t h n m j)) => (f h j m n r t v) (sort '(v f r t h n m j) '>) => (v t r n m j h f) (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 s '<) => (a k l s) (sort s '>) => (s l k a) s => (s l k a) (apply <= (sort (rand 10 100))) => true
Note that sort relies on the OS's 'C'-lib function sort(), which in a few older C-lib implementations only handles 16k or 32k of elements to be sorted.
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 can be controlled using the pretty-print function.
The expression in num is evaluated and the square root is calculated from the result.
example:(sqrt 10) => 3.16227766 (sqrt 25) => 5
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.
Translates anything which results from evaluating exp ... 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"
See also append for concatenating strings and join for concatenating strings and specifying the joining strings in between.
exp is evaluated and tested if a string. true or nil is returned, depending on the result.
example:(set 'var "hello") (string? var) => true
The expression in num-1 is evaluated and expressions num-2 ... are successively subtracted from the result. 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 NaN also returns NaN.
example:(sub 10 8 0.25) => 1.75 (sub 123) => -123
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"
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 functional identical.
But note that symbol spaces 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 symbol 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:(symbol "some") => some (set (symbol "var") 345) => 345 var => 345 (symbol "aSym" 'MyCTX) => MyCTX:aSym (symbol "aSym" MyCTX) => MyCTX:aSym ; unquoted context (symbol "foo" MyCTX nil) => nil ; 'foo does not exist (symbol "foo" MyCTX) => foo ; 'foo is created (symbol "foo" MyCTX nil) => foo ; foo now exists
Because the function symbol returns the symbol looked up or created, expressions with symbol can be embedded directly in other expressions. The following example show the usage of symbol as a hash-like function for associative memory access and using symbol configurations which are not legal newLISP symbols:
example:(set (symbol "John Doe" 'MyDB') 1.234) (set (symbol "(" 'MyDB) "parenthesis open") (set (symbol 12 'MyDB) "twelve") (eval (symbol "John Doe" 'MyDB)) => 1.234 (eval (symbol "(" 'MyDB)) => "parenthesis open" (eval (symbol 12 'MyDB)) => "twelve" (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.
Expression exp is evaluated and returns true only if the value is a non-primitive symbol and otherwise returns nil.
example:(set 'x 'y) => var (symbol? x) => true (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.
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) ; since version 7.1.0 quote can be omitted
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.
;; 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.
Returns a list of internal resource statistics. The list has 8 integers reporting the following status:
example:Number of LISP cells Maximum number of LISP cells constant Number of symbols Evaluation/recursion level Environment stack level Maximum call stack constant Version number as an integer constant Operating System constant: linux=1, bsd=2, osx=3, solaris=4, cygwin=5, win32=6 the highest bit (bit 7) will be set for UTF-8 versions (add 128) bit 6 will be added for library versions (add 64)
(sys-info) => (291 268435456 269 1 0 1024 8000 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 commandline switch.
The expression in num is evaluated and the tangent function is calculated as the result.
example:(tan 1) => 1.557407725 (set 'pi (mul 2 (asin 1))) => 3.141592654 (tan (div pi 4)) => 1
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"
throw is useful to break out in the middle of a loop or for programming other exception conditions.
Evaluates the expression in exp and returns the time in milliseconds spent on evaluation. Note that time previous to version 6.4.9 returned the number of seconds since 1970-1-1 UCT; this number can now be retrieved using date-value and now.
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.
Returns the time in milliseconds since start of current day.
See also date, date-value, time and now.
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 it also switches on break 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.
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.
(trace true) => true ;; switches newLISP into debugging mode (my-func a b c) ;; the debugger shows each step now (trace nil) => nil ;; switches newLISP out of debugging mode
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.
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.
Transposes a matrix by reversing the rows and columns and converts all cells to floating point numbers. Any kind of matrix can be transposed (previously only only matrices containing numbers). 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 and the number of elements in the first row as number of columns of the original matrix.
example:(set 'A '((1 2 3) (4 5 6))) (transpose A) => ((1 2) (3 4) (5 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.
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"
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.
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 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) "small" "big") => "big"
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 from versions 5.5 on str-addr-packed may also be a number or an expression returning a number representing a memory address. This facilitates unpacking structures returned from imported shared library functions.
The following characters may define a format:
example:
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
(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 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 since version 8.1.0 of newLISP.
See also address, get-integer, get-char, get-string and pack.
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")
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.
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 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.
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 manpages 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.
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 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")
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.
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.
Since version 7.1.6 a string buffer can be used directly without quoting a symbol
. example:(set 'handle (open "myfile.ext" "write")) (write-buffer handle 'data 100) ;; string buffer w/o quote since 7.1.6 (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.
example:(set 'str "") (dotimes (x 5) (write-buffer str "hello")) ;; fast method str => "HelloHelloHelloHelloHello") ;; much slower method of string concatenation (dotimes (x 5) (set 'str (append str "hello")))
The second 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.
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.
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.
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).
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)
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 the xml-parse fails returning nil because of malformed XML nil is returned and xml-error can be used to access error information.
example:Modifying the translation process.(set 'xml "<person name='John Doe' tel='555-1212'>a nice person</person>") (xml-parse xml) => (("ELEMENT" "person" (("name" "John Doe") ("tel" "555-1212")) (("TEXT" "a nice person"))))
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 |
1 | suppress whitespace text tags |
2 | suppress empty attribute lists |
4 | suppress comment tags |
8 | translate string tags into symbols |
16 | add 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:Parsing without any options:<?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>
(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.
The XML type tags "TEXT" "CDATA" "COMMENT" and "ELEMENT" can be replaced with something else specified in the parameters or suppressed completely.
Note that xm-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".
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 symbol is not a context 13 list expected 14 list or symbol expected 15 list or string expected 16 list or number expected 17 array expected 18 array, list or string expected 19 lambda expected 20 lambda-macro expected 21 invalid function 22 invalid lambda expression 23 invalid macro expression 24 invalid let expression 25 problem saving file 26 math exception 27 matrix expected 28 matrix wrong dimensions 29 matrix is singular 30 syntax in regular expression 31 catch without throw 32 problem loading library 33 import function not found 34 symbol is protected 35 error number to high 36 regular expression 37 missing [/text] tag 38 mismatch in number of arguments 39 problem in format string 40 data type and format don't match 41 invalid parameter: 0.0 42 invalid parameter: NaN 43 global not in MAIN context 44 symbol not in current context 45 array index out of bounds 46 user reset - 47
0: No error 1: Cannot open socket 2: Host name not known 3: Not a valid service 4: Connection failed 5: Accept failed 6: Invalid symbol 7: Connection closed 8: Connection broken 9: Read failed 10: Socket send() failed 11: Cannot bind socket 12: not used 13: Badly formed IP number 14: Listen failed 15: Peek failed 16: Select failed
#!/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 ;;
#!/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 ;
#!/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
#!/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
#!/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)
;; 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 ;; ;; ;; v 1.1: replaced all 'concat' with 'append', 'debug' renamed to 'debug-flag' ;; v 1.2: replaces # with ;; for comments ;; v 1.3: better error reporting when (set 'debug-flag true) ;; v 1.4: Modified message file name generation to assure uniqueness in ;; get-all-messages (CaveGuy). ;; v 1.5: Fixed 'mail-dir reference in (get-all-mail and (get-new-mail functions ;; (get-messages now attempts to makes 'mail-dir, if not found. ;; also changed the message file type to ".pop3" to reflect the context ;; it was created by. (CaveGuy). ;; ;; v.1.6: fixed bug in get-messages: directory? doesn't take trailing slash in arg ;; ;; v.1.7: will also work on POP3 servers, which do not support LAST, but then will ;; only support (POP3:get-all-messages ...) ;; ;; v.1.8: added (PP3:delete-all-mail ...), which also works on servers not supporting ;; the LAST command (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 ;; ;; v 1.4: modified file name generation to improve uniqueness. (CaveGuy) ;; file name now created using last SMTP or ESMTP ID from header. ;; v 1.5: changed file type to ".pop3" to reflect the context that created it. ;; (get-messages now forces the directory, if it does not exist. ;; ;; v 1.6: make sure directory? doesn't have trailing slash in arg ;; (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
;; 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
;; 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
#!/usr/bin/newlisp ; ; httpd - web server v.3.9 ; 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/ ; ; v 3.2: changed opsys reference in sys-info ; ; v 3.4: changed to unquoted syntax style of net-send ; multiple default file names ; handling of missing cgi files ; ; v 3.5: did not issue werror message if it couldn't ; change to root dir on start up ; ; v 3.7: replaced all deprecated 'match' with 'find' ; fixed bug with post requests on IE Explorer ; and Netscape 4.0 ; ; v 3.8: change for new sys-info os version numbers ; v 3.9: replaced deprecated 'putenv' with 'env' (context 'HTTPD) (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 3.7\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 (or (starts-with query "http://") (starts-with query "HTTP://")) (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 2.0\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" )) ;; for win32 (set 'procStr (append "./" fileName " > /tmp/pcgi" ))) ;; for 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 3.7<BR>" "Error: " (string error-no) " " error-txt "<BR></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
;; 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.3 ;; ;; 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 (symbol vars)) (set 'var (float vars)))) (throw (append vars "ERR: is not a variable")) (push var expression)) (push vars expression))) (push op expression) (push expression varstack)) (context 'MAIN) ;; eof ;;