picolisp

Unnamed repository; edit this file to name it for gitweb.
git clone https://logand.com/git/picolisp.git/
Log | Files | Refs | README | LICENSE

commit 3291fb0890008ab8a3d26e1917b1449c21bb170e
parent 2804ee02f9ddb3c273360e2ff9bef0a774f09351
Author: Commit-Bot <unknown>
Date:   Thu, 22 Apr 2010 14:32:31 +0000

Automatic commit from picoLisp.tgz, From: Thu, 22 Apr 2010 11:32:31 GMT
Diffstat:
ACHANGES | 404+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ACOPYING | 280+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ACREDITS | 23+++++++++++++++++++++++
AINSTALL | 103+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AREADME | 105+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AReleaseNotes | 18++++++++++++++++++
Aapp/cusu.l | 43+++++++++++++++++++++++++++++++++++++++++++
Aapp/er.l | 167+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aapp/gui.l | 243+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aapp/init.l | 81+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aapp/inventory.l | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aapp/item.l | 40++++++++++++++++++++++++++++++++++++++++
Aapp/lib.l | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aapp/loc/ar | 5+++++
Aapp/loc/ch | 4++++
Aapp/loc/de | 86+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aapp/loc/es | 86+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aapp/loc/jp | 86+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aapp/loc/no | 86+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aapp/loc/ru | 86+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aapp/main.l | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aapp/ord.l | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aapp/role.l | 33+++++++++++++++++++++++++++++++++
Aapp/sal.l | 21+++++++++++++++++++++
Aapp/sales.l | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aapp/user.l | 36++++++++++++++++++++++++++++++++++++
Abin/pil | 2++
Abin/psh | 14++++++++++++++
Abin/replica | 31+++++++++++++++++++++++++++++++
Abin/scrape | 11+++++++++++
Abin/watchdog | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acygwin/README | 170+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acygwin/tcc.l | 22++++++++++++++++++++++
Adbg | 2++
Adbg.l | 16++++++++++++++++
Adoc/app.html | 2551+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/apply | 30++++++++++++++++++++++++++++++
Adoc/db | 91+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/doc.css | 12++++++++++++
Adoc/family.l | 242+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/family/1 | 0
Adoc/family/2 | 0
Adoc/family/3 | 0
Adoc/family/4 | 0
Adoc/faq.html | 664+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/fun.l | 9+++++++++
Adoc/hello.l | 5+++++
Adoc/index.html | 108+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/model | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/quine | 24++++++++++++++++++++++++
Adoc/ref.html | 2455+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/refA.html | 567+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/refB.html | 319+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/refC.html | 657+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/refD.html | 748+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/refE.html | 486+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/refF.html | 512+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/refG.html | 188+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/refH.html | 216+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/refI.html | 389+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/refJ.html | 81+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/refK.html | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/refL.html | 531+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/refM.html | 621+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/refN.html | 399+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/refO.html | 262+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/refP.html | 816+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/refQ.html | 107+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/refR.html | 713+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/refS.html | 870+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/refT.html | 565+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/refU.html | 356+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/refV.html | 163+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/refW.html | 196+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/refX.html | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/refY.html | 30++++++++++++++++++++++++++++++
Adoc/refZ.html | 102+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/ref_.html | 546+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/rlook.html | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/select.html | 490+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/shape.l | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/structures | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/toc.html | 41+++++++++++++++++++++++++++++++++++++++++
Adoc/travel | 24++++++++++++++++++++++++
Adoc/tut.html | 2402+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/utf8 | 39+++++++++++++++++++++++++++++++++++++++
Adoc64/README | 136+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc64/asm | 194+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc64/structures | 308+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aext.l | 6++++++
Afavicon.ico | 0
Agames/README | 233+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Agames/chess.l | 566+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Agames/mine.l | 126+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Agames/nim.l | 27+++++++++++++++++++++++++++
Agames/sudoku.l | 73+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Agames/ttt.l | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Agames/xchess | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Aimg/7fach.eps | 474+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aimg/7fach.gif | 0
Aimg/go.png | 0
Aimg/no.png | 0
Alib.css | 194+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib.l | 369+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/adm.l | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/app.l | 34++++++++++++++++++++++++++++++++++
Alib/boss.l | 16++++++++++++++++
Alib/btree.l | 438+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/cal.l | 79+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/conDbgc.l | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/db.l | 1125++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/db32-64.l | 73+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/dbase.l | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/debug.l | 362+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/ed.l | 47+++++++++++++++++++++++++++++++++++++++++++++++
Alib/edit.l | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/el/inferior-picolisp.el | 312+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/el/paredit.el.diff | 89+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/el/picolisp.el | 536+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/el/tsm.el | 130+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/form.js | 352+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/form.l | 2069+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/gcc.l | 40++++++++++++++++++++++++++++++++++++++++
Alib/glyphlist.txt | 4322+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/head.ps | 28++++++++++++++++++++++++++++
Alib/heartbeat.l | 19+++++++++++++++++++
Alib/http.l | 440+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/import.l | 30++++++++++++++++++++++++++++++
Alib/led.l | 431+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/led.min.l | 23+++++++++++++++++++++++
Alib/lint.l | 257+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/math.l | 11+++++++++++
Alib/math32.l | 22++++++++++++++++++++++
Alib/math64.l | 44++++++++++++++++++++++++++++++++++++++++++++
Alib/misc.l | 480+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/native.l | 23+++++++++++++++++++++++
Alib/pilog.l | 550+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/prof.l | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/ps.l | 318+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/readline.l | 28++++++++++++++++++++++++++++
Alib/rsa.l | 109+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/scrape.l | 160+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/simul.l | 154+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/sq.l | 131+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/tags | 346+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/term.l | 47+++++++++++++++++++++++++++++++++++++++++++++++
Alib/test.l | 31+++++++++++++++++++++++++++++++
Alib/tex.l | 164+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/too.l | 487+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/xhtml.l | 669+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/xm.l | 115+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/xml.l | 286+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/xmlrpc.l | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aloc/AR.l | 7+++++++
Aloc/CH.l | 7+++++++
Aloc/DE.l | 7+++++++
Aloc/ES.l | 7+++++++
Aloc/JP.l | 7+++++++
Aloc/NIL.l | 7+++++++
Aloc/NO.l | 7+++++++
Aloc/RU.l | 7+++++++
Aloc/UK.l | 7+++++++
Aloc/US.l | 7+++++++
Aloc/ar | 1+
Aloc/ch | 4++++
Aloc/de | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aloc/es | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Aloc/jp | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aloc/no | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aloc/ru | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amisc/bigtest | 103+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amisc/calc | 12++++++++++++
Amisc/calc.l | 73+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amisc/chat | 32++++++++++++++++++++++++++++++++
Amisc/crc.l | 23+++++++++++++++++++++++
Amisc/dining.l | 42++++++++++++++++++++++++++++++++++++++++++
Amisc/dirTree.l | 19+++++++++++++++++++
Amisc/fannkuch.l | 38++++++++++++++++++++++++++++++++++++++
Amisc/fibo.l | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Amisc/hanoi.l | 24++++++++++++++++++++++++
Amisc/life.l | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amisc/mailing | 93+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amisc/maze.l | 33+++++++++++++++++++++++++++++++++
Amisc/pi.l | 23+++++++++++++++++++++++
Amisc/pilog.l | 125+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amisc/reverse.l | 16++++++++++++++++
Amisc/setf.l | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Amisc/sieve.l | 14++++++++++++++
Amisc/stress.l | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amisc/travel.l | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Amisc/trip.l | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aopt/pilog.l | 15+++++++++++++++
Ap | 2++
Aplmod | 2++
Aplmod.l | 10++++++++++
Arcsim/README | 125+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Arcsim/env.l | 103+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Arcsim/fokker.l | 456+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Arcsim/lib.l | 255+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Arcsim/main.l | 124+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Arcsim/tone | 41+++++++++++++++++++++++++++++++++++++++++
Asimul/lib.l | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asimul/rgb.l | 29+++++++++++++++++++++++++++++
Asrc/Makefile | 145+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/apply.c | 676+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/balance.c | 94+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/big.c | 1137+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/ext.c | 182+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/flow.c | 1688+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/gc.c | 185+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/ht.c | 368+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/httpGate.c | 309+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/io.c | 3543+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lat1.c | 75+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main.c | 1140+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/net.c | 204+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/pico.h | 852+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/ssl.c | 241+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/start.c | 10++++++++++
Asrc/subr.c | 1686+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/sym.c | 1991+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/tab.c | 410+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/utf2.c | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/z3d.c | 468+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/z3dClient.c | 532+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc64/Makefile | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc64/apply.l | 1606+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc64/arch/x86-64.l | 772+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc64/big.l | 2673+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc64/db.l | 2249+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc64/defs.l | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc64/err.l | 726+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc64/ext.l | 248+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc64/flow.l | 3150+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc64/gc.l | 1002+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc64/glob.l | 1078+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc64/ht.l | 727+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc64/io.l | 5001+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc64/lib/asm.l | 546+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc64/main.l | 2605+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc64/mkAsm | 14++++++++++++++
Asrc64/net.l | 336+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc64/subr.l | 4013+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc64/sym.l | 3417+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc64/sys/linux.code.l | 39+++++++++++++++++++++++++++++++++++++++
Asrc64/sys/linux.defs.l | 145+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc64/version.l | 6++++++
Atest/lib.l | 201+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atest/lib/lint.l | 21+++++++++++++++++++++
Atest/lib/misc.l | 213+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atest/src/apply.l | 107+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atest/src/big.l | 159+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atest/src/db.l | 43+++++++++++++++++++++++++++++++++++++++++++
Atest/src/ext.l | 22++++++++++++++++++++++
Atest/src/ext2.l | 31+++++++++++++++++++++++++++++++
Atest/src/flow.l | 434+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atest/src/ht.l | 46++++++++++++++++++++++++++++++++++++++++++++++
Atest/src/io.l | 220+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atest/src/main.l | 150+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atest/src/net.l | 25+++++++++++++++++++++++++
Atest/src/subr.l | 477+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atest/src/sym.l | 368+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
262 files changed, 93029 insertions(+), 0 deletions(-)

diff --git a/CHANGES b/CHANGES @@ -0,0 +1,404 @@ +* XXjun10 picoLisp-3.0.3 + +* 30mar10 picoLisp-3.0.2 + Simple incrementing form of 'for' + Changed 'scl' to set '*Scl' globally + 'acquire' and 'release' mutex functions + Changed 'state' syntax + 'version' function (64-bit) + C 'lisp()' callback function (64-bit) + Bug in 'member' for circular lists (64-bit) + "lib/tags" for 'vi' source access + Bug in 'next' and 'arg' (64-bit) + Bug in comma read macro (64-bit) + Bug in binary read functions (64-bit) + 'hax' function + Bug when deleting external symbols (64-bit) + Bug in external symbol names (64-bit) + Bug in '|' and 'x|' (32-bit) + +* 31dec09 picoLisp-3.0.1 + '*Tsm' transient symbol markup + 'range' function + 'gcc' for 64-bit in "lib/native.l" + 'flip' optional 'cnt' argument + Up to four letters in 'c[ad]*ar' and 'c[ad]*dr' + Fixed sporadic GUI errors + GUI 'onchange' handling + +* 07oct09 picoLisp-3.0 + 64-bit version for x86-64 + Allowed '.' in symbol names + Changed GUI to Post/Redirect/Get pattern + Changed event handling to non-blocking I/O + Extension ".l" on localization country files + Deprecated 'begin' and 'nagle' + +* 30jun09 picoLisp-2.3.7 + 'dbg' startup script + Removed 'stk' function + Bug in GUI history "back" handling + Multi-line (block) comments + Improved external hash table + Transient characters no longer interned + 'getd' loads shared library code + +* 31mar09 picoLisp-2.3.6 + 'lines' returns 'NIL' on failure + Only numeric argument to 'hear' + 'sort' optional 'fun' argument + Bugs in 'evList()' and 'date' + +* 31dec08 picoLisp-2.3.5 + Bug in 'pipe' + Bug in 'later' + Dialog and chart bugs in "lib/form.l" + HTTP protocol bug in "lib/http.l" + Bugs in 'inc' and 'bigCmp()' + 'abort' function + 'eval' and 'run' optional 'lst' argument + +* 30sep08 picoLisp-2.3.4 + 'once' function + 'hex' and 'oct' negative arguments + Bug in 'pool' + 'cmd' function + 'script' function + Bug in 'idx' + Bug in 'lit' + 'extract' function + +* 29jun08 picoLisp-2.3.3 + Removed '*Rst' global variable + Catch error messages + Remote Pilog queries + DB extension with '*Ext' and 'ext' + Extended 'put'-syntax to zero keys + Wrong '@@' result in 'load' + Handling of "#" in 'str' + +* 29mar08 picoLisp-2.3.2 + Ctrl-D termination + Improved termios restore + 'file' function + ';' function + Changed (time T) semantics + Bugs in 'idx' and 'lup' + DB synchronous transaction log + Handling of 'bind' in 'debug' + +* 30dec07 picoLisp-2.3.1 + 'str' extended to parse tokens + '*Hup' global variable + Changed/extended 'all' semantics + Replaced 'die' with 'alarm' + Bug in 'glue' + Improved '@' handling + Bug in 'bye()' + 'eol' end-of-line function + Escape delimiter characters in symbol names + 'lint' also file contents + 'noLint' function + +* 30sep07 picoLisp-2.3.0 + Extended "lib/test.l" unit tests + 'full' function + Bug in 'wipe' + Bug in 'digSub1()' + Changed internal symbol structure + 'pid' selector for 'tell' + 'vi' and 'ld' source code access + Restored 'in'/'out' negative channel offsets + Abandoned 'stdio' in I/O functions + Improved signal handling + 'leaf' function + Restored 'gc' unit to "megabytes" + Changed 'heap' return values + Bug in 'tell' + 'chess' XBoard interface + '*Sig1', '*Sig2' global variables + 'ipid' and 'opid' functions + Bug in writing blobs + Timeout bug in 'httpGate' + '*Zap' global variable + '*OS' global variable + +* 30jun07 picoLisp-2.2.7 + Extended "doc/ref.html" + 'cons' multiple arguments + 'yoke' function + 'up' optional 'cnt' argument + +* 01apr07 picoLisp-2.2.6 + 'app' reference application + Bug in 'text' + Family IPC redesign + Gave up 'in'/'out' negative channel offsets + Changed 'keep>' and 'lose>' methods + Gave up '*Tsm' transient symbol markup + 'sect' and 'diff' in C + 'gc' unit changed to "million cells" + +* 31dec06 picoLisp-2.2.5 + Persistent HTTP Connections + Extended 'tick' to count system time + Chunked HTTP transfers + Changed '*Key' to '*Run' + 'fifo' function + 'die' alarm function + 'line' carriage return handling + Pre- and post-arguments to 'commit' + 'text' function + 'glue' in C + Ajax GUI in "lib/form.l", "lib/form.js" + 'push1' function (deprecates '?push') + Bug in 'ht:Fmt' + +* 30sep06 picoLisp-2.2.4 + Cygwin/Win32 port (Doug Snead) + Changed 'bind' argument + 'fish' function + 'rd' optional 'sym' argument + Bug in 'lock' (unlock all) + 'free' function + Extended 'seq' to return first symbol + Simple 'udp' function + 'usec' function + Bug in 'isLife()' + '*PPid' global variable + 'nagle' network function + Extended 'get'-syntax to 'asoq' + +* 30jun06 picoLisp-2.2.3 + "redefined" messages go to stderr + Bug in 'argv' + Deprecated "lib/tree.l" + Restored '*Solo' global variable + '(get lst 0)' returns 'NIL' + Bug in 'extern' + 'nond' (negated 'cond') function + 'ge0' function + Bug in 'lose>' and 'keep>' for '+Joint' + '*Rst' global variable + Bug in 'next'/'arg' + Changed 'env' and 'job' + Bug in B-Tree 'step' + Changed 'mark' return value + Changed 'close' return value + +* 29mar06 picoLisp-2.2.2 + Mac OS X (Darwin) port (Rick Hanson) + 'pwd' function + 'if2' flow function + 'rpc' function + 'one' function + Changed 'space' return value + 'up' symbol binding lookup function + Bug in 'eval' and 'run' environment offset + 'onOff' function + 'path' substitution function + '*Tsm' transient symbol markup + Underlining transient symbols + +* 30dec05 picoLisp-2.2.1 + 'eof' end-of-file function + Changed 'line' EOF return value + Deprecated 'whilst' and 'until=T' + 'read' extended to parse tokens + 'raw' console mode function + 'later' multiprocessing function + Bug in nested 'fork' and 'pipe' + Extended 'gcc' arguments + Bug in 'boxWord2()' + 'id' external symbol function + Extended 'dm' syntax for object argument + 'size' changed to return bytes instead of blocks in DB + Executable renamed to "picolisp" + 'lieu' predicate function + Bug in 'compare()' + +* 29sep05 picoLisp-2.2.0 + FreeBSD port + B-Trees + Multi-file DB + Configurable DB block size + Generalized 'pipe' semantics + Changed 'rank' to sorted lists + Removed '*Solo' global variable + Relaxed 'wipe' "modified" error condition + DB-I/O changed to 'pread()' and 'pwrite()' + Extended 'get'-syntax to zero and negative keys + 'by' attribute map function + Swing GUI in "java2/" and "lib/gui2.l" + 'box?' predicate function + Bug in 'compare()' + 'balance' C-utility + +* 30jun05 picoLisp-2.1.2 + GC non-recursive + 'lup' lookup in 'idx' trees + Applet colors + 'try' to send messages + 'x|' function + Tooltips in applets + Binding environment offset for 'eval' and 'run' + XHTML/CSS support in "lib/xhtml.l" + Separated "lib/html.l" from "lib/http.l" + Removed "lib/http.l" from "ext.l" + Bug in 'isa' + Bug in 'lose>' and 'keep>' for '+Bag' + Security hole in 'http' + Bug in 'rel>' for '+Hook' + +* 30mar05 picoLisp-2.1.1 + 'protect' function + DB journaling + 'chess' demo + Predicates return their argument instead of 'T', if possible + Bug in 'fun?' + Improved 'lint' heuristics + I/O-Multiplexing also for plain stdin + 'dir' in C + Self-adjusting applet size + Bug in 'pack()' + +* 30dec04 picoLisp-2.1.0 + 'pipe' function + Bugs in bignum arithmetic + 'arg' optional 'cnt' argument + '+Aux' auxiliary index keys + '*Solo' global variable + 'flg?' predicate function + 'fin' access function + Bug in 'compare()' + 'cd' returns old directory + 'inc' and 'dec' numeric argument + Next 'opt' command line arg + 'finally' exception cleanup + Implied 'upd' argument in transactions 'put!>', 'del!>' etc. + Bug in 'idx' for empty trees + 'curry' function + Anonymous recursion with 'recur' and 'recurse' + Extended 'env' to return bindings + Second argument to 'fill' + Optional comment character argument for 'skip' + 'flip' destructive list reversal + +* 01oct04 picoLisp-2.0.14 + '<tree>' HTML function + Finite 'state' machine function + Extended 'for' functionality + 'rcsim' toy RC flight simulator + Bug in 'sym', 'str' and '*/' + Extended 'dbck' return value + +* 03aug04 picoLisp-2.0.13 + Changed rounding and argument policy of '*/' + Applet protocol revised + Extended 'head' and 'tail' to predicate functionality + Changed 'accu' default from 1 to 0 + Dialog handling revised + Multiple JAR files per applet + Fixed "Last-Modified:" format in 'httpEcho' + +* 29may04 picoLisp-2.0.12 + Fixed 'boss' mechanism + 'del' delete-and-set function + '*Fork' global variable + Changed URL encoding of Lisp objects + Removed traffic throttle from 'httpGate' + Synchronized ".picoHistory" in "lib/led.l" + Fixed exception handling in debug breakpoint + Revised subclass handling in 'db' and 'collect' + Applet font/size parameters + +* 07apr04 picoLisp-2.0.11 + Bug in 'append' + Modal dialogs revised + Bug in 'lose>' and 'keep>' for '+Bag' + 'poll' (no block-on-read-) check function + Inline 'gcc' C-function compilation + +* 01feb04 picoLisp-2.0.10 + 'wr' raw byte output function + Improved modal dialogs + Comma ',' read-macro, replacing the '_' function + 'let?' conditional flow/bind function + 'accept' non-blocking, with timeout + Optional method-defining arguments to '+Form's + '+Bool' relation class + '+Ref2' backing index prefix class + 'size' returns number of DB blocks for external symbols + '+ListTextField' split parameter + +* 06dec03 picoLisp-2.0.9 + 'Tele' java client + Closed leaking file descriptors in 'fork' + Changed applet protocol to individual server connections + Decoupled applet init from HTML page load + +* 14oct03 picoLisp-2.0.8b + Bug in 'put>', 'rel>', 'lose>' and 'keep>' for '+List' + Bug in 'lose>' and 'keep>' for '+Bag' + +* 01oct03 picoLisp-2.0.8 + '+Hook' handling in '+Bag' + Unicode case conversions + '+Hook' changed to prefix class + Telephone number locales + CR-LF in HTTP headers + 'date' and 'time' return UTC for 'T' argument + 'clk>' (doubleclick) for '+DrawField' + Improved Hook support in Pilog + Optional 'NIL' argument to 'html' for "no Cache-Control" + +* 03aug03 picoLisp-2.0.7 + Extended 'in' and 'out' for negative channel offset arguments + Changed internal database index tree function API + Changed 'info' to return 'T' for the directory size + Interrupt signal handling in 'ctty', 'psh' and "bin/psh" + Generic 'help>' method for '+Form' class in "lib/gui.l" + Fixed 'ht:Prin' bug (NULL-Bytes) + 'argv' optional symbolic arguments + Changed 'idx' return value + Better tracing and profiling of C-functions + +* 08jun03 picoLisp-2.0.6 + Allowed '#' in symbol names + Changed 'eps' in "lib/ps.l" + Interactive DB tools in "lib/sq.l" + 'revise' line editor function + 'circ' changed to individual arguments + Moved code-libraries to "lib/" + Moved *.jar-files to "java/" + +* 23apr03 picoLisp-2.0.5 + 'mail' changed to direct SMTP + 'sys' environment access function + Plain HTML-GUI "lib/htm.l" (experimental) + Semantics of 'do NIL' changed from enless- to zero-loop + +* 03mar03 picoLisp-2.0.4 + Changed and extended '+IndexChart' + '=0', 'lt0' and 'gt0' return numeric argument instead of 'T' + 'cut' changed to be non-desctructive + 'ssl' replication mechanism + 'ctl' file control primitives + 'ext?' and 'extern' check for physical existence of external symbol + +* 01feb03 picoLisp-2.0.3 + Extension and redesign of the HTML API + 'loop' function as a synonym for 'do NIL' + +* 17jan03 picoLisp-2.0.2 + The example files for the tutorial were in the wrong directory + Bind '*Key' in debug breakpoint + Localization bug in "misc/tax.l" + +* 27dec02 picoLisp-2.0.1 + Default locale 'NIL' + Pilog documentation + Example family database + +* 16dec02 picoLisp-2.0 + Initial release diff --git a/COPYING b/COPYING @@ -0,0 +1,280 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/CREDITS b/CREDITS @@ -0,0 +1,23 @@ +# The PicoLisp system is originally written and maintained by +Alexander Burger <abu@software-lab.de> + +# For many years, ideas and application concepts were contributed by +Josef Bartl <josef.bartl@7fach.org> + +# Build procedure for Mac OS X (Darwin) +Rick Hanson <rick@tamos.net> + +# Port to Cygwin/Win32 +Doug Snead <doug@drugsense.org> + +# Documentation, Mac OS support, OpenGL library, Norwegian localization +Jon Kleiser <jon.kleiser@usit.uio.no> + +# Russian localization +Mansur Mamkin <mmamkin@mail.ru> + +# XML parser (and other) improvements +Tomas Hlavaty <kvietaag@seznam.cz> + +# Spanish localization and emacs picolisp-mode +Armadillo <tc.rucho@gmail.com> diff --git a/INSTALL b/INSTALL @@ -0,0 +1,103 @@ +16mar10abu +(c) Software Lab. Alexander Burger + + + PicoLisp Installation + ===================== + +There is no 'configure' procedure, but the PicoLisp file structure is simple +enough to get along without it (we hope). It should compile and run on +GNU/Linux, FreeBSD, Mac OS X (Darwin), Cygwin/Win32, and possibly other systems +without problems. + +By default, PicoLisp installs completely in a local directory. No need to touch +any system locations, so you don't have to be root. + + +Please follow these steps: + +1. Unpack the distribution + + $ tar xfz picoLisp-XXX.tgz + +2. Change the directory + + $ cd picoLisp-XXX + +3. Compile the PicoLisp interpreter + + $ (cd src; make picolisp) + + or, if you have an x86-64 Linux system, build the 64-bit version + + $ (cd src64; make picolisp) + + In both cases the executable bin/picolisp will be created. + + Note that on the BSD family of operating systems, 'gmake' must be used + instead of 'make'. + +4. Optional (but recommended) are two symbolic links from /usr/lib and /usr/bin + to the installation directory + + # ln -s /<installdir> /usr/lib/picolisp + # ln -s /usr/lib/picolisp/bin/picolisp /usr/bin/picolisp + + In that case, you might also copy the script bin/pil to /usr/bin, for a + convenient global invocation. + + + Invocation + ---------- + +The shell script 'dbg' is usually called to start up PicoLisp in interactive +debugging mode + + $ ./dbg + : + +The colon ':' is PicoLisp's prompt. You may enter some Lisp expression, + + : (+ 1 2 3) + -> 6 + +To exit the interpreter, enter + + : (bye) + +or simply type an empy line (Return). + + + Console Underlines + ================== + +In case that your console (terminal) does not support underlining, you might +want to remove or replace the first statement int "ext.l" which uses the +terminfo database to initialize the global variable '*Tsm' (transient symbol +markup). Unfortunately, the VGA text mode does not properly support underlines. + + + Documentation + ------------- + +For further information, please look at "doc/index.html". There you find the +PicoLisp Reference Manual (doc/ref.html), the PicoLisp tutorials (doc/tut.html +and doc/app.html), and the frequently asked questions (doc/faq.html). + +For details about the 64-bit version, refer to "doc64/README", "doc64/asm" and +"doc64/structures". + +As always, the most accurate and complete documentation is the source code ;-) +Included in the distribution are many utilities and pet projects, including +tests, demo databases and servers, games (chess, minesweeper), 3D animation +(flight simulator), and more. + +Any feedback is welcome! +Hope you enjoy :-) + +-------------------------------------------------------------------------------- + + Alexander Burger + Software Lab. / 7fach GmbH + Bahnhofstr. 24a, D-86462 Langweid + abu@software-lab.de, http://www.software-lab.de, +49 8230 5060 diff --git a/README b/README @@ -0,0 +1,105 @@ +12nov09abu +(c) Software Lab. Alexander Burger + + Perfection is attained + not when there is nothing left to add + but when there is nothing left to take away + (Antoine de Saint-Exupery) + The PicoLisp System + =================== + + _PI_co Lisp is not _CO_mmon Lisp + +PicoLisp can be viewed from two different aspects: As a general purpose +programming language, and a dedicated application server framework. + + +(1) As a programming language, PicoLisp provides a 1-to-1 mapping of a clean +and powerful Lisp derivate, to a simple and efficient virtual machine. It +supports persistent objects as a first class data type, resulting in a database +system of Entity/Relation classes and a Prolog-like query language tightly +integrated into the system. + +The virtual machine was designed to be + Simple + The internal data structure should be as simple as possible. Only one + single data structure is used to build all higher level constructs. + Unlimited + There are no limits imposed upon the language due to limitations of the + virtual machine architecture. That is, there is no upper bound in symbol + name length, number digit counts, or data structure and buffer sizes, + except for the total memory size of the host machine. + Dynamic + Behavior should be as dynamic as possible ("run"-time vs. "compile"-time). + All decisions are delayed till runtime where possible. This involves + matters like memory management, dynamic symbol binding, and late method + binding. + Practical + PicoLisp is not just a toy of theoretical value. PicoLisp is used since + 1988 in actual application development, research and production. + +The language inherits the major advantages of classical Lisp systems like + - Dynamic data types and structures + - Formal equivalence of code and data + - Functional programming style + - An interactive environment + +PicoLisp is very different from any other Lisp dialect. This is partly due to +the above design principles, and partly due to its long development history +since 1984. + +You can download the latest release version at +"http://software-lab.de/down.html". + + +(2) As an application server framework, PicoLisp provides for + Database Management + Index trees + Object local indexes + Entity/Relation classes + Pilog (PicoLisp Prolog) queries + Multi-user synchronization + DB Garbage collection + Journaling, Replication + User Interface + Browser GUI + (X)HTML/CSS + XMLHttpRequest/JavaScript + Application Server + Process management + Process family communication + XML I/O + Import/export + User administration + Internationalization + Security + Object linkage + Postscript/Printing + +PicoLisp is not an IDE. All program development in Software Lab. is done using +the console, bash, vim and the Lisp interpreter. + +The only type of GUI supported for applications is through a browser via HTML. +This makes the client side completely platform independent. The GUI is created +dynamically. Though it uses JavaScript and XMLHttpRequest for speed +improvements, it is fully functional also without JavaScript or CSS. + +The GUI is deeply integrated with - and generated dynamically from - the +application's data model. Because the application logic runs on the server, +multiple users can view and modify the same database object without conflicts, +everyone seeing changes done by other users on her screen immediately due to the +internal process and database synchronization. + +PicoLisp is free software, and you are welcome to redistribute it under the +conditions of the GNU General Public License (GPL). + +It compiles and runs on current 32-bit GNU/Linux, FreeBSD, Mac OS X (Darwin), +Cygwin/Win32 (and possibly other) systems. A native 64-bit version is available +for Linux on x86-64. + +-------------------------------------------------------------------------------- + + Alexander Burger + Software Lab. / 7fach GmbH + Bahnhofstr. 24a, D-86462 Langweid + abu@software-lab.de, http://www.software-lab.de, +49 8230 5060 diff --git a/ReleaseNotes b/ReleaseNotes @@ -0,0 +1,18 @@ +19apr10abu +(c) Software Lab. Alexander Burger + + + Release Notes for picoLisp-3.0.3 + ================================ + +A. The underlined display of transient symbols in the documentation is changed + back to double quotes, to allow an easier copy/paste of example code + fragments. + +B. The function 'not' is included in the group of flow- and logic-functions + which store non-NIL results of their conditional expressions in '@' (see the + chapter "@ Result" in "doc/ref.html"). This makes it consistent with 'nand' + and 'nor'. + +C. The line editor "lib/led.l" cycles with TAB also through path names (in + addition to internal symbols). diff --git a/app/cusu.l b/app/cusu.l @@ -0,0 +1,43 @@ +# 05nov09abu +# (c) Software Lab. Alexander Burger + +(must "Customer/Supplier" Customer) + +(menu ,"Customer/Supplier" + (ifn *ID + (prog + (<h3> NIL ,"Select" " " ,"Customer/Supplier") + (form 'dialog (choCuSu)) ) + (<h3> NIL ,"Customer/Supplier") + (form NIL + (<h2> NIL (<id> (: nr) " -- " (: nm))) + (panel T (pack ,"Customer/Supplier" " @1") '(may Delete) '(choCuSu) 'nr '+CuSu) + (<hr>) + (<tab> + (,"Name" + (<grid> 3 + ,"Number" NIL (gui '(+E/R +NumField) '(nr : home obj) 10) + ,"Salutation" + (gui '(+Hint) ,"Salutation" + '(mapcar '((This) (cons (: nm) This)) (collect 'nm '+Sal)) ) + (gui '(+Hint2 +E/R +Obj +TextField) '(sal : home obj) '(nm +Sal) 20) + ,"Name" NIL (gui '(+E/R +Cue +TextField) '(nm : home obj) ,"Name" 40) + ,"Name 2" NIL (gui '(+E/R +TextField) '(nm2 : home obj) 40) ) ) + (,"Address" + (<grid> 2 + ,"Street" (gui '(+E/R +TextField) '(str : home obj) 40) + NIL NIL + ,"Zip" (gui '(+E/R +TextField) '(plz : home obj) 10) + ,"City" (gui '(+E/R +TextField) '(ort : home obj) 40) ) ) + (,"Contact" + (<grid> 2 + ,"Phone" (gui '(+E/R +TelField) '(tel : home obj) 40) + ,"Fax" (gui '(+E/R +TelField) '(fax : home obj) 40) + ,"Mobile" (gui '(+E/R +TelField) '(mob : home obj) 40) + ,"EMail" (gui '(+E/R +MailField) '(em : home obj) 40) ) ) + ((pack (and (: obj txt) "@ ") ,"Memo") + (gui '(+BlobField) '(txt : home obj) 60 8) ) ) + (<hr>) + (<spread> NIL (editButton T)) ) ) ) + +# vi:et:ts=3:sw=3 diff --git a/app/er.l b/app/er.l @@ -0,0 +1,167 @@ +# 01dec09abu +# (c) Software Lab. Alexander Burger + +### Entity/Relations ### +# +# nr nm nr nm nm +# | | | | | +# +-*----*-+ +-*----*-+ +--*-----+ +# | | sup | | | | +# str --* CuSu O-----------------* Item *-- inv | Role @-- perm +# | | | | | | +# +-*-*--O-+ +----O---+ +----@---+ +# | | | | | usr +# nm tel -+ | | | | +# | | | | itm | role +# +-*-----+ | | +-------+ +---*---+ +----*---+ +# | | | | | | ord | | | | +# | Sal +---+ +---* Ord @--------* Pos | nm --* User *-- pw +# | | cus | | pos | | | | +# +-*---*-+ +-*---*-+ +-*---*-+ +--------+ +# | | | | | | +# hi sex nr dat pr cnt + +(extend +Role) + +(dm url> (Tab) + (and (may RoleAdmin) (list "app/role.l" '*ID This)) ) + + +(extend +User) +(rel nam (+String)) # Full Name +(rel tel (+String)) # Phone +(rel em (+String)) # EMail + +(dm url> (Tab) + (and (may UserAdmin) (list "app/user.l" '*ID This)) ) + + +# Salutation +(class +Sal +Entity) +(rel nm (+Key +String)) # Salutation +(rel hi (+String)) # Greeting +(rel sex (+Any)) # T:male, 0:female + +(dm url> (Tab) + (and (may Customer) (list "app/sal.l" '*ID This)) ) + +(dm hi> (Nm) + (or (text (: hi) Nm) ,"Dear Sir or Madam,") ) + + +# Customer/Supplier +(class +CuSu +Entity) +(rel nr (+Need +Key +Number)) # Customer/Supplier Number +(rel sal (+Link) (+Sal)) # Salutation +(rel nm (+Sn +Idx +String)) # Name +(rel nm2 (+String)) # Name 2 +(rel str (+String)) # Street +(rel plz (+Ref +String)) # Zip +(rel ort (+Fold +Idx +String)) # City +(rel tel (+Fold +Ref +String)) # Phone +(rel fax (+String)) # Fax +(rel mob (+Fold +Ref +String)) # Mobile +(rel em (+String)) # EMail +(rel txt (+Blob)) # Memo + +(dm url> (Tab) + (and (may Customer) (list "app/cusu.l" '*Tab Tab '*ID This)) ) + +(dm check> () + (make + (or (: nr) (link ,"No customer number")) + (or (: nm) (link ,"No customer name")) + (unless (and (: str) (: plz) (: ort)) + (link ,"Incomplete customer address") ) ) ) + + +# Item +(class +Item +Entity) +(rel nr (+Need +Key +Number)) # Item Number +(rel nm (+Fold +Idx +String)) # Item Description +(rel sup (+Ref +Link) NIL (+CuSu)) # Supplier +(rel inv (+Number)) # Inventory +(rel pr (+Ref +Number) NIL 2) # Price +(rel txt (+Blob)) # Memo +(rel jpg (+Blob)) # Picture + +(dm url> (Tab) + (and (may Item) (list "app/item.l" '*ID This)) ) + +(dm cnt> () + (- + (or (: inv) 0) + (sum '((This) (: cnt)) + (collect 'itm '+Pos This) ) ) ) + +(dm check> () + (make + (or (: nr) (link ,"No item number")) + (or (: nm) (link ,"No item description")) ) ) + + +# Order +(class +Ord +Entity) +(rel nr (+Need +Key +Number)) # Order Number +(rel dat (+Need +Ref +Date)) # Order date +(rel cus (+Ref +Link) NIL (+CuSu)) # Customer +(rel pos (+List +Joint) ord (+Pos)) # Positions + +(dm lose> () + (mapc 'lose> (: pos)) + (super) ) + +(dm url> (Tab) + (and (may Order) (list "app/ord.l" '*ID This)) ) + +(dm sum> () + (sum 'sum> (: pos)) ) + +(dm check> () + (make + (or (: nr) (link ,"No order number")) + (or (: dat) (link ,"No order date")) + (if (: cus) + (chain (check> @)) + (link ,"No customer") ) + (if (: pos) + (chain (mapcan 'check> @)) + (link ,"No positions") ) ) ) + + +(class +Pos +Entity) +(rel ord (+Dep +Joint) # Order + (itm) + pos (+Ord) ) +(rel itm (+Ref +Link) NIL (+Item)) # Item +(rel pr (+Number) 2) # Price +(rel cnt (+Number)) # Quantity + +(dm sum> () + (* (: pr) (: cnt)) ) + +(dm check> () + (make + (if (: itm) + (chain (check> @)) + (link ,"Position without item") ) + (or (: pr) (link ,"Position without price")) + (or (: cnt) (link ,"Position without quantity")) ) ) + + +# Database sizes +(dbs + (1 +Role +User +Sal) # (1 . 128) + (2 +CuSu) # (2 . 256) + (1 +Item +Ord) # (3 . 128) + (0 +Pos) # (4 . 64) + (2 (+Role nm) (+User nm) (+Sal nm)) # (5 . 256) + (4 (+CuSu nr plz tel mob)) # (6 . 1024) + (4 (+CuSu nm)) # (7 . 1024) + (4 (+CuSu ort)) # (8 . 1024) + (4 (+Item nr sup pr)) # (9 . 1024) + (4 (+Item nm)) # (10 . 1024) + (4 (+Ord nr dat cus)) # (11 . 1024) + (4 (+Pos itm)) ) # (12 . 1024) + +# vi:et:ts=3:sw=3 diff --git a/app/gui.l b/app/gui.l @@ -0,0 +1,243 @@ +# 20apr10abu +# (c) Software Lab. Alexander Burger + +### GUI ### +(de menu (Ttl . Prg) + (action + (html 0 Ttl *Css NIL + (<div> '(id . menu) + (expires) + (<menu> + (,"Home" "@start") + (,"logout" (and *Login "@stop")) + (NIL (<hr>)) + (T ,"Data" + (,"Orders" (and (may Order) "app/ord.l")) + (,"Items" (and (may Item) "app/item.l")) + (,"Customers/Suppliers" (and (may Customer) "app/cusu.l")) + (,"Salutations" (and (may Customer) "app/sal.l")) ) + (T ,"Report" + (,"Inventory" (and (may Report) "app/inventory.l")) + (,"Sales" (and (may Report) "app/sales.l")) ) + (T ,"System" + (,"Role Administration" (and (may RoleAdmin) "app/role.l")) + (,"User Administration" (and (may UserAdmin) "app/user.l")) ) ) ) + (<div> '(id . main) (run Prg 1)) ) ) ) + +(de start () + (setq *Url "@start") + (and (app) (setq *Menu 3)) + (menu "PicoLisp App" + (<h2> NIL "PicoLisp App") + (<img> "img/7fach.gif" "7fach Logo") + (----) + (form NIL + (gui '(+Init +Map +TextField) + (cons *Ctry *Lang) + *Locales + (mapcar car *Locales) + ',"Language" ) + (gui '(+Button) ',"Change" + '(let V (val> (field -1)) + (locale (car V) (cdr V) "app/loc/") ) ) ) + (form NIL + (<grid> 2 + ,"Name" (gui 'nm '(+Focus +Able +TextField) '(not *Login) 20) + ,"Password" (gui 'pw '(+Able +PwField) '(not *Login) 20) ) + (--) + (gui '(+Button) '(if *Login ,"logout" ,"login") + '(cond + (*Login (logout)) + ((login (val> (: home nm)) (val> (: home pw))) + (clr> (: home pw)) ) + (T (err ,"Permission denied")) ) ) + (when *Login + (<nbsp> 4) + (<span> "bold green" + (<big> (ht:Prin "'" (; *Login nm) ,"' logged in")) ) ) ) ) ) + +(de stop () + (logout) + (start) ) + +# Search dialogs +(de choCuSu (Dst) + (diaform '(Dst) + (<grid> "--.-.-." + ,"Number" (gui 'nr '(+Var +NumField) '*CuSuNr 10) + ,"Name" (gui 'nm '(+Focus +Var +TextField) '*CuSuNm 30) + ,"Phone" (gui 'tel '(+Var +TelField) '*CuSuTel 20) + (searchButton '(init> (: home query))) + ,"Zip" (gui 'plz '(+Var +TextField) '*CuSuPlz 10) + ,"City" (gui 'ort '(+Var +TextField) '*CuSuOrt 30) + ,"Mobile" (gui 'mob '(+Var +TelField) '*CuSuMob 20) + (resetButton '(nr nm tel plz ort mob query)) ) + (gui 'query '(+QueryChart) (cho) + '(goal + (quote + @Nr (and *CuSuNr (cons @ T)) + @Nm *CuSuNm + @Tel *CuSuTel + @Plz *CuSuPlz + @Ort *CuSuOrt + @Mob *CuSuMob + (select (@@) + ((nr +CuSu @Nr) (nm +CuSu @Nm) (tel +CuSu @Tel) + (plz +CuSu @Plz) (ort +CuSu @Ort) (mob +CuSu @Mob) ) + (range @Nr @@ nr) + (tolr @Nm @@ nm) + (fold @Tel @@ tel) + (head @Plz @@ plz) + (part @Ort @@ ort) + (fold @Mob @@ mob) ) ) ) + 9 + '((This) (list This (: nr) This (: nm2) (: em) (: plz) (: ort) (: tel) (: mob))) ) + (<table> 'chart (choTtl ,"Customers/Suppliers" 'nr '+CuSu) + (quote + (btn) + (align "#") + (NIL ,"Name") + (NIL) + (NIL ,"EMail") + (NIL ,"Zip") + (NIL ,"City") + (NIL ,"Phone") + (NIL ,"Mobile") ) + (do (cho) + (<row> (alternating) + (gui 1 '(+DstButton) Dst) + (gui 2 '(+NumField)) + (gui 3 '(+ObjView +TextField) '(: nm)) + (gui 4 '(+TextField)) + (gui 5 '(+MailField)) + (gui 6 '(+TextField)) + (gui 7 '(+TextField)) + (gui 8 '(+TelField)) + (gui 9 '(+TelField)) ) ) ) + (<spread> + (scroll (cho)) + (newButton T Dst '(+CuSu) + '(nr genKey 'nr '+CuSu) + 'nm *CuSuNm + 'plz *CuSuPlz + 'ort *CuSuOrt + 'tel *CuSuTel + 'mob *CuSuMob ) + (cancelButton) ) ) ) + +(de choItem (Dst) + (diaform '(Dst) + (<grid> "--.-." + ,"Number" (gui 'nr '(+Focus +Var +NumField) '*ItemNr 10) + ,"Supplier" (gui 'sup '(+Var +TextField) '*ItemSup 20) + (searchButton '(init> (: home query))) + ,"Description" (gui 'nm '(+Var +TextField) '*ItemNm 30) + ,"Price" (gui 'pr '(+Var +FixField) '*ItemPr 2 12) + (resetButton '(nr nm pr sup query)) ) + (gui 'query '(+QueryChart) (cho) + '(goal + (quote + @Nr (and *ItemNr (cons @ T)) + @Nm *ItemNm + @Pr (and *ItemPr (cons @ T)) + @Sup *ItemSup + (select (@@) + ((nr +Item @Nr) (nm +Item @Nm) (pr +Item @Pr) (nm +CuSu @Sup (sup +Item))) + (range @Nr @@ nr) + (part @Nm @@ nm) + (range @Pr @@ pr) + (tolr @Sup @@ sup nm) ) ) ) + 6 + '((This) (list This (: nr) This (: sup) (: sup ort) (: pr))) ) + (<table> 'chart (choTtl ,"Items" 'nr '+Item) + (quote + (btn) + (align "#") + (NIL ,"Description") + (NIL ,"Supplier") + (NIL ,"City") + (align ,"Price") ) + (do (cho) + (<row> (alternating) + (gui 1 '(+DstButton) Dst) + (gui 2 '(+NumField)) + (gui 3 '(+ObjView +TextField) '(: nm)) + (gui 4 '(+ObjView +TextField) '(: nm)) + (gui 5 '(+TextField)) + (gui 6 '(+FixField) 2) ) ) ) + (<spread> + (scroll (cho)) + (newButton T Dst '(+Item) + '(nr genKey 'nr '+Item) + 'nm *ItemNm + 'pr *ItemPr ) + (cancelButton) ) ) ) + +(de choOrd (Dst) + (diaform '(Dst) + (<grid> "--.-.-." + ,"Number" (gui 'nr '(+Focus +Var +NumField) '*OrdNr 10) + ,"Customer" (gui 'cus '(+Var +TextField) '*OrdCus 20) + ,"City" (gui 'ort '(+Var +TextField) '*OrdOrt 20) + (searchButton '(init> (: home query))) + ,"Date" (gui 'dat '(+Var +DateField) '*OrdDat 10) + ,"Supplier" (gui 'sup '(+Var +TextField) '*OrdSup 20) + ,"Item" (gui 'item '(+Var +TextField) '*OrdItem 20) + (resetButton '(nr cus ort dat sup item query)) ) + (gui 'query '(+QueryChart) (cho) + '(goal + (quote + @Nr (cons (or *OrdNr T)) + @Dat (cons (or *OrdDat T)) + @Cus *OrdCus + @Ort *OrdOrt + @Sup *OrdSup + @Item *OrdItem + (select (@@) + ((nr +Ord @Nr) (dat +Ord @Dat) + (nm +CuSu @Cus (cus +Ord)) + (ort +CuSu @Ort (cus +Ord)) + (nm +Item @Item (itm +Pos) ord) + (nm +CuSu @Sup (sup +Item) (itm +Pos) ord) ) + (range @Nr @@ nr) + (range @Dat @@ dat) + (tolr @Cus @@ cus nm) + (part @Ort @@ cus ort) + (part @Item @@ pos itm nm) + (tolr @Sup @@ pos itm sup nm) ) ) ) + 9 + '((This) + (list This (: nr) This + (: cus) (: cus ort) + (: pos 1 itm sup) (: pos 1 itm) + (: pos 2 itm sup) (: pos 2 itm) ) ) ) + (<table> 'chart (choTtl ,"Orders" 'nr '+Ord) + (quote + (btn) + (align "#") + (NIL ,"Date") + (NIL ,"Customer") + (NIL ,"City") + (NIL ,"Supplier" "(1)") + (NIL ,"Item" "(1)") + (NIL ,"Supplier" "(2)") + (NIL ,"Item" "(2)") ) + (do (cho) + (<row> (alternating) + (gui 1 '(+DstButton) Dst) + (gui 2 '(+NumField)) + (gui 3 '(+ObjView +DateField) '(: dat)) + (gui 4 '(+ObjView +TextField) '(: nm)) + (gui 5 '(+TextField)) + (gui 6 '(+ObjView +TextField) '(: nm)) + (gui 7 '(+ObjView +TextField) '(: nm)) + (gui 8 '(+ObjView +TextField) '(: nm)) + (gui 9 '(+ObjView +TextField) '(: nm)) ) ) ) + (<spread> + (scroll (cho)) + (newButton T Dst '(+Ord) + '(nr genKey 'nr '+Ord) + 'dat (date) ) + (cancelButton) ) ) ) + +# vi:et:ts=3:sw=3 diff --git a/app/init.l b/app/init.l @@ -0,0 +1,81 @@ +# 14jan10abu +# (c) Software Lab. Alexander Burger + +### Role ### +(obj ((+Role) nm "Administration") perm `*Perms) +(obj ((+Role) nm "Accounting") perm (Customer Item Order Report Delete)) +(obj ((+Role) nm "Assistance") perm (Order)) +(commit) + +### User ### +(obj ((+User) nm "admin") pw "admin" nam "Administrator" role `(db 'nm '+Role "Administration")) +(obj ((+User) nm "ben") pw "ben" nam "Ben Affleck" role `(db 'nm '+Role "Accounting")) +(obj ((+User) nm "jodie") pw "jodie" nam "Jodie Foster" role `(db 'nm '+Role "Accounting")) +(obj ((+User) nm "sandy") pw "sandy" nam "Sandra Bullock" role `(db 'nm '+Role "Accounting")) +(obj ((+User) nm "depp") pw "depp" nam "Johnny Depp" role `(db 'nm '+Role "Assistance")) +(obj ((+User) nm "tom") pw "tom" nam "Tom Hanks" role `(db 'nm '+Role "Assistance")) +(commit) + +(obj ((+Sal) nm "Department") hi "Dear Sir or Madam,") +(obj ((+Sal) nm "Mr.") hi "Dear Mr. @1," sex T) +(obj ((+Sal) nm "Mrs.") hi "Dear Mrs. @1," sex 0) +(obj ((+Sal) nm "Ms.") hi "Dear Ms. @1," sex 0) +(obj ((+Sal) nm "Mme") hi "Bonjour Mme @1," sex 0) +(obj ((+Sal) nm "Herr") hi "Sehr geehrter Herr @1," sex T) +(obj ((+Sal) nm "Herr Dr.") hi "Sehr geehrter Herr Dr. @1," sex T) +(obj ((+Sal) nm "Frau") hi "Sehr geehrte Frau @1," sex 0) +(obj ((+Sal) nm "Frau Dr.") hi "Sehr geehrte Frau Dr. @1," sex 0) +(obj ((+Sal) nm "Señor") hi "Estimado Señor @1," sex T) +(obj ((+Sal) nm "Señora") hi "Estimada Señora @1," sex 0) +(commit) + +### Customer/Supplier ### +(obj ((+CuSu) nr 1) + nm "Active Parts Inc." + nm2 "East Division" + str "Wildcat Lane" + plz "3425" + ort "Freetown" + tel "37 4967 6846-0" + fax "37 4967 68462" + mob "37 176 86303" + em "info@api.tld" ) +(obj ((+CuSu) nr 2) + nm "Seven Oaks Ltd." + str "Sunny Side Heights 202" + plz "1795" + ort "Winterburg" + tel "37 6295 5855-0" + fax "37 6295 58557" + em "info@7oaks.tld" ) +(obj ((+CuSu) nr 3) + sal `(db 'nm '+Sal "Mr.") + nm "Miller" + nm2 "Thomas Edwin" + str "Running Lane 17" + plz "1208" + ort "Kaufstadt" + tel "37 4773 82534" + mob "37 129 276877" + em "tem@shoppers.tld" ) +(commit) + +### Item ### +(obj ((+Item) nr 1) nm "Main Part" sup `(db 'nr '+CuSu 1) inv 100 pr 29900) +(obj ((+Item) nr 2) nm "Spare Part" sup `(db 'nr '+CuSu 2) inv 100 pr 1250) +(obj ((+Item) nr 3) nm "Auxiliary Construction" sup `(db 'nr '+CuSu 1) inv 100 pr 15700) +(obj ((+Item) nr 4) nm "Enhancement Additive" sup `(db 'nr '+CuSu 2) inv 100 pr 999) +(obj ((+Item) nr 5) nm "Metal Fittings" sup `(db 'nr '+CuSu 1) inv 100 pr 7980) +(obj ((+Item) nr 6) nm "Gadget Appliance" sup `(db 'nr '+CuSu 2) inv 100 pr 12500) +(commit) + +### Order ### +(let Ord (new (db: +Ord) '(+Ord) 'nr 1 'dat (date 2007 2 14) 'cus (db 'nr '+CuSu 3)) + (put> Ord 'pos + (list + (new (db: +Pos) '(+Pos) 'itm (db 'nr '+Item 1) 'pr 29900 'cnt 1) + (new (db: +Pos) '(+Pos) 'itm (db 'nr '+Item 2) 'pr 1250 'cnt 8) + (new (db: +Pos) '(+Pos) 'itm (db 'nr '+Item 4) 'pr 999 'cnt 20) ) ) ) +(commit) + +# vi:et:ts=3:sw=3 diff --git a/app/inventory.l b/app/inventory.l @@ -0,0 +1,55 @@ +# 08mar10abu +# (c) Software Lab. Alexander Burger + +(must "Inventory" Report) + +(menu ,"Inventory" + (<h3> NIL ,"Inventory") + (form NIL + (<grid> "-.-" + ,"Number" NIL + (prog + (gui '(+Var +NumField) '*InvFrom 10) + (prin " - ") + (gui '(+Var +NumField) '*InvTill 10) ) + ,"Description" NIL (gui '(+Var +TextField) '*InvNm 30) + ,"Supplier" (gui '(+ChoButton) '(choCuSu (field 1))) + (gui '(+Var +Obj +TextField) '*InvSup '(nm +CuSu) 30) ) + (--) + (gui '(+ShowButton) NIL + '(csv ,"Inventory" + (<table> 'chart NIL + (<!> + (quote + (align) + (NIL ,"Description") + (align ,"Inventory") + (NIL ,"Supplier") + NIL + (NIL ,"Zip") + (NIL ,"City") + (align ,"Price") ) ) + (catch NIL + (pilog + (quote + @Rng (cons *InvFrom (or *InvTill T)) + @Nm *InvNm + @Sup *InvSup + (select (@Item) + ((nr +Item @Rng) (nm +Item @Nm) (sup +Item @Sup)) + (range @Rng @Item nr) + (tolr @Nm @Item nm) + (same @Sup @Item sup) ) ) + (with @Item + (<row> (alternating) + (<+> (: nr) This) + (<+> (: nm) This) + (<+> (cnt> This)) + (<+> (: sup nm) (: sup)) + (<+> (: sup nm2)) + (<+> (: sup plz)) + (<+> (: sup ort)) + (<-> (money (: pr))) ) ) + (at (0 . 10000) (or (flush) (throw))) ) ) ) ) ) ) ) + +# vi:et:ts=3:sw=3 diff --git a/app/item.l b/app/item.l @@ -0,0 +1,40 @@ +# 03jan09abu +# (c) Software Lab. Alexander Burger + +(must "Item" Item) + +(menu ,"Item" + (ifn *ID + (prog + (<h3> NIL ,"Select" " " ,"Item") + (form 'dialog (choItem)) ) + (<h3> NIL ,"Item") + (form NIL + (<h2> NIL (<id> (: nr) " -- " (: nm))) + (panel T (pack ,"Item" " @1") '(may Delete) '(choItem) 'nr '+Item) + (<grid> 4 + ,"Number" NIL (gui '(+E/R +NumField) '(nr : home obj) 10) NIL + ,"Description" NIL (gui '(+E/R +Cue +TextField) '(nm : home obj) ,"Item" 30) NIL + ,"Supplier" (gui '(+ChoButton) '(choCuSu (field 1))) + (gui '(+E/R +Obj +TextField) '(sup : home obj) '(nm +CuSu) 30) + (gui '(+View +TextField) '(field -1 'obj 'ort) 30) + ,"Inventory" NIL (gui '(+E/R +NumField) '(inv : home obj) 12) + (gui '(+View +NumField) '(cnt> (: home obj)) 12) + ,"Price" NIL (gui '(+E/R +FixField) '(pr : home obj) 2 12) ) + (--) + (<grid> 2 + ,"Memo" (gui '(+BlobField) '(txt : home obj) 60 8) + ,"Picture" + (prog + (gui '(+Able +UpField) '(not (: home obj jpg)) 30) + (gui '(+Button) '(if (: home obj jpg) ,"Uninstall" ,"Install") + '(if (: home obj jpg) + (ask ,"Uninstall Picture?" + (put!> (: home top 1 obj) 'jpg NIL) ) + (let? F (val> (field -1)) + (blob! (: home obj) 'jpg (tmp F)) ) ) ) ) ) + (<spread> NIL (editButton T)) + (when (: obj jpg) + (<img> (allow (blob (: obj) 'jpg)) ,"Picture") ) ) ) ) + +# vi:et:ts=3:sw=3 diff --git a/app/lib.l b/app/lib.l @@ -0,0 +1,62 @@ +# 22jan08abu +# (c) Software Lab. Alexander Burger + +### PDF-Print ### +(dm (ps> . +Ord) () + (a4) + (font (12 . "Helvetica")) + (eps "img/7fach.eps" 340 150 75) + (window 380 120 120 30 + (font (21 . "Times-Roman") (ps ,"Order" 0)) ) + (brief NIL 8 "7fach GmbH, Bawaria" + (ps) + (with (: cus) + (ps + (pack + (and (: sal) (pack (: sal nm) " ")) + (: nm2) " " (: nm) ) ) + (ps (: str)) + (ps (pack (: plz) " " (: ort))) ) ) + (window 360 280 240 60 + (let Fmt (80 12 60) + (table Fmt ,"Customer" ":" (ps (: cus nr))) + (table Fmt ,"Order" ":" (ps (: nr))) + (table Fmt ,"Date" ":" (ps (datStr (: dat)))) ) ) + (down 360) + (indent 60 60) + (let (Page 1 Fmt (14 6 200 80 80 80)) + (width "0.5" + (hline 0 470 -8) + (font "Helvetica-Bold" + (table Fmt NIL NIL + (ps ,"Item") + (ps ,"Price" T) + (ps ,"Quantity" T) + (ps ,"Total" T) ) ) + (hline 4 470 -8) + (pages 720 + (hline 0 470 -8) + (down 12) + (font 9 (ps (text ,"Continued on page @1" (inc 'Page)))) + (page T) + (eps "img/7fach.eps" 340 150 75) + (down 40) + (font 9 (ps (text ,"Page @1" Page))) + (down 80) + (hline 0 470 -8) ) + (for (I . This) (: pos) + (down 4) + (table Fmt + (ps I T) NIL + (ps (: itm nm)) + (ps (money (: pr)) T) + (ps (: cnt) T) + (ps (money (sum> This)) T) ) ) + (pages) + (hline 4 470 -8) + (down 4) + (table Fmt NIL NIL NIL NIL NIL (ps (money (sum> This)) T)) + (hline 4 470 -8) ) ) + (page) ) + +# vi:et:ts=3:sw=3 diff --git a/app/loc/ar b/app/loc/ar @@ -0,0 +1,5 @@ +# 26aug09art +# Armadillo <tc.rucho@gmail.com> + +T "@app/loc/es" +"Mobile" "Celular" diff --git a/app/loc/ch b/app/loc/ch @@ -0,0 +1,4 @@ +# 10may08abu +# (c) Software Lab. Alexander Burger + +T "app/loc/de" diff --git a/app/loc/de b/app/loc/de @@ -0,0 +1,86 @@ +# 09may08abu +# (c) Software Lab. Alexander Burger + +"(@1 Positions)" "(@1 Positionen)" + +"Address" "Adresse" + +"Can't print order" "Beleg kann nicht gedruckt werden" +"Change" "Ändern" +"City" "Ort" +"Contact" "Kontakt" +"Continued on page @1" "Fortsetzung auf Seite @1" +"Country" "Land" +"Customer" "Kunde" +"Customer/Supplier" "Kunde/Lieferant" +"Customers/Suppliers" "Kunden/Lieferanten" + +"Data" "Daten" +"Date" "Datum" +"Dear Sir or Madam," "Sehr geehrte Damen und Herren," +"Description" "Bezeichnung" + +"eMail" "eMail" + +"Fax" "Fax" +"Full Name" "Vollständiger Name" + +"Greeting" "Gruß" + +"Home" "Startseite" + +"Incomplete customer address" "Unvollständige Kundenadresse" +"Install" "Installieren" +"Inventory" "Lagerbestand" +"Item" "Artikel" +"Items" "Artikel" + +"Login Name" "Login-Name" + +"Memo" "Memo" +"Mobile" "Mobil" + +"Name" "Name" +"Name 2" "Name 2" +"No customer" "Kunde fehlt" +"No customer name" "Kundenname fehlt" +"No customer number" "Kundennummer fehlt" +"No item description" "Artikelbezeichnung fehlt" +"No item number" "Artikelnummer fehlt" +"No order date" "Belegdatum fehlt" +"No order number" "Belegnummer fehlt" +"No positions" "Keine Positionen" +"Number" "Nummer" + +"Order" "Bestellung" +"Orders" "Bestellungen" + +"Page @1" "Seite @1" +"PDF-Print" "PDF-Druck" +"Phone" "Telefon" +"Picture" "Bild" +"Position without item" "Position ohne Artikel" +"Position without price" "Position ohne Preis" +"Position without quantity" "Position ohne Menge" +"Price" "Preis" + +"Quantity" "Menge" + +"Report" "Auswertung" +"Role Administration" "Rollenverwaltung" + +"Sales" "Verkauf" +"Salutation" "Anrede" +"Salutations" "Anreden" +"Sex" "Geschlecht" +"Street" "Straße" +"Supplier" "Lieferant" +"System" "System" + +"Total" "Gesamt" + +"Uninstall" "De-installieren" +"Uninstall Picture?" "Bild de-installieren?" +"User Administration" "Benutzerverwaltung" + +"Zip" "PLZ" diff --git a/app/loc/es b/app/loc/es @@ -0,0 +1,86 @@ +# 20aug09art +# Armadillo <tc.rucho@gmail.com> + +"(@1 Positions)" "(@1 Posiciones)" + +"Address" "Dirección" + +"Can't print order" "No se puede imprimir la órden" +"Change" "Cambiar" +"City" "Ciudad" +"Contact" "Contacto" +"Continued on page @1" "Continuado en la página @1" +"Country" "País" +"Customer" "Cliente" +"Customer/Supplier" "Cliente/Proveedor" +"Customers/Suppliers" "Clientes/Proveedores" + +"Data" "Datos" +"Date" "Fecha" +"Dear Sir or Madam," "Estimado/a Sr/a," +"Description" "Descripción" + +"eMail" "eMail" + +"Fax" "Fax" +"Full Name" "Nombre Completo" + +"Greeting" "Saludos" + +"Home" "Inicio" + +"Incomplete customer address" "Dirección del cliente incompleta" +"Install" "Instalar" +"Inventory" "Inventario" +"Item" "Artículo" +"Items" "Artículos" + +"Login Name" "Nombre de usuario" + +"Memo" "Memo" +"Mobile" "Móbil" + +"Name" "Nombre" +"Name 2" "Segundo nombre" +"No customer" "No cliente" +"No customer name" "Nombre de cliente indefinido" +"No customer number" "Número de cliente indefinido" +"No item description" "Descripción de artículo indefinida" +"No item number" "Número de artículo no definido" +"No order date" "Fecha de órden, indefinida" +"No order number" "Número de órden indefinido" +"No positions" "Posiciones indefinidas" +"Number" "Número" + +"Order" "Orden" +"Orders" "Órdenes" + +"Page @1" "Página @1" +"PDF-Print" "Imprimir-PDF" +"Phone" "Teléfono" +"Picture" "Foto" +"Position without item" "Posición sin artículo" +"Position without price" "Posición sin precio" +"Position without quantity" "Posición sin cantidad" +"Price" "Precio" + +"Quantity" "Cantidad" + +"Report" "Reporte" +"Role Administration" "Administración de roles" + +"Sales" "Ventas" +"Salutation" "Saludo" +"Salutations" "Saludos" +"Sex" "Género" +"Street" "Calle" +"Supplier" "Proveedor" +"System" "Sistema" + +"Total" "Total" + +"Uninstall" "Desinstalar" +"Uninstall Picture?" "Desinstalar foto?" +"User Administration" "Administración de usuarios" + +"Zip" "Código Postal" diff --git a/app/loc/jp b/app/loc/jp @@ -0,0 +1,86 @@ +# 09may08abu +# (c) Software Lab. Alexander Burger + +"(@1 Positions)" "(ポジション数:@1)" + +"Address" "住所" + +"Can't print order" "注文書の印刷ができない" +"Change" "変換" +"City" "都市" +"Contact" "問い合わせ" +"Continued on page @1" "@1ページに続く" +"Country" "国" +"Customer" "カスタマー" +"Customer/Supplier" "カスタマー/注文先" +"Customers/Suppliers" "カスタマー/注文先" + +"Data" "データ" +"Date" "日付" +"Dear Sir or Madam," "拝啓," +"Description" "仕様" + +"eMail" "eメール" + +"Fax" "Fax" +"Full Name" "フルネーム" + +"Greeting" "手紙の書きだし" + +"Home" "ホーム" + +"Incomplete customer address" "カスタマーの住所不十分" +"Install" "インストール" +"Inventory" "在庫目録" +"Item" "商品" +"Items" "商品" + +"Login Name" "ログイン名" + +"Memo" "メモ" +"Mobile" "携帯電話" + +"Name" "名前" +"Name 2" "名前 2" +"No customer" "カスタマーなし" +"No customer name" "カスタマー名なし" +"No customer number" "カスタマー番号なし" +"No item description" "商品仕様なし" +"No item number" "商品番号なし" +"No order date" "注文書日付なし" +"No order number" "注文番号なし" +"No positions" "ポジションなし" +"Number" "番号" + +"Order" "注文" +"Orders" "注文" + +"Page @1" "@1 ページ" +"PDF-Print" "PDF印刷" +"Phone" "電話番号" +"Picture" "写真" +"Position without item" "ポジションに商品がない" +"Position without price" "ポジションに価格がない" +"Position without quantity" "ポジションに数量がない" +"Price" "価格" + +"Quantity" "数量" + +"Report" "レポート" +"Role Administration" "役割管理" + +"Sales" "セールス" +"Salutation" "敬称" +"Salutations" "敬称" +"Sex" "性別" +"Street" "住所" +"Supplier" "注文先" +"System" "システム" + +"Total" "総計" + +"Uninstall" "アンインストール" +"Uninstall Picture?" "写真をアンインストールしますか?" +"User Administration" "ユーザー管理" + +"Zip" "郵便番号" diff --git a/app/loc/no b/app/loc/no @@ -0,0 +1,86 @@ +# 14jan10jk +# Jon Kleiser, jon.kleiser@usit.uio.no + +"(@1 Positions)" "(@1 Posisjoner)" + +"Address" "Adresse" + +"Can't print order" "Kan ikke skrive ut bestilling" +"Change" "Endre" +"City" "By" +"Contact" "Kontakt" +"Continued on page @1" "Fortsettes på side @1" +"Country" "Land" +"Customer" "Kunde" +"Customer/Supplier" "Kunde/Leverandør" +"Customers/Suppliers" "Kunder/Leverandører" + +"Data" "Data" +"Date" "Dato" +"Dear Sir or Madam," "Kjære frue/herre," +"Description" "Beskrivelse" + +"eMail" "e-post" + +"Fax" "Fax" +"Full Name" "Fullt navn" + +"Greeting" "Hilsen" + +"Home" "Startside" + +"Incomplete customer address" "Ufullstendig kundeadresse" +"Install" "Installer" +"Inventory" "Lagerbeholdning" +"Item" "Artikkel" +"Items" "Artikler" + +"Login Name" "Innloggingsnavn" + +"Memo" "Merknad" +"Mobile" "Mobil" + +"Name" "Navn" +"Name 2" "Navn 2" +"No customer" "Kunde mangler" +"No customer name" "Kundenavn mangler" +"No customer number" "Kundenummer mangler" +"No item description" "Artikkelbeskrivelse mangler" +"No item number" "Artikkelnummer mangler" +"No order date" "Bestillingsdato mangler" +"No order number" "Bestillingsnummer mangler" +"No positions" "Ingen posisjoner" +"Number" "Nummer" + +"Order" "Bestilling" +"Orders" "Bestillinger" + +"Page @1" "Side @1" +"PDF-Print" "PDF-utskrift" +"Phone" "Telefon" +"Picture" "Bilde" +"Position without item" "Posisjon uten artikkel" +"Position without price" "Posisjon uten pris" +"Position without quantity" "Posisjon uten antall" +"Price" "Pris" + +"Quantity" "Antall" + +"Report" "Rapport" +"Role Administration" "Rolle-administrasjon" + +"Sales" "Salg" +"Salutation" "Titulering" +"Salutations" "Tituleringer" +"Sex" "Kjønn" +"Street" "Gate" +"Supplier" "Leverandør" +"System" "System" + +"Total" "Total" + +"Uninstall" "Av-installer" +"Uninstall Picture?" "Av-installere bilde?" +"User Administration" "Bruker-administrasjon" + +"Zip" "Postnr." diff --git a/app/loc/ru b/app/loc/ru @@ -0,0 +1,86 @@ +# 25apr08 +# Mansur Mamkin <mmamkin@mail.ru> + +"(@1 Positions)" "(@1 позиций)" + +"Address" "Адрес" + +"Can't print order" "Невозможно напечатать заказ" +"Change" "Изменить" +"City" "Город" +"Contact" "Контакт" +"Continued on page @1" "Продолжение на странице @1" +"Country" "Страна" +"Customer" "Покупатель" +"Customer/Supplier" "Покупатель/Поставщик" +"Customers/Suppliers" "Покупатели/Поставщики" + +"Data" "Данные" +"Date" "Дата" +"Dear Sir or Madam," "Уважаемый(ая)" +"Description" "Описание" + +"eMail" "емейл" + +"Fax" "Факс" +"Full Name" "Полное имя" + +"Greeting" "Приветствие" + +"Home" "Домой" + +"Incomplete customer address" "Неполный адрес покупателя" +"Install" "Установить" +"Inventory" "Инвентаризация" +"Item" "Товар" +"Items" "Товары" + +"Login Name" "Имя регистрации" + +"Memo" "Мемо" +"Mobile" "Мобильный" + +"Name" "Имя" +"Name 2" "Имя 2" +"No customer" "Нет покупателя" +"No customer name" "Нет имени покупателя" +"No customer number" "Нет номера покупателя" +"No item description" "Нет описания товара" +"No item number" "Нет номера товара" +"No order date" "Нет даты заказа" +"No order number" "Нет номера заказа" +"No positions" "Нет позиций" +"Number" "Номер" + +"Order" "Заказ" +"Orders" "Заказы" + +"Page @1" "Страница @1" +"PDF-Print" "Печать PDF" +"Phone" "Телефон" +"Picture" "Картинка" +"Position without item" "Позиция без товара" +"Position without price" "Позиция без цены" +"Position without quantity" "Позиция без количества" +"Price" "Цена" + +"Quantity" "Количество" + +"Report" "Отчет" +"Role Administration" "Управление ролями" + +"Sales" "Продажи" +"Salutation" "Приветствие" +"Salutations" "Приветствия" +"Sex" "Пол" +"Street" "Улица" +"Supplier" "Поставщик" +"System" "Система" + +"Total" "Всего" + +"Uninstall" "Удалить" +"Uninstall Picture?" "Удалить картинку?" +"User Administration" "Управление пользователями" + +"Zip" "Индекс" diff --git a/app/main.l b/app/main.l @@ -0,0 +1,61 @@ +# 14jan10abu +# (c) Software Lab. Alexander Burger + +(allowed ("app/" "img/") + "@start" "@stop" "favicon.ico" "lib.css" "@psh" ) + +(load "lib/http.l" "lib/xhtml.l" "lib/form.l" "lib/ps.l" "lib/adm.l") + +(setq + *Scl 2 + *Css "lib.css" + *Blob "blob/app/" ) + +(load "app/er.l" "app/lib.l" "app/gui.l") + +(permission + Customer ,"Customer" + Item ,"Item" + Order ,"Order" + Report ,"Report" + RoleAdmin ,"Role Administration" + UserAdmin ,"User Administration" + Password ,"Password" + Delete ,"Delete" ) + +(de *Locales + ("English" NIL) + ("English (US)" "US") + ("English (UK)" "UK") + ("Español (AR)" "AR" . "ar") + ("Español (ES)" "ES" . "es") + ("Deutsch (DE)" "DE" . "de") + ("Deutsch (CH)" "CH" . "ch") + ("Norsk" "NO" . "no") + ("Русский" "RU" . "ru") + ("日本語" "JP" . "jp") ) + +# Entry point +(de main () + (call 'mkdir "-p" "db/app/" *Blob) + (pool "db/app/" *Dbs) + (unless (seq *DB) + (load "app/init.l") ) ) + +(de go () + (pw 12) + (task (port 4040) # Set up query server in the background + (let? Sock (accept @) + (unless (fork) # Child process + (in Sock + (while (rd) + (sync) + (out Sock + (pr (eval @)) ) ) ) + (bye) ) + (close Sock) ) ) + (forked) + (rollback) + (server 8080 "@start") ) + +# vi:et:ts=3:sw=3 diff --git a/app/ord.l b/app/ord.l @@ -0,0 +1,58 @@ +# 03sep09abu +# (c) Software Lab. Alexander Burger + +(must "Order" Order) + +(menu ,"Order" + (ifn *ID + (prog + (<h3> NIL ,"Select" " " ,"Order") + (form 'dialog (choOrd)) ) + (<h3> NIL ,"Order") + (form NIL + (<h2> NIL (<id> (: nr))) + (panel T (pack ,"Order" " @1") '(may Delete) '(choOrd) 'nr '+Ord) + (<grid> 4 + ,"Date" NIL + (gui '(+E/R +DateField) '(dat : home obj) 10) + (gui '(+View +TextField) + '(text ,"(@1 Positions)" (length (: home obj pos))) ) + ,"Customer" (gui '(+ChoButton) '(choCuSu (field 1))) + (gui '(+E/R +Obj +TextField) '(cus : home obj) '(nm +CuSu) 30) + (gui '(+View +TextField) '(field -1 'obj 'ort) 30) ) + (--) + (gui '(+Set +E/R +Chart) '((L) (filter bool L)) '(pos : home obj) 8 + '((Pos I) + (with Pos + (list I NIL (: itm) (or (: pr) (: itm pr)) (: cnt) (sum> Pos)) ) ) + '((L D) + (cond + (D + (put!> D 'itm (caddr L)) + (put!> D 'pr (cadddr L)) + (put!> D 'cnt (; L 5)) + (and (; D itm) D) ) + ((caddr L) + (new! '(+Pos) 'itm (caddr L)) ) ) ) ) + (<table> NIL NIL + '((align) (btn) (NIL ,"Item") (NIL ,"Price") (NIL ,"Quantity") (NIL ,"Total")) + (do 8 + (<row> NIL + (gui 1 '(+NumField)) + (gui 2 '(+ChoButton) '(choItem (field 1))) + (gui 3 '(+Obj +TextField) '(nm +Item) 30) + (gui 4 '(+FixField) 2 12) + (gui 5 '(+NumField) 8) + (gui 6 '(+Sgn +Lock +FixField) 2 12) + (gui 7 '(+DelRowButton)) + (gui 8 '(+BubbleButton)) ) ) + (<row> NIL NIL NIL (scroll 8 T) NIL NIL + (gui '(+Sgn +View +FixField) '(sum> (: home obj)) 2 12) ) ) + (<spread> + (gui '(+Rid +Button) ,"PDF-Print" + '(if (check> (: home obj)) + (note ,"Can't print order" (uniq @)) + (psOut 0 ,"Order" (ps> (: home obj))) ) ) + (editButton T) ) ) ) ) + +# vi:et:ts=3:sw=3 diff --git a/app/role.l b/app/role.l @@ -0,0 +1,33 @@ +# 22apr10abu +# (c) Software Lab. Alexander Burger + +(must "Role Administration" RoleAdmin) + +(menu ,"Role Administration" + (ifn *ID + (prog + (<h3> NIL ,"Select" " " ,"Role") + (form 'dialog (choDlg NIL ,"Roles" '(nm +Role))) ) + (<h3> NIL ,"Role Administration") + (form NIL + (<h2> NIL (<id> (: nm))) + (panel T (pack ,"Role" " '@1'") '(may Delete) '(choDlg NIL ,"Roles" '(nm +Role)) 'nm '+Role) + (gui '(+E/R +Cue +TextField) '(nm : home obj) ,"Role" 30 ,"Name") + (<table> NIL NIL NIL + (gui '(+E/R +Fmt +Chart) + '(perm : home obj) + '((Val) (mapcar '((S) (list S (memq S Val))) *Perms)) + '((Lst) (extract '((L P) (and (cadr L) P)) Lst *Perms)) + 2 ) + (do (length *Perms) + (<row> NIL + (gui 1 '(+Set +TextField) '((Sym) (val (val Sym)))) + (gui 2 '(+Checkbox)) ) ) ) + (gui '(+/R +Chart) '(usr : home obj) 1 list) + (<table> 'chart ,"User" NIL + (do 8 + (<row> (alternating) + (gui 1 '(+Obj +TextField) '(nm +User)) ) ) ) + (<spread> (scroll 8 T) (editButton T)) ) ) ) + +# vi:et:ts=3:sw=3 diff --git a/app/sal.l b/app/sal.l @@ -0,0 +1,21 @@ +# 03jan09abu +# (c) Software Lab. Alexander Burger + +(must "Salutation" Customer) + +(menu ,"Salutation" + (ifn *ID + (prog + (<h3> NIL ,"Select" " " ,"Salutation") + (form 'dialog (choDlg NIL ,"Salutations" '(nm +Sal))) ) + (<h3> NIL ,"Salutation") + (form NIL + (<h2> NIL (<id> (: nm))) + (panel T (pack ,"Salutation" " '@1'") '(may Delete) '(choDlg NIL ,"Salutations" '(nm +Sal)) 'nm '+Sal) + (<grid> 2 + ,"Salutation" (gui '(+E/R +Cue +TextField) '(nm : home obj) ,"Salutation" 40) + ,"Greeting" (gui '(+E/R +TextField) '(hi : home obj) 40) + ,"Sex" (gui '(+E/R +SexField) '(sex : home obj)) ) + (<spread> NIL (editButton T)) ) ) ) + +# vi:et:ts=3:sw=3 diff --git a/app/sales.l b/app/sales.l @@ -0,0 +1,56 @@ +# 08mar10abu +# (c) Software Lab. Alexander Burger + +(must "Sales" Report) + +(menu ,"Sales" + (<h3> NIL ,"Sales") + (form NIL + (<grid> "-.-" + ,"Date" NIL + (prog + (gui '(+Var +DateField) '*SalFrom 10) + (prin " - ") + (gui '(+Var +DateField) '*SalTill 10) ) + ,"Customer" (gui '(+ChoButton) '(choCuSu (field 1))) + (gui '(+Var +Obj +TextField) '*SalCus '(nm +CuSu) 30) ) + (--) + (gui '(+ShowButton) NIL + '(csv ,"Sales" + (<table> 'chart NIL + (<!> + (quote + (align) + (NIL ,"Date") + (NIL ,"Customer") + NIL + (NIL ,"Zip") + (NIL ,"City") + (align ,"Total") ) ) + (catch NIL + (let Sum 0 + (pilog + (quote + @Rng (cons *SalFrom (or *SalTill T)) + @Cus *SalCus + (select (@Ord) + ((dat +Ord @Rng) (cus +Ord @Cus)) + (range @Rng @Ord dat) + (same @Cus @Ord cus) ) ) + (with @Ord + (let N (sum> This) + (<row> (alternating) + (<+> (: nr) This) + (<+> (datStr (: dat)) This) + (<+> (: cus nm) (: cus)) + (<+> (: cus nm2)) + (<+> (: cus plz)) + (<+> (: cus ort)) + (<-> (money N)) ) + (inc 'Sum N) ) ) + (at (0 . 10000) (or (flush) (throw))) ) + (<row> 'nil + (<strong> ,"Total") - - - - - + (<strong> (prin (money Sum))) ) ) ) ) ) ) ) ) + +# vi:et:ts=3:sw=3 diff --git a/app/user.l b/app/user.l @@ -0,0 +1,36 @@ +# 03jan09abu +# (c) Software Lab. Alexander Burger + +(must "User Administration" UserAdmin) + +(menu ,"User Administration" + (ifn *ID + (prog + (<h3> NIL ,"Select" " " ,"User") + (form 'dialog (choDlg NIL ,"Users" '(nm +User))) ) + (<h3> NIL ,"User Administration") + (form NIL + (<h2> NIL (<id> (: nm))) + (panel T (pack ,"User" " '@1'") '(may Delete) '(choDlg NIL ,"Users" '(nm +User)) 'nm '+User) + (<grid> 2 + ,"Login Name" (gui '(+E/R +Cue +TextField) '(nm : home obj) ,"User" 30) + ,"Password" + (gui '(+Tip +Able +E/R +Fmt +TextField) + '(and (may Password) (val> This)) + '(may Password) + '(pw : home obj) + '((V) (and V "****")) + '((V) (if (= V "****") (: home obj pw) V)) + 30 ) + ,"Role" + (gui '(+Able +E/R +Obj +TextField) + '(may RoleAdmin) + '(role : home obj) + '(nm +Role) + T ) + ,"Full Name" (gui '(+E/R +TextField) '(nam : home obj) 40) + ,"Phone" (gui '(+E/R +TelField) '(tel : home obj) 40) + ,"EMail" (gui '(+E/R +MailField) '(em : home obj) 40) ) + (<spread> NIL (editButton T)) ) ) ) + +# vi:et:ts=3:sw=3 diff --git a/bin/pil b/bin/pil @@ -0,0 +1,2 @@ +#!/usr/bin/picolisp /usr/lib/picolisp/lib.l +(load "@lib/misc.l" "@lib/btree.l" "@lib/db.l" "@lib/pilog.l") diff --git a/bin/psh b/bin/psh @@ -0,0 +1,14 @@ +#!bin/picolisp lib.l +# 28sep07abu +# (c) Software Lab. Alexander Burger + +(load "@lib/misc.l" "@lib/http.l") + +(raw T) +(let *Dbg NIL + (client "localhost" (format (opt)) + (pack "@psh?" (pw) "&" (in '("tty") (line T))) + (ctty (read)) + (line) + (line) ) ) +(bye) diff --git a/bin/replica b/bin/replica @@ -0,0 +1,31 @@ +#!bin/picolisp lib.l +# 21aug07abu +# Use: bin/replica <port> <keyFile> <journal> <dbFile> <blob/app/> [dbs1 ..] +# : bin/ssl <host> 443 <port>/@replica <keyFile> <journal> <blob/app/> 60 + +(load "@lib/misc.l" "@lib/http.l") + +(allowed NIL "@replica") + +(argv *Port *KeyFile *Journal *Pool *Blob . *Dbs) + +(setq + *Port (format *Port) + *SSLKey (in *KeyFile (line T)) ) + +(de replica () + (ctl *KeyFile + (protect + (when (= (line T) *SSLKey) + (let? X (line T) + (if (format X) + (when (out (tmp 'replica) (echo @)) # Journal + (prin (peek)) + (flush) + (journal (tmp 'replica)) ) + (let Blob (pack *Blob X) # Blob + (call 'mkdir "-p" (dirname Blob)) + (out Blob (echo)) ) ) ) ) ) ) ) + +(pool *Pool (mapcar format *Dbs) *Journal) +(server *Port) diff --git a/bin/scrape b/bin/scrape @@ -0,0 +1,11 @@ +#!bin/picolisp lib.l +# 07oct08abu +# (c) Software Lab. Alexander Burger + +(load "ext.l" "dbg.l" "lib/http.l" "lib/scrape.l") + +(scrape + (or (opt) "localhost") + (or (format (opt)) 8080) ) + +# vi:et:ts=3:sw=3 diff --git a/bin/watchdog b/bin/watchdog @@ -0,0 +1,68 @@ +#!bin/picolisp lib.l +# 09mar08abu +# (c) Software Lab. Alexander Burger +# Use: bin/watchdog <host> <port> <from> <to1> <to2> .. + +(load "@lib/misc.l") + +# *MailHost *MailPort *MailFrom *MailTo *Watch + +(argv *MailHost *MailPort *MailFrom . *MailTo) +(setq *MailPort (format *MailPort)) + +(unless (call 'test "-p" "fifo/beat") + (call 'mkdir "-p" "fifo") + (call 'rm "-f" "fifo/beat") + (call 'mkfifo "fifo/beat") ) + +(push1 '*Bye '(call 'rm "fifo/beat")) + +(de *Err + (prin (stamp)) + (space) + (println *Watch) ) + +(task (open "fifo/beat") + (in @ + (let X (rd) + (cond + ((not X) (bye)) + ((num? X) + (del (assoc X *Watch) '*Watch) ) + ((atom X) # bin/picolisp -"out 'fifo/beat (pr '$(tty))" -bye + (let D (+ (* 86400 (date T)) (time T)) + (out X + (for W *Watch + (prinl + (align 5 (car W)) + " " + (- (cadr W) D) + " " + (or (caddr W) "o") + " " + (cdddr W) ) ) ) ) ) + ((assoc (car X) *Watch) # X = (Pid Tim . Any) + (let W @ # W = (Pid Tim Flg . Any) + (when (caddr W) + (msg (car W) " " (stamp) " resumed") ) + (set (cdr W) (cadr X)) + (set (cddr W)) + (con (cddr W) (or (cddr X) (cdddr W))) ) ) + (T (push '*Watch (list (car X) (cadr X) NIL (cddr X)))) ) ) ) ) + +(task -54321 54321 + (let D (+ (* 86400 (date T)) (time T)) + (for W (filter '((X) (> D (cadr X))) *Watch) + (if (caddr W) + (prog + (msg (car W) " " (stamp) + (if (kill (car W) 15) " killed" " gone") ) + (del W '*Watch) ) + (inc (cdr W) 3600) + (set (cddr W) T) + (let Sub (pack "Timeout " (car W) " " (cdddr W)) + (msg (car W) " " (stamp)) + (unless (mail *MailHost *MailPort *MailFrom *MailTo Sub) + (msg (cons Sub *MailTo) " mail failed " (stamp)) ) ) ) ) ) ) + +(wait) diff --git a/cygwin/README b/cygwin/README @@ -0,0 +1,170 @@ +Porting PicoLisp to Cygwin + +A few months back, I was looking at Lisp programming language +offerings for the MS Windows environment. I want an interpreter +that is fast and powerful, yet small. I want it to work well in +the Cygwin/Win32 environment. + +Enter PicoLisp. http://software-lab.de/down.html + +According to the PicoLisp FAQ, "PicoLisp is for programmers +who want to control their programming environment, at all +levels, from the application domain down to the bare metal." +Yes! That's part of what I want a Lisp for. Especially a Lisp I +might embed in other applications. I want control. PicoLisp +looked promising. + +PicoLisp is designed with a philosophy of "succinctness", +according to the literature on the site. Although there are +even smaller Lisp interpreters available, PicoLisp seemed to +strike a balance between terseness and functionality. + +PicoLisp is written using standard C, and the author +(Alexander Burger) distributes it as C source code under the +GNU General Public License. That means if you want to use +PicoLisp, you'll need to compile it yourself, or otherwise obtain +the executables. PicoLisp comes in two flavours: picolisp, and +an even smaller version: mini picolisp. (More about mini +picolisp in a bit.) + +When you do build PicoLisp for yourself, you'll get a +powerhouse of a Lisp including APIs for building web servers, +gui web application servers (for browser clients running java +and/or javascript) integrated relational databases, prolog db +access, and much more. PicoLisp even comes with two example +versions of a flight simulator: one which runs under X-Windows, +the other which uses a client's browser/java for the display. +There's a chess game written in PicoLisp and Prolog. + +Lest one think that PicoLisp is a mere toy, consider this. In +2006, PicoLisp won second prize in the German-language C't +Magazine database contest, beating entries written using DB2 +and Oracle. Industrial-strength databases with tightly +integrated web applications have been crafted with PicoLisp. +http://tinyurl.com/y9wu39 + +PicoLisp has some drawbacks and limitations. As the FAQ warns, +PicoLisp "does not pretend to be easy to learn." It is not a +Common Lisp flavor. It is not "some standard, 'safe' black-box, +which may be easier to learn." Also, for my purposes, I want +software that runs not only on Linux, but also on PCs with the +MS-Windows operating systems. And there was the rub: PicoLisp +isn't distributed with binaries or Windows exe files. + +Even worse (for Windows users), PicoLisp wasn't ported to +Cygwin. I have a growing list of portable apps that will run on +a flash drive, many of them I compiled from source from using +Cygwin tools like make, gcc, etc. + +Cygwin provides a POSIX emulation layer in the form of +cygwin1.dll and other libraries. This lets a PC running Windows +look like much like a Linux or UNIX box to programs which have +been compiled for Cygwin. I'd compiled hundreds of programs +for Cygwin and here was PicoLisp which I wanted to have +running on all my PCs, Linux ones as well as the MS-Windows +PCs, too. + +So this was beginning to look like a challenge. I'd just take a +little peek at porting PicoLisp to Cygwin, and see how it +would go. I'd ported everything from sox to busybox to fluxbox +to Cygwin, so I felt ready for porting PicoLisp. + +PicoLisp comes in two flavors. Mini picolisp and full +picolisp. + +Mini PicoLisp is a kind of a "pure" PicoLisp without +system-dependent functions like databases, UTF-8, bignums, IPC, +and networking. This seemed like a good place to start my +PicoLisp porting adventures. I first tried a straight Cygwin/gcc +build, and that worked fine, no hitches. + +Then I remembered the -mno-cygwin compiler flag for Cygwin's +gcc. When you compile with -mno-cygwin, gcc causes the +resulting executable to be built without Cygwin dll library +dependances. For C code that relies heavily upon the POSIX +emulation aspects of Cygwin, this might not work. But why not +try building mini picolisp with the -mno-cygwin option? + +The C code for mini picolisp is free from Linux/POSIX system +calls, and it compiled with no problems using -mno-cygwin. It +produced a mini picolisp exe file of about 73K, which is not +dependant upon any Cygwin DLLs. + +Porting the full PicoLisp interpreter proved to be more of a +challenge. Whereas the mini picolisp was careful to avoid Linux +system calls, PicoLisp takes the opposite approach and uses +Linux (UNIX/POSIX) system functions where needed. + +Additionally, PicoLisp has the ability to dynamically load +shared libraries for various extensions. + +Since we need to use shared libraries anyway, I wanted for all +of picolisp to go into a single DLL. Then the picolisp exe +would be a just small stub that uses that the shared library, +picolisp.dll. PicoLisp applications often use fork, so this +should also be more efficient when forking. + +Splitting up PicoLisp this way (a DLL and an exe stub) would +allow the picolisp.dll to be used as a Lisp library. As a +shared library, it would then be possible for other +applications to treat PicoLisp as an embedded interpreter, +somewhat like librep, but much smaller and more portable. + +Wanting to see how much I could squeeze down the size of the +executables and libraries under Cygwin, I used gcc's -Os +option, which requests that gcc optimize by making the smallest +possible code. Doing this resulted in a picolisp dll of just +150K, and a picolisp exe stub of only 2K. + +Of course, if you want this full PicoLisp to run on a Windows +PC which does not already have Cygwin installed, you'll need to +obtain a few Cygwin DLLs which provide the POSIX emulation +layer for PicoLisp. + +For the most part, the port to Win32/Cygwin went smoothly. +There were just a few differences between Linux and Cygwin that +were handled with macro ifdef statements in the C code that +allow something to be done differently for the Cygwin +compilation. + +In the end it turned out that the biggest problem was the fcntl +system function that does file and record locking. This was +especially frustrating, as time and time again, I thought I'd +found a solution or a work-around to the differences in +semantics of the fcntl call between Linux and Cygwin, only to +have the my "solution" fail with more rigorous testing. + +The locking problem was finally just circumvented for Windows +by simply not using fcntl locking. So, there is no file or +record locking for PicoLisp running under Windows. (See the +locking notes in http://www.sqlite.org/lockingv3.html for +another perspective on locking system functions in Windows.) +However, all the example applications run fine, running in a +special (Solo) mode in PicoLisp, in the few places it even +matters. This avoids depending on buggy or non-existent record +locking functionality with the various Windows versions and +file system types. + +So, what do we have at this point? PicoLisp is running on the +PC. A working, industrial-strength Lisp interpreter is +PicoLisp, ready for writing applications that are succinct yet +powerful. PicoLisp comes with a Prolog interpreter and +relational databases and flight simulators and chess games and +web servers and chat servers and sendmail and much more. + +And PicoLisp itself is written in highly portable C, running +on Linux and Windows. PicoLisp is readily embedable, and will +be useful to add scripting languages (Lisp, Prolog) to other +applications, either statically linked, or as a shared library +(DLL). + +PicoLisp is a little dynamo. It even has the ability to use +in-line C code which is compiled on-the-fly into a shared +library. This in-line C ability uses gcc. (And it works with +tcc, the Tiny C Compiler, too.) + +With the tremendous number of PCs out there now able to run +PicoLisp, watch out! PicoLisp may be small, but sometimes +very powerful things come in small packages. + +Doug Snead, Jan. 2007 diff --git a/cygwin/tcc.l b/cygwin/tcc.l @@ -0,0 +1,22 @@ +# 21jan07abu +# (c) Software Lab. Alexander Burger + +# use the Tiny C Compiler http://fabrice.bellard.free.fr/tcc +(de tcc (S L . @) + (out (tmp S ".c") + (chdir '@ (prinl "#include <pico.h>")) + (here "/**/") ) + (apply call L 'tcc "-shared" "-rdynamic" + (pack "-I" (dospath "/usr/include")) + (pack "-I" (dospath (path "@/src"))) + "-falign-functions" "-fomit-frame-pointer" + "-W" "-Wimplicit" "-Wreturn-type" "-Wunused" "-Wformat" + "-Wuninitialized" "-Wstrict-prototypes" "-pipe" + "-D_GNU_SOURCE" "-D_FILE_OFFSET_BITS=64" "-DNOWAIT" + "-o" (tmp S ".dll") (tmp S ".c") + (dospath (path "@/bin/picolisp.def"))) + (while (args) + (def (next) (def (tmp S ': (arg)))) ) ) + +(de dospath (p) + (in '("cygpath" "-m" p) (line T)) ) diff --git a/dbg b/dbg @@ -0,0 +1,2 @@ +#!/bin/sh +exec ${0%/*}/bin/picolisp -"on *Dbg" ${0%/*}/lib.l @ext.l @dbg.l "$@" diff --git a/dbg.l b/dbg.l @@ -0,0 +1,16 @@ +# 14apr10abu +# (c) Software Lab. Alexander Burger + +(on *Dbg) + +(when (sys "TERM") + (setq *Tsm + (cons + (in '("tput" "smul") (line T)) + (in '("tput" "rmul") (line T)) ) ) ) + +(load "@lib/debug.l" "@lib/led.l" "@lib/edit.l" "@lib/lint.l" "@lib/sq.l") + +(noLint 'later (loc "@Prg" later)) + +# vi:et:ts=3:sw=3 diff --git a/doc/app.html b/doc/app.html @@ -0,0 +1,2551 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/1998/REC-html40-19980424/loose.dtd"> +<html lang="en"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> +<title>PicoLisp Application Development</title> +<link rel="stylesheet" href="doc.css" type="text/css"> +</head> +<body> +<a href="mailto:abu@software-lab.de">abu@software-lab.de</a> + +<h1>PicoLisp Application Development</h1> + +<p align=right>(c) Software Lab. Alexander Burger + +<p>This document presents an introduction to writing browser-based applications +in PicoLisp. + +<p>It concentrates on the XHTML/CSS GUI-Framework (as opposed to the previous +Java-AWT, Java-Swing and Plain-HTML frameworks), which is easier to use, more +flexible in layout design, and does not depend on plug-ins, JavaScript or +cookies. + +<p>A plain HTTP/HTML GUI has various advantages: It runs on any browser, and can +be fully driven by scripts ("lib/scrape.l"). + +<p>To be precise: CSS <i>can</i> be used to enhance the layout. And browsers +<i>with</i> JavaScript will respond faster and smoother. But this framework +works just fine in browsers which do not know anything about CSS or JavaScript. +All examples were also tested using the w3m text browser. + +<p>For basic informations about the PicoLisp system please look at the <a +href="ref.html">PicoLisp Reference</a> and the <a href="tut.html">PicoLisp +Tutorial</a>. Knowledge of HTML, and a bit of CSS and HTTP is assumed. + +<p>Throughout this document, transient symbols will be displayed with <code><a +href="refT.html#*Tsm">*Tsm</a></code> turned off, i.e. as "Name" (double-quoted) +instead of <u>Name</u> (underlined), to make it easier to copy/paste the +examples. + +<p><ul> +<li><a href="#static">Static Pages</a> + <ul> + <li><a href="#hello">Hello World</a> + <ul> + <li><a href="#server">Start the application server</a> + <li><a href="#how">How does it work?</a> + </ul> + <li><a href="#urlSyntax">URL Syntax</a> + <li><a href="#security">Security</a> + <ul> + <li><a href="#pw">The ".pw" File</a> + </ul> + <li><a href="#htmlFoo">The <code>html</code> Function</a> + <li><a href="#cssAttr">CSS Attributes</a> + <li><a href="#tags">Tag Functions</a> + <ul> + <li><a href="#simple">Simple Tags</a> + <li><a href="#lists">(Un)ordered Lists</a> + <li><a href="#tables">Tables</a> + <li><a href="#menus">Menus and Tabs</a> + </ul> + </ul> +<li><a href="#forms">Interactive Forms</a> + <ul> + <li><a href="#sessions">Sessions</a> + <li><a href="#actionForms">Action Forms</a> + <ul> + <li><a href="#guiFoo">The <code>gui</code> Function</a> + <li><a href="#ctlFlow">Control Flow</a> + <li><a href="#switching">Switching URLs</a> + <li><a href="#dialogs">Alerts and Dialogs</a> + <li><a href="#calc">A Calculator Example</a> + </ul> + <li><a href="#charts">Charts</a> + <ul> + <li><a href="#scrolling">Scrolling</a> + <li><a href="#putGet">Put and Get Functions</a> + </ul> + </ul> +<li><a href="#guiClasses">GUI Classes</a> + <ul> + <li><a href="#inputFields">Input Fields</a> + <ul> + <li><a href="#numberFields">Numeric Input Fields</a> + <li><a href="#timeDateFields">Time &amp; Date</a> + <li><a href="#telFields">Telephone Numbers</a> + <li><a href="#checkboxes">Checkboxes</a> + </ul> + <li><a href="#fieldPrefix">Field Prefix Classes</a> + <ul> + <li><a href="#initPrefix">Initialization</a> + <li><a href="#ablePrefix">Disabling and Enabling</a> + <li><a href="#formatPrefix">Formatting</a> + <li><a href="#sideEffects">Side Effects</a> + <li><a href="#validPrefix">Validation</a> + <li><a href="#linkage">Data Linkage</a> + </ul> + <li><a href="#buttons">Buttons</a> + <ul> + <li><a href="#dialogButtons">Dialog Buttons</a> + <li><a href="#jsButtons">Active JavaScript</a> + </ul> + </ul> +<a name="minAppRef"></a> +<li><a href="#minApp">A Minimal Complete Application</a> + <ul> + <li><a href="#getStarted">Getting Started</a> + <ul> + <li><a href="#localization">Localization</a> + <li><a href="#navigation">Navigation</a> + <li><a href="#choosing">Choosing Objects</a> + <li><a href="#editing">Editing</a> + <li><a href="#btnLinks">Buttons vs. Links</a> + </ul> + <li><a href="#dataModel">The Data Model</a> + <li><a href="#usage">Usage</a> + <ul> + <li><a href="#cuSu">Customer/Supplier</a> + <li><a href="#item">Item</a> + <li><a href="#order">Order</a> + <li><a href="#reports">Reports</a> + </ul> + <li><a href="#bugs">Bugs</a> + </ul> +</ul> + + +<p><hr> +<h2><a name="static">Static Pages</a></h2> + +<p>You can use PicoLisp to generate static HTML pages. This does not make much +sense in itself, because you could directly write HTML code as well, but it +forms the base for interactive applications, and allows us to introduce the +application server and other fundamental concepts. + +<p><hr> +<h3><a name="hello">Hello World</a></h3> + +<p>To begin with a minimal application, please enter the following two lines +into a generic source file named "project.l" in the PicoLisp installation +directory. + +<pre><code> +######################################################################## +(html 0 "Hello" "lib.css" NIL + "Hello World!" ) +######################################################################## +</code></pre> + +<p>(We will modify and use this file in all following examples and experiments. +Whenever you find such a program snippet between hash ('#') lines, just copy and +paste it into your "project.l" file, and press the "reload" button of your +browser to view the effects) + + +<h4><a name="server">Start the application server</a></h4> + +<p>Open a second terminal window, and start a PicoLisp application server + +<pre><code> +$ ./dbg lib/http.l lib/xhtml.l lib/form.l -'server 8080 "project.l"' +</code></pre> + +<p>No prompt appears. The server just sits, and waits for connections. You can +stop it later by hitting <code>Ctrl-C</code> in that terminal, or by executing +'<code>killall picolisp</code>' in some other window. + +<p>(In the following, we assume that this HTTP server is up and running) + +<p>Now open the URL '<code><a +href="http://localhost:8080">http://localhost:8080</a></code>' with your +browser. You should see an empty page with a single line of text. + + +<h4><a name="how">How does it work?</a></h4> + +<p>The above line loads the debugger ('./dbg', which is equivalent to "./p +dbg.l"), the HTTP server code ("lib/http.l"), the XHTML functions +("lib/xhtml.l") and the input form framework ("lib/form.l", it will be needed +later for <a href="#forms">interactive forms</a>). + +<p>Then the <code>server</code> function is called with a port number and a +default URL. It will listen on that port for incoming HTTP requests in an +endless loop. Whenever a GET request arrives on port 8080, the file "project.l" +will be <code><a href="refL.html#load">(load)</a></code>ed, causing the +evaluation (= execution) of all its Lisp expressions. + +<p>During that execution, all data written to the current output channel is sent +directly to to the browser. The code in "project.l" is responsible to produce +HTML (or anything else the browser can understand). + + +<p><hr> +<h3><a name="urlSyntax">URL Syntax</a></h3> + +<p>The PicoLisp application server uses a slightly specialized syntax when +communicating URLs to and from a client. The "path" part of an URL - which +remains when + +<p><ul> +<li>the preceding protocol, host and port specifications, +<li>and the trailing question mark plus arguments +</ul> + +are stripped off - is interpreted according so some rules. The most prominent +ones are: + +<p><ul> +<li>If a path starts with an at-mark ('@'), the rest (without the '@') is taken +as the name of a Lisp function to be called. All arguments following the +question mark are passed to that function. + +<li>If a path ends with ".l" (a dot and a lower case 'L'), it is taken as a Lisp +source file name to be <code><a href="refL.html#load">(load)</a></code>ed. This +is the most common case, and we use it in our example "project.l". + +<li>If the extension of a file name matches an entry in the global mime type +table <code>*Mimes</code>, the file is sent to the client with mime-type and +max-age values taken from that table. + +<li>Otherwise, the file is sent to the client with a mime-type of +"application/octet-stream" and a max-age of 1 second. + +</ul> + +<p>An application is free to extend or modify the <code>*Mimes</code> table with +the <code>mime</code> function. For example + +<pre><code> +(mime "doc" "application/msword" 60) +</code></pre> + +<p>defines a new mime type with a max-age of one minute. + +<p>Argument values in URLs, following the path and the question mark, are +encoded in such a way that Lisp data types are preserved: + +<p><ul> +<li>An internal symbol starts with a dollar sign ('$') +<li>A number starts with a plus sign ('+') +<li>An external (database) symbol starts with dash ('-') +<li>A list (one level only) is encoded with underscores ('_') +<li>Otherwise, it is a transient symbol (a plain string) + +</ul> + +<p>In that way, high-level data types can be directly passed to functions +encoded in the URL, or assigned to global variables before a file is loaded. + + +<p><hr> +<h3><a name="security">Security</a></h3> + +<p>It is, of course, a huge security hole that - directly from the URL - any +Lisp source file can be loaded, and any Lisp function can be called. For that +reason, applications must take care to declare exactly which files and functions +are to be allowed in URLs. The server checks a global variable <code><a +href="refA.html#*Allow">*Allow</a></code>, and - when its value is +non-<code>NIL</code> - denies access to anything that does not match its +contents. + +<p>Normally, <code>*Allow</code> is not manipulated directly, but set with the +<code><a href="refA.html#allowed">allowed</a></code> and <code><a +href="refA.html#allow">allow</a></code> functions + +<pre><code> +(allowed ("img/" "demo/") + "favicon.ico" "lib.css" + "@start" "customer.l" "article.l") +</code></pre> + +<p>This is usually called in the beginning of an application, and allows access +to the directories "img/" and "demo/", to the function 'start', and to the files +"favicon.ico", "lib.css", "customer.l" and "article.l". + +<p>Later in the program, <code>*Allow</code> may be dynamically extended with +<code>allow</code> + +<pre><code> +(allow "@foo") +(allow "newdir/" T) +</code></pre> + +<p>This adds the function 'foo', and the directory "newdir/", to the set of +allowed items. + + +<h4><a name="pw">The ".pw" File</a></h4> + +<p>For a variety of security checks (most notably for using the <code>psh</code> +function, as in some later examples) it is necessary to create a file named +".pw" in the PicoLisp installation directory. This file should contain a single +line of arbitrary data, to be used as a password for identifying local +resources. + +<p>The recommeded way to create this file is to call the <code>pw</code> +function, defined in "lib/http.l" + +<pre><code> +$ ./p lib/http.l -'pw 12' -bye +</code></pre> + +<p>Please execute this command. + + +<p><hr> +<h3><a name="htmlFoo">The <code>html</code> Function</a></h3> + +<p>Now back to our "Hello World" example. In principle, you could write +"project.l" as a sequence of print statements + +<pre><code> +######################################################################## +(prinl "HTTP/1.0 200 OK^M") +(prinl "Content-Type: text/html; charset=utf-8") +(prinl "^M") +(prinl "&lt;html&gt;") +(prinl "Hello World!") +(prinl "&lt;/html&gt;") +######################################################################## +</code></pre> + +<p>but using the <code>html</code> function is much more convenient. + +<p>Moreover, <code>html</code> <b>is</b> nothing more than a printing function. +You can see this easily if you connect a PicoLisp Shell (<code>psh</code>) to +the server process (you must have generated a <a href="#pw">".pw" file</a> for +this), and enter the <code>html</code> statement + +<pre><code> +$ bin/psh 8080 +: (html 0 "Hello" "lib.css" NIL "Hello World!") +HTTP/1.0 200 OK +Server: PicoLisp +Date: Fri, 29 Dec 2006 07:28:58 GMT +Cache-Control: max-age=0 +Cache-Control: no-cache +Content-Type: text/html; charset=utf-8 + +&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt; +&lt;html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"&gt; +&lt;head&gt; +&lt;title&gt;Hello&lt;/title&gt; +&lt;base href="http://localhost:8080/"/&gt; +&lt;link rel="stylesheet" href="http://localhost:8080/lib.css" type="text/css"/&gt; +&lt;/head&gt; +&lt;body&gt;Hello World!&lt;/body&gt; +&lt;/html&gt; +-&gt; &lt;/html&gt; +: # (type ENTER here to terminate the PicoLisp Shell) +</code></pre> + +<p>These are the arguments to <code>html</code>: + +<ol> + +<li><code>0</code>: A max-age value for cache-control (in seconds, zero means +"no-cache"). You might pass a higher value for pages that change seldom, or +<code>NIL</code> for no cache-control at all. + +<li><code>"Hello"</code>: The page title. + +<li><code>"lib.css"</code>: A CSS-File name. Pass <code>NIL</code> if you do not want +to use any CSS-File, or a list of file names if you want to give more than one +CSS-File. + +<li><code>NIL</code>: A CSS style attribute specification (see the description +of <a href="#cssAttr">CSS Attributes</a> below). It will be passed to the +<code>body</code> tag. + +</ol> + +<p>After these four arguments, an arbitrary number of expressions may follow. +They form the body of the resulting page, and are evaluated according to a +special rule. <a name="tagRule">This rule</a> is slightly different from the +evaluation of normal Lisp expressions: + +<p><ul> + +<li>If an argument is an atom (a number or a symbol (string)), its value is +printed immediately. + +<li>Otherwise (a list), it is evaluated as a Lisp function (typically some form +of print statement). + +</ul> + +<p>Therefore, our source file might as well be written as: + +<pre><code> +######################################################################## +(html 0 "Hello" "lib.css" NIL + (prinl "Hello World!") ) +######################################################################## +</code></pre> + +<p>The most typical print statements will be some HTML-tags: + +<pre><code> +######################################################################## +(html 0 "Hello" "lib.css" NIL + (&lt;h1&gt; NIL "Hello World!") + (&lt;br&gt; "This is some text.") + (ht:Prin "And this is a number: " (+ 1 2 3)) ) +######################################################################## +</code></pre> + +<p><code>&lt;h1&gt;</code> and <code>&lt;br&gt;</code> are tag functions. +<code>&lt;h1&gt;</code> takes a CSS attribute as its first argument. + +<p>Note the use of <code>ht:Prin</code> instead of <code>prin</code>. +<code>ht:Prin</code> should be used for all direct printing in HTML pages, +because it takes care to escape special characters. + + +<p><hr> +<h3><a name="cssAttr">CSS Attributes</a></h3> + +<p>The <a href="#htmlFoo"><code>html</code> function</a> above, and many of the +HTML <a href="#tags">tag functions</a>, accept a CSS attribute specification. +This may be either an atom, a cons pair, or a list of cons pairs. We demonstrate +the effects with the <code>&lt;h1&gt;</code> tag function. + +<p>An atom (usually a symbol or a string) is taken as a CSS class name + +<pre><code> +: (&lt;h1&gt; 'foo "Title") +&lt;h1 class="foo"&gt;Title&lt;/h1&gt; +</code></pre> + +<p>For a cons pair, the CAR is taken as an attribute name, and the CDR as the +attribute's value + +<pre><code> +: (&lt;h1&gt; '(id . bar) "Title") +&lt;h1 id="bar"&gt;Title&lt;/h1&gt; +</code></pre> + +<p>Consequently, a list of cons pairs gives a set of attribute-value pairs + +<pre><code> +: (&lt;h1&gt; '((id . "abc") (lang . "de")) "Title") +&lt;h1 id="abc" lang="de"&gt;Title&lt;/h1&gt; +</code></pre> + + +<p><hr> +<h3><a name="tags">Tag Functions</a></h3> + +<p>All pre-defined XHTML tag functions can be found in "lib/xhtml.l". We +recommend to look at their sources, and to experiment a bit, by executing them +at a PicoLisp prompt, or by pressing the browser's "Reload" button after editing +the "project.l" file. + +<p>For a suitable PicoLisp prompt, either execute (in a separate terminal +window) the PicoLisp Shell (<code>psh</code>) command (works only if the +application server is running, and you did generate a <a href="#pw">".pw" +file</a>) + +<pre><code> +$ bin/psh 8080 +: +</code></pre> + +<p>or start the interpreter stand-alone, with "lib/xhtml.l" loaded + +<pre><code> +$ ./dbg lib/http.l lib/xhtml.l +: +</code></pre> + +<p>Note that for all these tag functions the above <a href="#tagRule">tag body +evaluation rule</a> applies. + + +<h4><a name="simple">Simple Tags</a></h4> + +<p>Most tag functions are simple and straightforward. Some of them just print +their arguments + +<pre><code> +: (&lt;br&gt; "Hello world") +Hello world&lt;br/&gt; + +: (&lt;em&gt; "Hello world") +&lt;em&gt;Hello world&lt;/em&gt; +</code></pre> + +<p>while most of them take a <a href="#cssAttr">CSS attribute specification</a> +as their first argument (like the <code>&lt;h1&gt;</code> tag above) + +<pre><code> +: (&lt;div&gt; 'main "Hello world") +&lt;div class="main"&gt;Hello world&lt;/div&gt; + +: (&lt;p&gt; NIL "Hello world") +&lt;p&gt;Hello world&lt;/p&gt; + +: (&lt;p&gt; 'info "Hello world") +&lt;p class="info"&gt;Hello world&lt;/p&gt; +</code></pre> + +<p>All of these functions take an arbitrary number of arguments, and may nest to +an arbitrary depth (as long as the resulting HTML is legal) + +<pre><code> +: (&lt;div&gt; 'main + (&lt;h1&gt; NIL "Head") + (&lt;p&gt; NIL + (&lt;br&gt; "Line 1") + "Line" + (&lt;nbsp&gt;) + (+ 1 1) ) ) +&lt;div class="main"&gt;&lt;h1&gt;Head&lt;/h1&gt; +&lt;p&gt;Line 1&lt;br/&gt; +Line&nbsp;2&lt;/p&gt; +&lt;/div&gt; +</code></pre> + + +<h4><a name="lists">(Un)ordered Lists</a></h4> + +<p>HTML-lists, implemented by the <code>&lt;ol&gt;</code> and +<code>&lt;ul&gt;</code> tags, let you define hierarchical structures. You might +want to paste the following code into your copy of "project.l": + +<pre><code> +######################################################################## +(html 0 "Unordered List" "lib.css" NIL + (&lt;ul&gt; NIL + (&lt;li&gt; NIL "Item 1") + (&lt;li&gt; NIL + "Sublist 1" + (&lt;ul&gt; NIL + (&lt;li&gt; NIL "Item 1-1") + (&lt;li&gt; NIL "Item 1-2") ) ) + (&lt;li&gt; NIL "Item 2") + (&lt;li&gt; NIL + "Sublist 2" + (&lt;ul&gt; NIL + (&lt;li&gt; NIL "Item 2-1") + (&lt;li&gt; NIL "Item 2-2") ) ) + (&lt;li&gt; NIL "Item 3") ) ) +######################################################################## +</code></pre> + +<p>Here, too, you can put arbitrary code into each node of that tree, including +other tag functions. + + +<h4><a name="tables">Tables</a></h4> + +<p>Like the hierarchical structures with the list functions, you can generate +two-dimensional tables with the <code>&lt;table&gt;</code> and +<code>&lt;row&gt;</code> functions. + +<p>The following example prints a table of numbers and their squares: + +<pre><code> +######################################################################## +(html 0 "Table" "lib.css" NIL + (&lt;table&gt; NIL NIL NIL + (for (N 1 (&gt;= 10 N) (inc N)) # A table with 10 rows + (&lt;row&gt; NIL N (prin (* N N))) ) ) ) # and 2 columns +######################################################################## +</code></pre> + +<p>The first argument to <code>&lt;table&gt;</code> is the usual CSS attribute, +the second an optional title ("caption"), and the third an optional list +specifying the column headers. In that list, you may supply a list for a each +column, with a CSS attribute in its CAR, and a tag body in its CDR for the +contents of the column header. + +<p>The body of <code>&lt;table&gt;</code> contains calls to the +<code>&lt;row&gt;</code> function. This function is special in that each +expression in its body will go to a separate column of the table. If both for +the column header and the row function an CSS attribute is given, they will be +combined by a space and passed to the HTML <code>&lt;td&gt;</code> tag. This +permits distinct CSS specifications for each column and row. + +<p>As an extension of the above table example, let's pass some attributes for +the table itself (not recommended - better define such styles in a CSS file and +then just pass the class name to <code>&lt;table&gt;</code>), right-align both +columns, and print each row in an alternating red and blue color + +<pre><code> +######################################################################## +(html 0 "Table" "lib.css" NIL + (&lt;table&gt; + '((width . "200px") (style . "border: dotted 1px;")) # table style + "Square Numbers" # caption + '((align "Number") (align "Square")) # 2 headers + (for (N 1 (&gt;= 10 N) (inc N)) # 10 rows + (&lt;row&gt; (xchg '(red) '(blue)) # red or blue + N # 2 columns + (prin (* N N) ) ) ) ) ) +######################################################################## +</code></pre> + +<p>If you wish to concatenate two or more cells in a table, so that a single +cell spans several columns, you can pass the symbol '<code>-</code>' for the +additional cell data to <code>&lt;row&gt;</code>. This will cause the data given +to the left of the '<code>-</code>' symbols to expand to the right. + +<p>You can also directly specify table structures with the simple +<code>&lt;th&gt;</code>, <code>&lt;tr&gt;</code> and <code>&lt;td&gt;</code> tag +functions. + +<p>If you just need a two-dimensional arrangement of components, the even +simpler <code>&lt;grid&gt;</code> function might be convenient: + +<pre><code> +######################################################################## +(html 0 "Grid" "lib.css" NIL + (&lt;grid&gt; 3 + "A" "B" "C" + 123 456 789 ) ) +######################################################################## +</code></pre> + +<p>It just takes a specification for the number of columns (here: 3) as its +first argument, and then a single expression for each cell. Instead of a number, +you can also pass a list of CSS attributes. Then the length of that list will +determine the number of columns. You can change the second line in the above +example to + +<pre><code> + (&lt;grid&gt; '(NIL NIL right) +</code></pre> + +<p>Then the third column will be right aligned. + + +<h4><a name="menus">Menus and Tabs</a></h4> + +<p>The two most powerful tag functions are <code>&lt;menu&gt;</code> and +<code>&lt;tab&gt;</code>. Used separately or in combination, they form a +navigation framework with + +<p><ul> +<li>menu items which open and close submenus +<li>submenu items which switch to different pages +<li>tabs which switch to different subpages +</ul> + +<p>The following example is not very useful, because the URLs of all items link +to the same "project.l" page, but it should suffice to demonstrate the +functionality: + +<pre><code> +######################################################################## +(html 0 "Menu+Tab" "lib.css" NIL + (&lt;div&gt; '(id . menu) + (&lt;menu&gt; + ("Item" "project.l") # Top level item + (NIL (&lt;hr&gt;)) # Plain HTML + (T "Submenu 1" # Submenu + ("Subitem 1.1" "project.l") + (T "Submenu 1.2" + ("Subitem 1.2.1" "project.l") + ("Subitem 1.2.2" "project.l") + ("Subitem 1.2.3" "project.l") ) + ("Subitem 1.3" "project.l") ) + (T "Submenu 2" + ("Subitem 2.1" "project.l") + ("Subitem 2.2" "project.l") ) ) ) + (&lt;div&gt; '(id . main) + (&lt;h1&gt; NIL "Menu+Tab") + (&lt;tab&gt; + ("Tab1" + (&lt;h3&gt; NIL "This is Tab 1") ) + ("Tab2" + (&lt;h3&gt; NIL "This is Tab 2") ) + ("Tab3" + (&lt;h3&gt; NIL "This is Tab 3") ) ) ) ) +######################################################################## +</code></pre> + +<p><code>&lt;menu&gt;</code> takes a sequence of menu items. Each menu item is a +list, with its CAR either + +<p><ul> +<li><code>NIL</code>: The entry is not an active menu item, and the rest of the +list may consist of arbitrary code (usually HTML tags). + +<li><code>T</code>: The second element is taken as a submenu name, and a click +on that name will open or close the corresponding submenu. The rest of the list +recursively specifies the submenu items (may nest to arbitrary depth). + +<li>Otherwise: The menu item specifies a direct action (instead of opening a +submenu), where the first list element gives the item's name, and the second +element the corresponding URL. + +</ul> + +<p><code>&lt;tab&gt;</code> takes a list of subpages. Each page is simply a tab +name, followed by arbitrary code (typically HTML tags). + +<p>Note that only a single menu and a single tab may be active at the same time. + + +<p><hr> +<h2><a name="forms">Interactive Forms</a></h2> + +<p>In HTML, the only possibility for user input is via <code>&lt;form&gt;</code> +and <code>&lt;input&gt;</code> elements, using the HTTP POST method to +communicate with the server. + +<p>"lib/xhtml.l" defines a function called <code>&lt;post&gt;</code>, and a +collection of input tag functions, which allow direct programming of HTML forms. +We will supply only one simple example: + +<pre><code> +######################################################################## +(html 0 "Simple Form" "lib.css" NIL + (&lt;post&gt; NIL "project.l" + (&lt;field&gt; 10 '*Text) + (&lt;submit&gt; "Save") ) ) +######################################################################## +</code></pre> + +<p>This associates a text input field with a global variable <code>*Text</code>. +The field displays the current value of <code>*Text</code>, and pressing the +submit button causes a reload of "project.l" with <code>*Text</code> set to any +string entered by the user. + +<p>An application program could then use that variable to do something useful, +for example store its value in a database. + +<p>The problem with such a straightforward use of forms is that + +<p><ol> +<li>they require the application programmer to take care of maintaining lots of +global variables. Each input field on the page needs an associated variable for +the round trip between server and client. + +<li>they do not preserve an application's internal state. Each POST request +spawns an individual process on the server, which sets the global variables to +their new values, generates the HTML page, and terminates thereafter. The +application state has to be passed along explicitly, e.g. using +<code>&lt;hidden&gt;</code> tags. + +<li>they are not very interactive. There is typically only a single submit +button. The user fills out a possibly large number of input fields, but changes +will take effect only when the submit button is pressed. + +</ol> + +<p>Though we wrote a few applications in that style, we recommend the GUI +framework provided by "lib/form.l". It does not need any variables for the +client/server communication, but implements a class hierarchy of GUI components +for the abstraction of application logic, button actions and data linkage. + + +<p><hr> +<h3><a name="sessions">Sessions</a></h3> + +<p>First of all, we need to establish a persistent environment on the server, to +handle each individual session (for each connected client). + +<p>Technically, this is just a child process of the server we started <a +href="#server">above</a>, which does not terminate immediately after it sent its +page to the browser. It is achieved by calling the <code>app</code> function +somewhere in the application's startup code. + +<pre><code> +######################################################################## +(app) # Start a session + +(html 0 "Simple Session" "lib.css" NIL + (&lt;post&gt; NIL "project.l" + (&lt;field&gt; 10 '*Text) + (&lt;submit&gt; "Save") ) ) +######################################################################## +</code></pre> + +<p>Nothing else changed from the previous example. However, when you connect +your browser and then look at the terminal window where you started the +application server, you'll notice a colon, the PicoLisp prompt + +<pre><code> +$ ./dbg lib/http.l lib/xhtml.l lib/form.l -'server 8080 "project.l"' +: +</code></pre> + +<p>Tools like the Unix <code>ps</code> utility will tell you that now two +<code>picolisp</code> processes are running, the first being the parent of the +second. + +<p>If you enter some text, say "abcdef", into the text field in the browser +window, press the submit button, and inspect the Lisp <code>*Text</code> +variable, + +<pre><code> +: *Text +-> "abcdef" +</code></pre> + +<p>you see that we now have a dedicated PicoLisp process, "connected" to the +client. + +<p>You can terminate this process (like any interactive PicoLisp) by hitting +ENTER on an empty line. Otherwise, it will terminate by itself if no other +browser requests arrive within a default timeout period of 5 minutes. + +<p>To start a (non-debug) production version, the server is commonly started not +as 'dbg' but with a 'p', and with <code>-wait</code> + +<pre><code> +$ ./p lib/http.l lib/xhtml.l lib/form.l -'server 8080 "project.l"' -wait +</code></pre> + +<p>In that way, no command line prompt appears when a client connects. + + +<p><hr> +<h3><a name="actionForms">Action Forms</a></h3> + +<p>Now that we have a persistent session for each client, we can set up an +active GUI framework. + +<p>This is done by wrapping the call to the <code>html</code> function with +<code>action</code>. Inside the body of <code>html</code> can be - in addition +to all other kinds of tag functions - one or more calls to <code>form</code> + +<pre><code> +######################################################################## +(app) # Start session + +(action # Action handler + (html 0 "Form" "lib.css" NIL # HTTP/HTML protocol + (form NIL # Form + (gui 'a '(+TextField) 10) # Text Field + (gui '(+Button) "Print" # Button + '(msg (val&gt; (: home a))) ) ) ) ) +######################################################################## +</code></pre> + +<p>Note that there is no longer a global variable like <code>*Text</code> to +hold the contents of the input field. Instead, we gave a local, symbolic name +'<code>a</code>' to a <code>+TextField</code> component + +<pre><code> + (gui 'a '(+TextField) 10) # Text Field +</code></pre> + +<p>Other components can refer to it + +<pre><code> + '(msg (val&gt; (: home a))) +</code></pre> + +<p><code>(: home)</code> is always the form which contains this GUI component. +So <code>(: home a)</code> evaluates to the component '<code>a</code>' in the +current form. As <code><a href="refM.html#msg">msg</a></code> prints its +argument to standard error, and the <code>val&gt;</code> method retrieves the +current contents of a component, we will see on the console the text typed into +the text field when we press the button. + +<p>An <code>action</code> without embedded <code>form</code>s - or a +<code>form</code> without a surrounding <code>action</code> - does not make much +sense by itself. Inside <code>html</code> and <code>form</code>, however, calls +to HTML functions (and any other Lisp functions, for that matter) can be freely +mixed. + +<p>In general, a typical page may have the form + +<pre><code> +(action # Action handler + (html .. # HTTP/HTML protocol + (&lt;h1&gt; ..) # HTML tags + (form NIL # Form + (&lt;h3&gt; ..) + (gui ..) # GUI component(s) + (gui ..) + .. ) + (&lt;h2&gt; ..) + (form NIL # Another form + (&lt;h3&gt; ..) + (gui ..) # GUI component(s) + .. ) + (&lt;br&gt; ..) + .. ) ) +</code></pre> + + +<h4><a name="guiFoo">The <code>gui</code> Function</a></h4> + +<p>The most prominent function in a <code>form</code> body is <code>gui</code>. +It is the workhorse of GUI construction. + +<p>Outside of a <code>form</code> body, <code>gui</code> is undefined. +Otherwise, it takes an optional alias name, a list of classes, and additional +arguments as needed by the constructors of these classes. We saw this example +before + +<pre><code> + (gui 'a '(+TextField) 10) # Text Field +</code></pre> + +Here, '<code>a</code>' is an alias name for a component of type +<code>(+TextField)</code>. The numeric argument <code>10</code> is passed to the +text field, specifying its width. See the chapter on <a href="#guiClasses">GUI +Classes</a> for more examples. + +<p>During a GET request, <code>gui</code> is basically a front-end to +<code>new</code>. It builds a component, stores it in the internal structures of +the current form, and initializes it by sending the <code>init&gt;</code> +message to the component. Finally, it sends it the <code>show&gt;</code> +message, to produce HTML code and transmit it to the browser. + +<p>During a POST request, <code>gui</code> does not build any new components. +Instead, the existing components are re-used. So <code>gui</code> does not have +much more to do than sending the <code>show&gt;</code> message to a component. + + +<h4><a name="ctlFlow">Control Flow</a></h4> + +<p>HTTP has only two methods to change a browser window: GET and POST. We employ +these two methods in a certain defined, specialized way: + +<p><ul> +<li>GET means, a <b>new page</b> is being constructed. It is used when a page is +visited for the first time, usually by entering an URL into the browser's +address field, or by clicking on a link (which is often a <a +href="#menus">submenu item or tab</a>). + +<li>POST is always directed to the <b>same page</b>. It is triggered by a button +press, updates the corresponding form's data structures, and executes that +button's action code. + +</ul> + +<p>A button's action code can do almost anything: Read and modify the contents +of input fields, communicate with the database, display alerts and dialogs, or +even fake the POST request to a GET, with the effect of showing a completely +different document (See <a href="#switching">Switching URLs</a>). + +<p>GET builds up all GUI components on the server. These components are objects +which encapsulate state and behavior of the HTML page in the browser. Whenever a +button is pressed, the page is reloaded via a POST request. Then - before any +output is sent to the browser - the <code>action</code> function takes control. +It performs error checks on all components, processes possible user input on the +HTML page, and stores the values in correct format (text, number, date, object +etc.) in each component. + +<p>The state of a form is preserved over time. When the user returns to a +previous page with the browser's BACK button, that state is reactivated, and may +be POSTed again. + +<p>The following silly example displays two text fields. If you enter some text +into the "Source" field, you can copy it in upper or lower case to the +"Destination" field by pressing one of the buttons + +<pre><code> +######################################################################## +(app) + +(action + (html 0 "Case Conversion" "lib.css" NIL + (form NIL + (&lt;grid&gt; 2 + "Source" (gui 'src '(+TextField) 30) + "Destination" (gui 'dst '(+Lock +TextField) 30) ) + (gui '(+JS +Button) "Upper Case" + '(set&gt; (: home dst) + (uppc (val&gt; (: home src))) ) ) + (gui '(+JS +Button) "Lower Case" + '(set&gt; (: home dst) + (lowc (val&gt; (: home src))) ) ) ) ) ) +######################################################################## +</code></pre> + +<p>The <code>+Lock</code> prefix class in the "Destination" field makes that +field read-only. The only way to get some text into that field is by using one +of the buttons. + + +<h4><a name="switching">Switching URLs</a></h4> + +<p>Because an action code runs before <code>html</code> has a chance to output +an HTTP header, it can abort the current page and present something different to +the user. This might, of course, be another HTML page, but would not be very +interesting as a normal link would suffice. Instead, it can cause the download +of dynamically generated data. + +<p>The next example shows a text area and two buttons. Any text entered into the +text area is exported either as a text file via the first button, or a PDF +document via the second button + +<pre><code> +######################################################################## +(load "lib/ps.l") + +(app) + +(action + (html 0 "Export" "lib.css" NIL + (form NIL + (gui '(+TextField) 30 8) + (gui '(+Button) "Text" + '(let Txt (tmp "export.txt") + (out Txt (prinl (val&gt; (: home gui 1)))) + (url Txt) ) ) + (gui '(+Button) "PDF" + '(psOut NIL "foo" + (a4) + (indent 40 40) + (down 60) + (hline 3) + (font (14 . "Times-Roman") + (ps (val&gt; (: home gui 1))) ) + (hline 3) + (page) ) ) ) ) ) +######################################################################## +</code></pre> + +<p>(a text area is built when you supply two numeric arguments (columns and +rows) to a <code>+TextField</code> class) + +<p>The action code of the first button creates a temporary file (i.e. a file +named "export.txt" in the current process's temporary space), prints the value +of the text area (this time we did not bother to give it a name, we simply refer +to it as the form's first gui list element) into that file, and then calls the +<code>url</code> function with the file name. + +<p>The second button uses the PostScript library "lib/ps.l" to create a +temporary file "foo.pdf". Here, the temporary file creation and the call to the +<code>url</code> function is hidden in the internal mechanisms of +<code>psOut</code>. The effect is that the browser receives a PDF document and +displays it. + + +<h4><a name="dialogs">Alerts and Dialogs</a></h4> + +<p>Alerts and dialogs are not really what they used to be ;-) + +<p>They do not "pop up". In this framework, they are just a kind of +simple-to-use, pre-fabricated form. They can be invoked by a button's action +code, and appear always on the current page, immediately preceding the form +which created them. + +<p>Let's look at an example which uses two alerts and a dialog. In the +beginning, it displays a simple form, with a locked text field, and two buttons + +<pre><code> +######################################################################## +(app) + +(action + (html 0 "Alerts and Dialogs" "lib.css" NIL + (form NIL + (gui '(+Init +Lock +TextField) "Initial Text" 20 "My Text") + (gui '(+Button) "Alert" + '(alert NIL "This is an alert " (okButton)) ) + (gui '(+Button) "Dialog" + '(dialog NIL + (&lt;br&gt; "This is a dialog.") + (&lt;br&gt; + "You can change the text here " + (gui '(+Init +TextField) (val&gt; (: top 1 gui 1)) 20) ) + (&lt;br&gt; "and then re-submit it to the form.") + (gui '(+Button) "Re-Submit" + '(alert NIL "Are you sure? " + (yesButton + '(set&gt; (: home top 2 gui 1) + (val&gt; (: home top 1 gui 1)) ) ) + (noButton) ) ) + (cancelButton) ) ) ) ) ) +######################################################################## +</code></pre> + +<p>The <code>+Init</code> prefix class initializes the "My Text" field with the +string "Initial Text". As the field is locked, you cannot modify this value +directly. + +<p>The first button brings up an alert saying "This is an alert.". You can +dispose it by pressing "OK". + +<p>The second button brings up a dialog with an editable text field, containing +a copy of the value from the form's locked text field. You can modify this +value, and send it back to the form, if you press "Re-Submit" and answer "Yes" +to the "Are you sure?" alert. + + +<h4><a name="calc">A Calculator Example</a></h4> + +<p>Now let's forget our "project.l" test file for a moment, and move on to a +more substantial and practical, stand-alone, example. Using what we have learned +so far, we want to build a simple bignum calculator. ("bignum" because PicoLisp +can do <i>only</i> bignums) + +<p>It uses a single form, a single numeric input field, and lots of buttons. It +can be found in the PicoLisp distribution in "misc/calc.l", together with a +directly executable wrapper script "misc/calc". + +<p>To use it, change to the PicoLisp installation directory, and start it as + +<pre><code> +$ misc/calc +</code></pre> + +<p>If you want to use it from other directories too, change the two relative +path names in the first line to absolute paths. We recommend symbolic links in +some global directories, as described in the <a +href="tut.html#script">Scripting</a> section of the PicoLisp Tutorial. + +<p>If you like to get a PicoLisp prompt for inspection, start it instead as + +<pre><code> +$ ./dbg misc/calc.l -main -go +</code></pre> + +<p>Then - as before - point your browser to '<code><a +href="http://localhost:8080">http://localhost:8080</a></code>'. + +<p>The code for the calculator logic and the GUI is rather straightforward. The +entry point is the single function <code>calculator</code>. It is called +directly (as described in <a href="#urlSyntax">URL Syntax</a>) as the server's +default URL, and implicitly in all POST requests. No further file access is +needed once the calculator is running. + +<p>Note that for a production application, we inserted an allow-statement (as +recommended by the <a href="#security">Security</a> chapter) + +<pre><code> +(allowed NIL "@calculator" "favicon.ico" "lib.css") +</code></pre> + +<p>at the beginning of "misc/calc.l". This will restrict external access to that +single function. + +<p>The calculator uses three global variables, <code>*Init</code>, +<code>*Accu</code> and <code>*Stack</code>. <code>*Init</code> is a boolean flag +set by the operator buttons to indicate that the next digit should initialize +the accumulator to zero. <code>*Accu</code> is the accumulator. It is always +displayed in the numeric input field, accepts user input, and it holds the +results of calculations. <code>*Stack</code> is a push-down stack, holding +postponed calculations (operators, priorities and intermediate results) with +lower-priority operators, while calculations with higher-priority operators are +performed. + +<p>The function <code>digit</code> is called by the digit buttons, and adds +another digit to the accumulator. + +<p>The function <code>calc</code> does an actual calculation step. It pops the +stack, checks for division by zero, and displays an error alert if necessary. + +<p><code>operand</code> processes an operand button, accepting a function and a +priority as arguments. It compares the priority with that in the top-of-stack +element, and delays the calculation if it is less. + +<p><code>finish</code> is used to calculate the final result. + +<p>The <code>calculator</code> function has one numeric input field, with a +width of 60 characters + +<pre><code> + (gui '(+Var +NumField) '*Accu 60) +</code></pre> + +<p>The <code>+Var</code> prefix class associates this field with the global +variable <code>*Accu</code>. All changes to the field will show up in that +variable, and modification of that variable's value will appear in the field. + +<p>The <a name="sqrtButton">square root operator button</a> has an +<code>+Able</code> prefix class + +<pre><code> + (gui '(+Able +JS +Button) '(ge0 *Accu) (char 8730) + '(setq *Accu (sqrt *Accu)) ) +</code></pre> + + +<p>with an argument expression which checks that the current value in the +accumulator is positive, and disables the button if otherwise. + +<p>The rest of the form is just an array (grid) of buttons, encapsulating all +functionality of the calculator. The user can enter numbers into the input +field, either by using the digit buttons, or by directly typing them in, and +perform calculations with the operator buttons. Supported operations are +addition, subtraction, multiplication, division, sign inversion, square root and +power (all in bignum integer arithmetic). The '<code>C</code>' button just +clears the accumulator, while the '<code>A</code>' button also clears all +pending calculations. + +<p>All that in 53 lines of code! + + +<p><hr> +<h3><a name="charts">Charts</a></h3> + +<p>Charts are virtual components, maintaining the internal representation of +two-dimensional data. + +<p>Typically, these data are nested lists, database selections, or some kind of +dynamically generated tabular information. Charts make it possible to view them +in rows and columns (usually in HTML <a href="#tables">tables</a>), scroll up +and down, and associate them with their corresponding visible GUI components. + +<p>In fact, the logic to handle charts makes up a substantial part of the whole +framework, with large impact on all internal mechanisms. Each GUI component must +know whether it is part of a chart or not, to be able to handle its contents +properly during updates and user interactions. + +<p>Let's assume we want to collect textual and numerical data. We might create a +table + +<pre><code> +######################################################################## +(app) + +(action + (html 0 "Table" "lib.css" NIL + (form NIL + (&lt;table&gt; NIL NIL '((NIL "Text") (NIL "Number")) + (do 4 + (&lt;row&gt; NIL + (gui '(+TextField) 20) + (gui '(+NumField) 10) ) ) ) + (&lt;submit&gt; "Save") ) ) ) +######################################################################## +</code></pre> + +<p>with two columns "Text" and "Number", and four rows, each containing a +<code>+TextField</code> and a <code>+NumField</code>. + +<p>You can enter text into the first column, and numbers into the second. +Pressing the "Save" button stores these values in the components on the server +(or produces an error message if a string in the second column is not a legal +number). + +<p>There are two problems with this solution: + +<p><ol> +<li>Though you can get at the user input for the individual fields, e.g. + +<pre><code> +: (val> (get *Top 'gui 2)) # Value in the first row, second column +-> 123 +</code></pre> + +there is no direct way to get the whole data structure as a single list. +Instead, you have to traverse all GUI components and collect the data. + +<li>The user cannot input more than four rows of data, because there is no easy +way to scroll down and make space for more. + +</ol> + +<p>A chart can handle these things: + +<pre><code> +######################################################################## +(app) + +(action + (html 0 "Chart" "lib.css" NIL + (form NIL + (gui '(+Chart) 2) # Inserted a +Chart + (&lt;table&gt; NIL NIL '((NIL "Text") (NIL "Number")) + (do 4 + (&lt;row&gt; NIL + (gui 1 '(+TextField) 20) # Inserted '1' + (gui 2 '(+NumField) 10) ) ) ) # Inserted '2' + (&lt;submit&gt; "Save") ) ) ) +######################################################################## +</code></pre> + +<p>Note that we inserted a <code>+Chart</code> component before the GUI +components which should be managed by the chart. The argument '2' tells the +chart that it has to expect two columns. + +<p>Each component got an index number (here '1' and '2') as the first argument +to <code>gui</code>, indicating the column into which this component should go +within the chart. + +<p>Now - if you entered "a", "b" and "c" into the first, and 1, 2, and 3 into +the second column - we can retrieve the chart's complete contents by sending it +the <code>val&gt;</code> message + +<pre><code> +: (val> (get *Top 'chart 1)) # Retrieve the value of the first chart +-> (("a" 1) ("b" 2) ("c" 3)) +</code></pre> + +<p>BTW, a more convenient function is <code>chart</code> + +<pre><code> +: (val> (chart)) # Retrieve the value of the current chart +-> (("a" 1) ("b" 2) ("c" 3)) +</code></pre> + +<p><code>chart</code> can be used instead of the above construct when we want to +access the "current" chart, i.e. the chart most recently processed in the +current form. + + +<h4><a name="scrolling">Scrolling</a></h4> + +<p>To enable scrolling, let's also insert two buttons. We use the pre-defined +classes <code>+UpButton</code> and <code>+DnButton</code> + +<pre><code> +######################################################################## +(app) + +(action + (html 0 "Scrollable Chart" "lib.css" NIL + (form NIL + (gui '(+Chart) 2) + (&lt;table&gt; NIL NIL '((NIL "Text") (NIL "Number")) + (do 4 + (&lt;row&gt; NIL + (gui 1 '(+TextField) 20) + (gui 2 '(+NumField) 10) ) ) ) + (gui '(+UpButton) 1) # Inserted two buttons + (gui '(+DnButton) 1) + (----) + (&lt;submit&gt; "Save") ) ) ) +######################################################################## +</code></pre> + +<p>to scroll down and up a single (argument '1') line at a time. + +<p>Now it is possible to enter a few rows of data, scroll down, and continue. It +is not necessary (except in the beginning, when the scroll buttons are still +disabled) to press the "Save" button, because <b>any</b> button in the form will +send changes to the server's internal structures before any action is performed. + + +<h4><a name="putGet">Put and Get Functions</a></h4> + +<p>As we said, a chart is a virtual component to edit two-dimensional data. +Therefore, a chart's native data format is a list of lists: Each sublist +represents a single row of data, and each element of a row corresponds to a +single GUI component. + +<p>In the example above, we saw a row like + +<pre><code> + ("a" 1) +</code></pre> + +<p>being mapped to + +<pre><code> + (gui 1 '(+TextField) 20) + (gui 2 '(+NumField) 10) +</code></pre> + +<p>Quite often, however, such a one-to-one relationship is not desired. The +internal data structures may have to be presented in a different form to the +user, and user input may need conversion to an internal representation. + +<p>For that, a chart accepts - in addition to the "number of columns" argument - +two optional function arguments. The first function is invoked to 'put' the +internal representation into the GUI components, and the second to 'get' data +from the GUI into the internal representation. + +<p>A typical example is a chart displaying customers in a database. While the +internal representation is a (one-dimensional) list of customer objects, 'put' +expands each object to a list with, say, the customer's first and second name, +telephone number, address and so on. When the user enters a customer's name, +'get' locates the matching object in the database and stores it in the internal +representation. In the following, 'put' will in turn expand it to the GUI. + +<p>For now, let's stick with a simpler example: A chart that holds just a list +of numbers, but expands in the GUI to show also a textual form of each number +(in German). + +<pre><code> +######################################################################## +(app) + +(load "lib/zahlwort.l") + +(action + (html 0 "Numerals" "lib.css" NIL + (form NIL + (gui '(+Init +Chart) (1 5 7) 2 + '((N) (list N (zahlwort N))) + car ) + (&lt;table&gt; NIL NIL '((NIL "Numeral") (NIL "German")) + (do 4 + (&lt;row&gt; NIL + (gui 1 '(+NumField) 9) + (gui 2 '(+Lock +TextField) 90) ) ) ) + (gui '(+UpButton) 1) + (gui '(+DnButton) 1) + (----) + (&lt;submit&gt; "Save") ) ) ) +######################################################################## +</code></pre> + +<p>"lib/zahlwort.l" defines the utility function <code>zahlwort</code>, which is +required later by the 'put' function. <code>zahlwort</code> accepts a number and +returns its wording in German. + +<p>Now look at the code + +<pre><code> + (gui '(+Init +Chart) (1 5 7) 2 + '((N) (list N (zahlwort N))) + car ) +</code></pre> + +<p>We prefix the <code>+Chart</code> class with <code>+Init</code>, and pass it +a list of numbers <code>(1 5 7)</code> for the initial value of the chart. Then, +following the '2' (the chart has two columns), we pass a 'put' function + +<pre><code> + '((N) (list N (zahlwort N))) +</code></pre> + +<p>which takes a number and returns a list of that number and its wording, and a +'get' function + +<pre><code> + car ) +</code></pre> + +<p>which in turn accepts such a list and returns a number, which happens to be +the list's first element. + +<p>You can see from this example that 'get' is the inverse function of 'put'. +'get' can be omitted, however, if the chart is read-only (contains no (or only +locked) input fields). + +<p>The field in the second column + +<pre><code> + (gui 2 '(+Lock +TextField) 90) ) ) ) +</code></pre> + +<p>is locked, because it displays the text generated by 'put', and is not +supposed to accept any user input. + +<p>When you start up this form in your browser, you'll see three pre-filled +lines with "1/eins", "5/fünf" and "7/sieben", according to the +<code>+Init</code> argument <code>(1 5 7)</code>. Typing a number somewhere into +the first column, and pressing ENTER or one of the buttons, will show a suitable +text in the second column. + + +<p><hr> +<h2><a name="guiClasses">GUI Classes</a></h2> + +<p>In previous chapters we saw examples of GUI classes like +<code>+TextField</code>, <code>+NumField</code> or <code>+Button</code>, often +in combination with prefix classes like <code>+Lock</code>, <code>+Init</code> +or <code>+Able</code>. Now we take a broader look at the whole hierarchy, and +try more examples. + +<p>The abstract class <code>+gui</code> is the base of all GUI classes. A live +view of the class hierarchy can be obtained with the <code><a +href="refD.html#dep">dep</a></code> ("dependencies") function: + +<pre><code> +: (dep '+gui) + +JsField + +Button + +UpButton + +PickButton + +DstButton + +ClrButton + +ChoButton + +Hint + +GoButton + +BubbleButton + +DelRowButton + +ShowButton + +DnButton + +field + +Checkbox + +TextField + +FileField + +ClassField + +numField + +NumField + +FixField + +BlobField + +DateField + +SymField + +UpField + +MailField + +SexField + +AtomField + +PwField + +ListTextField + +LinesField + +TelField + +TimeField + +HttpField + +Radio +-> +gui +</code></pre> + +<p>We see, for example, that <code>+DnButton</code> is a subclass of +<code>+Button</code>, which in turn is a subclass of <code>+gui</code>. +Inspecting <code>+DnButton</code> directly + +<pre><code> +: (dep '+DnButton) + +Tiny + +Rid + +JS + +Able + +gui + +Button ++DnButton +-> +DnButton +</code></pre> + +<p>shows that <code>+DnButton</code> inherits from <code>+Tiny</code>, +<code>+Rid</code>, <code>+Able</code> and <code>+Button</code>. The actual +definition of <code>+DnButton</code> can be found in "lib/form.l" + +<pre><code> +(class +DnButton +Tiny +Rid +JS +Able +Button) +... +</code></pre> + +<p>In general, "lib/form.l" is the ultimate reference to the framework, and +should be freely consulted. + + +<p><hr> +<h3><a name="inputFields">Input Fields</a></h3> + +<p>Input fields implement the visual display of application data, and allow - +when enabled - input and modification of these data. + +<p>On the HTML level, they can take the form of + +<ul> +<li>Normal text input fields +<li>Textareas +<li>Checkboxes +<li>Drop-down selections +<li>Password fields +<li>HTML links +<li>Plain HTML text +</ul> + +<p>Except for checkboxes, which are implemented by the <a +href="#checkboxes">Checkbox</a> class, all these HTML representations are +generated by <code>+TextField</code> and its content-specific subclasses like +<code>+NumField</code>, <code>+DateField</code> etc. Their actual appearance (as +one of the above forms) depends on their arguments: + +<p>We saw already "normal" text fields. They are created with a single numeric +argument. This example creates an editable field with a width of 10 characters: + +<pre><code> + (gui '(+TextField) 10) +</code></pre> + +<p>If you supply a second numeric for the line count ('4' in this case), you'll +get a text area: + +<pre><code> + (gui '(+TextField) 10 4) +</code></pre> + +<p>Supplying a list of values instead of a count yields a drop-down selection +(combo box): + +<pre><code> + (gui '(+TextField) '("Value 1" "Value 2" "Value 3")) +</code></pre> + +<p>In addition to these arguments, you can pass a string. Then the field is +created with a label: + +<pre><code> + (gui '(+TextField) 10 "Plain") + (gui '(+TextField) 10 4 "Text Area") + (gui '(+TextField) '("Value 1" "Value 2" "Value 3") "Selection") +</code></pre> + +<p>Finally, without any arguments, the field will appear as a plain HTML text: + +<pre><code> + (gui '(+TextField)) +</code></pre> + +<p>This makes mainly sense in combination with prefix classes like +<code>+Var</code> and <code>+Obj</code>, to manage the contents of these fields, +and achieve special behavior as HTML links or scrollable chart values. + + +<h4><a name="numberFields">Numeric Input Fields</a></h4> + +<p>A <code>+NumField</code> returns a number from its <code>val&gt;</code> +method, and accepts a number for its <code>set&gt;</code> method. It issues an +error message when user input cannot be converted to a number. + +<p>Large numbers are shown with a thousands-separator, as determined by the +current locale. + +<pre><code> +######################################################################## +(app) + +(action + (html 0 "+NumField" "lib.css" NIL + (form NIL + (gui '(+NumField) 10) + (gui '(+JS +Button) "Print value" + '(msg (val&gt; (: home gui 1))) ) + (gui '(+JS +Button) "Set to 123" + '(set&gt; (: home gui 1) 123) ) ) ) ) +######################################################################## +</code></pre> + +<p>A <code>+FixField</code> needs an additional scale factor argument, and +accepts/returns scaled fixpoint numbers. + +<p>The decimal separator is determined by the current locale. + +<pre><code> +######################################################################## +(app) + +(action + (html 0 "+FixField" "lib.css" NIL + (form NIL + (gui '(+FixField) 3 10) + (gui '(+JS +Button) "Print value" + '(msg (format (val&gt; (: home gui 1)) 3)) ) + (gui '(+JS +Button) "Set to 123.456" + '(set&gt; (: home gui 1) 123456) ) ) ) ) +######################################################################## +</code></pre> + + +<h4><a name="timeDateFields">Time &amp; Date</a></h4> + +<p>A <code>+DateField</code> accepts and returns a <code><a +href="refD.html#date">date</a></code> value. + +<pre><code> +######################################################################## +(app) + +(action + (html 0 "+DateField" "lib.css" NIL + (form NIL + (gui '(+DateField) 10) + (gui '(+JS +Button) "Print value" + '(msg (datStr (val&gt; (: home gui 1)))) ) + (gui '(+JS +Button) "Set to \"today\"" + '(set&gt; (: home gui 1) (date)) ) ) ) ) +######################################################################## +</code></pre> + +<p>The format displayed to - and entered by - the user depends on the current +locale (see <code><a href="refD.html#datStr">datStr</a></code> and <code><a +href="refE.html#expDat">expDat</a></code>). You can change it, for example to + +<pre><code> +: (locale "DE" "de") +-> NIL +</code></pre> + +<p>If no locale is set, the format is YYYY-MM-DD. Some pre-defined locales use +patterns like DD.MM.YYYY (DE), YYYY/MM/DD (JP), DD/MM/YYYY (UK), or MM/DD/YYYY +(US). + +<p>An error is issued when user input does not match the current locale's date +format. + +<p>Independent from the locale setting, a <code>+DateField</code> tries to +expand abbreviated input from the user. A small number is taken as that day of +the current month, larger numbers expand to day and month, or to day, month and +year: + +<ul> +<li>"7" gives the 7th of the current month +<li>"031" or "0301" give the 3rd of January of the current year +<li>"311" or "3101" give the 31st of January of the current year +<li>"0311" gives the 3rd of November of the current year +<li>"01023" or "010203" give the first of February in the year 2003 +<li>and so on +</ul> + +<p>Similar is the <code>+TimeField</code>. It accepts and returns a <code><a +href="refT.html#time">time</a></code> value. + +<pre><code> +######################################################################## +(app) + +(action + (html 0 "+TimeField" "lib.css" NIL + (form NIL + (gui '(+TimeField) 8) + (gui '(+JS +Button) "Print value" + '(msg (tim$ (val&gt; (: home gui 1)))) ) + (gui '(+JS +Button) "Set to \"now\"" + '(set&gt; (: home gui 1) (time)) ) ) ) ) +######################################################################## +</code></pre> + +<p>When the field width is '8', like in this example, time is displayed in the +format <code>HH:MM:SS</code>. Another possible value would be '5', causing +<code>+TimeField</code> to display its value as <code>HH:MM</code>. + +<p>An error is issued when user input cannot be converted to a time value. + +<p>The user may omit the colons. If he inputs just a small number, it should be +between '0' and '23', and will be taken as a full hour. '125' expands to +"12:05", '124517' to "12:45:17", and so on. + + +<h4><a name="telFields">Telephone Numbers</a></h4> + +<p>Telephone numbers are represented internally by the country code (without a +leading plus sign or zero) followed by the local phone number (ideally separated +by spaces) and the phone extension (ideally separated by a hyphen). The exact +format of the phone number string is not enforced by the GUI, but further +processing (e.g. database searches) normally uses <code><a +href="refF.html#fold">fold</a></code> for better reproducibility. + +<p>To display a phone number, <code>+TelField</code> replaces the country code +with a single zero if it is the country code of the current locale, or prepends +it with a plus sign if it is a foreign country (see <code><a +href="refT.html#telStr">telStr</a></code>). + +<p>For user input, a plus sign or a double zero is simply dropped, while a +single leading zero is replaced with the current locale's country code (see +<code><a href="refE.html#expTel">expTel</a></code>). + +<pre><code> +######################################################################## +(app) +(locale "DE" "de") + +(action + (html 0 "+TelField" "lib.css" NIL + (form NIL + (gui '(+TelField) 20) + (gui '(+JS +Button) "Print value" + '(msg (val&gt; (: home gui 1))) ) + (gui '(+JS +Button) "Set to \"49 1234 5678-0\"" + '(set&gt; (: home gui 1) "49 1234 5678-0") ) ) ) ) +######################################################################## +</code></pre> + + +<h4><a name="checkboxes">Checkboxes</a></h4> + +<p>A <code>+Checkbox</code> is straightforward. User interaction is restricted +to clicking it on and off. It accepts boolean (<code>NIL</code> or +non-<code>NIL</code>) values, and returns <code>T</code> or <code>NIL</code>. + +<pre><code> +######################################################################## +(app) + +(action + (html 0 "+Checkbox" "lib.css" NIL + (form NIL + (gui '(+Checkbox)) + (gui '(+JS +Button) "Print value" + '(msg (val&gt; (: home gui 1))) ) + (gui '(+JS +Button) "On" + '(set&gt; (: home gui 1) T) ) + (gui '(+JS +Button) "Off" + '(set&gt; (: home gui 1) NIL) ) ) ) ) +######################################################################## +</code></pre> + + +<p><hr> +<h3><a name="fieldPrefix">Field Prefix Classes</a></h3> + +<p>A big part of this framework's power is owed to the combinatorial flexibility +of prefix classes for GUI- and DB-objects. They allow to surgically override +individual methods in the inheritance tree, and can be combined in various ways +to achieve any desired behavior. + +<p>Technically, there is nothing special about prefix classes. They are just +normal classes. They are called "prefix" because they are intended to be written +<i>before</i> other classes in a class's or object's list of superclasses. + +<p>Usually they take their own arguments for their <code>T</code> method from +the list of arguments to the <code>gui</code> function. + + +<h4><a name="initPrefix">Initialization</a></h4> + +<p><code>+Init</code> overrides the <code>init&gt;</code> method for that +component. The <code>init&gt;</code> message is sent to a <code>+gui</code> +component when the page is loaded for the first time (during a GET request). +<code>+Init</code> takes an expression for the initial value of that field. + +<pre><code> + (gui '(+Init +TextField) "This is the initial text" 30) +</code></pre> + +<p>Other classes which automatically give a value to a field are +<code>+Var</code> (linking the field to a variable) and <code>+E/R</code> +(linking the field to a database entity/relation). + +<p><code>+Cue</code> can be used, for example in "mandatory" fields, to give a +hint to the user about what he is supposed to enter. It will display the +argument value, in angular brackets, if and only if the field's value is +<code>NIL</code>, and the <code>val&gt;</code> method will return +<code>NIL</code> despite the fact that this value is displayed. + +<p>Cause an empty field to display "&lt;Please enter some text here&gt;": + +<pre><code> + (gui '(+Cue +TextField) "Please enter some text here" 30) +</code></pre> + + +<h4><a name="ablePrefix">Disabling and Enabling</a></h4> + +<p>An important feature of an interactive GUI is the context-sensitive disabling +and enabling of individual components, or of a whole form. + +<p>The <code>+Able</code> prefix class takes an argument expression, and +disables the component if this expression returns <code>NIL</code>. We saw an +example for its usage already in the <a href="#sqrtButton">square root +button</a> of the calculator example. Or, for illustration purposes, imagine a +button which is supposed to be enabled only after Christmas + +<pre><code> + (gui '(+Able +Button) + '(>= (cdr (date (date))) (12 24)) + "Close this year" + '(endOfYearProcessing) ) +</code></pre> + +<p>or a password field that is disabled as long as somebody is logged in + +<pre><code> + (gui '(+Able +PwField) '(not *Login) 10 "Password") +</code></pre> + +<p>A special case is the <code>+Lock</code> prefix, which permanently and +unconditionally disables a component. It takes no arguments + +<pre><code> + (gui '(+Lock +NumField) 10 "Count") +</code></pre> + +<p>('10' and "Count" are for the <code>+NumField</code>), and creates a +read-only field. + +<p>The whole form can be disabled by calling <code>disable</code> with a +non-<code>NIL</code> argument. This affects all components in this form. Staying +with the above example, we can make the form read-only until Christmas + +<pre><code> + (form NIL + (disable (> (12 24) (cdr (date (date))))) # Disable whole form + (gui ..) + .. ) +</code></pre> + +<p>Even in a completely disabled form, however, it is often necessary to +re-enable certain components, as they are needed for navigation, scrolling, or +other activities which don't affect the contents of the form. This is done by +prefixing these fields with <code>+Rid</code> (i.e. getting "rid" of the lock). + +<pre><code> + (form NIL + (disable (> (12 24) (cdr (date (date))))) + (gui ..) + .. + (gui '(+Rid +Button) ..) # Button is enabled despite the disabled form + .. ) +</code></pre> + + +<h4><a name="formatPrefix">Formatting</a></h4> + +<p>GUI prefix classes allow a fine-grained control of how values are stored in - +and retrieved from - components. As in predefined classes like +<code>+NumField</code> or <code>+DateField</code>, they override the +<code>set&gt;</code> and/or <code>val&gt;</code> methods. + +<p><code>+Set</code> takes an argument function which is called whenever that +field is set to some value. To convert all user input to upper case + +<pre><code> + (gui '(+Set +TextField) uppc 30) +</code></pre> + +<p><code>+Val</code> is the complement to <code>+Set</code>. It takes a function +which is called whenever the field's value is retrieved. To return the square of +a field's value + +<pre><code> + (gui '(+Val +NumField) '((N) (* N N)) 10) +</code></pre> + +<p><code>+Fmt</code> is just a combination of <code>+Set</code> and +<code>+Val</code>, and takes two functional arguments. This example will display +upper case characters, while returning lower case characters internally + +<pre><code> + (gui '(+Fmt +TextField) uppc lowc 30) +</code></pre> + +<p><code>+Map</code> does (like <code>+Fmt</code>) a two-way translation. It +uses a list of cons pairs for a linear lookup, where the CARs represent the +displayed values which are internally mapped to the values in the CDRs. If a +value is not found in this list during <code>set&gt;</code> or +<code>val&gt;</code>, it is passed through unchanged. + +<p>Normally, <code>+Map</code> is used in combination with the combo box +incarnation of text fields (see <a href="#inputFields">Input Fields</a>). This +example displays "One", "Two" and "Three" to the user, but returns a number 1, 2 +or 3 internally + +<pre><code> +######################################################################## +(app) + +(action + (html 0 "+Map" "lib.css" NIL + (form NIL + (gui '(+Map +TextField) + '(("One" . 1) ("Two" . 2) ("Three" . 3)) + '("One" "Two" "Three") ) + (gui '(+Button) "Print" + '(msg (val> (field -1))) ) ) ) ) +######################################################################## +</code></pre> + + +<h4><a name="sideEffects">Side Effects</a></h4> + +<p>Whenever a button is pressed in the GUI, any changes caused by +<code>action</code> in the current environment (e.g. the database or application +state) need to be reflected in the corresponding GUI fields. For that, the +<code>upd&gt;</code> message is sent to all components. Each component then +takes appropriate measures (e.g. refresh from database objects, load values from +variables, or calculate a new value) to update its value. + +<p>While the <code>upd&gt;</code> method is mainly used internally, it can be +overridden in existing classes via the <code>+Upd</code> prefix class. Let's +print updated values to standard error + +<pre><code> +######################################################################## +(app) +(default *Number 0) + +(action + (html 0 "+Upd" "lib.css" NIL + (form NIL + (gui '(+Upd +Var +NumField) + '(prog (extra) (msg *Number)) + '*Number 8 ) + (gui '(+JS +Button) "Increment" + '(inc '*Number) ) ) ) ) +######################################################################## +</code></pre> + + +<h4><a name="validPrefix">Validation</a></h4> + +<p>To allow automatic validation of user input, the <code>chk&gt;</code> message +is sent to all components at appropriate times. The corresponding method should +return <code>NIL</code> if the value is all right, or a string describing the +error otherwise. + +<p>Many of the built-in classes have a <code>chk&gt;</code> method. The +<code>+NumField</code> class checks for legal numeric input, or the +<code>+DateField</code> for a valid calendar date. + +<p>An on-the-fly check can be implemented with the <code>+Chk</code> prefix +class. The following code only accepts numbers not bigger than 9: The +<code>or</code> expression first delegates the check to the main +<code>+NumField</code> class, and - if it does not give an error - returns an +error string when the current value is greater than 9. + +<pre><code> +######################################################################## +(app) + +(action + (html 0 "+Chk" "lib.css" NIL + (form NIL + (gui '(+Chk +NumField) + '(or + (extra) + (and (&gt; (val&gt; This) 9) "Number too big") ) + 12 ) + (gui '(+JS +Button) "Print" + '(msg (val&gt; (field -1))) ) ) ) ) +######################################################################## +</code></pre> + +<p>A more direct kind of validation is built-in via the <code>+Limit</code> +class. It controls the <code>maxlength</code> attribute of the generated HTML +input field component. Thus, it is impossible to type to more characters than +allowed into the field. + +<pre><code> +######################################################################## +(app) + +(action + (html 0 "+Limit" "lib.css" NIL + (form NIL + (gui '(+Limit +TextField) 4 8) + (gui '(+JS +Button) "Print" + '(msg (val&gt; (field -1))) ) ) ) ) +######################################################################## +</code></pre> + + +<h4><a name="linkage">Data Linkage</a></h4> + +<p>Although <code>set&gt;</code> and <code>val&gt;</code> are the official +methods to get a value in and out of a GUI component, they are not very often +used explicitly. Instead, components are directly linked to internal Lisp data +structures, which are usually either variables or database objects. + +<p>The <code>+Var</code> prefix class takes a variable (described as the +<code>var</code> data type - either a symbol or a cell - in the <a +href="ref.html#fun">Function Reference</a>). In the following example, we +initialize a global variable with the value "abc", and let a +<code>+TextField</code> operate on it. The "Print" button can be used to display +its current value. + +<pre><code> +######################################################################## +(app) + +(setq *TextVariable "abc") + +(action + (html 0 "+Var" "lib.css" NIL + (form NIL + (gui '(+Var +TextField) '*TextVariable 8) + (gui '(+JS +Button) "Print" + '(msg *TextVariable) ) ) ) ) +######################################################################## +</code></pre> + +<p><code>+E/R</code> takes an entity/relation specification. This is a cell, +with a relation in its CAR (e.g. <code>nm</code>, for an object's name), and an +expression in its CDR (typically <code>(: home obj)</code>, the object stored in +the <code>obj</code> property of the current form). + +<p>For an isolated, simple example, we create a temporary database, and access +the <code>nr</code> and <code>nm</code> properties of an object stored in a +global variable <code>*Obj</code>. + +<pre><code> +######################################################################## +(when (app) # On start of session + (class +Tst +Entity) # Define data model + (rel nr (+Number)) # with a number + (rel nm (+String)) # and a string + (pool (tmp "db")) # Create temporary DB + (setq *Obj # and a single object + (new! '(+Tst) 'nr 1 'nm "New Object") ) ) + +(action + (html 0 "+E/R" "lib.css" NIL + (form NIL + (gui '(+E/R +NumField) '(nr . *Obj) 8) # Linkage to 'nr' + (gui '(+E/R +TextField) '(nm . *Obj) 20) # Linkage to 'nm' + (gui '(+JS +Button) "Show" # Show the object + '(out 2 (show *Obj)) ) ) ) ) # on standard error +######################################################################## +</code></pre> + + +<p><hr> +<h3><a name="buttons">Buttons</a></h3> + +<p>Buttons are, as explained in <a href="#ctlFlow">Control Flow</a>, the only +way (via POST requests) for an application to communicate with the server. + +<p>Basically, a <code>+Button</code> takes + +<ul> +<li>a label, which may be either a string or the name of an image file +<li>an optional alternative label, shown when the button is disabled +<li>and an executable expression. +</ul> + +<p>Here is a minimal button, with just a label and an expression: + +<pre><code> + (gui '(+Button) "Label" '(doSomething)) +</code></pre> + +<p>And this is a button displaying different labels, depending on the state: + +<pre><code> + (gui '(+Button) "Enabled" "Disabled" '(doSomething)) +</code></pre> + +<p>To show an image instead of plain text, the label(s) must be preceeded by the +<code>T</code> symbol: + +<pre><code> + (gui '(+Button) T "img/enabled.png" "img/disabled.png" '(doSomething)) +</code></pre> + +<p>The expression will be executed during <code>action</code> handling (see <a +href="#actionForms">Action Forms</a>), when this button was pressed. + +<p>Like other components, buttons can be extended and combined with prefix +classes, and a variety of predefined classes and class combinations are +available. + + +<h4><a name="dialogButtons">Dialog Buttons</a></h4> + +<p>Buttons are essential for the handling of <a href="#dialogs">alerts and +dialogs</a>. Besides buttons for normal functions, like <a +href="#scrolling">scrolling</a> in charts or other <a href="#sideEffects">side +effects</a>, special buttons exist which can <i>close</i> an alert or dialog in +addition to doing their principal job. + +<p>Such buttons are usually subclasses of <code>+Close</code>, and most of them +can be called easily with ready-made functions like <code>closeButton</code>, +<code>cancelButton</code>, <code>yesButton</code> or <code>noButton</code>. We +saw a few examples in <a href="#dialogs">Alerts and Dialogs</a>. + + +<h4><a name="jsButtons">Active JavaScript</a></h4> + +<p>When a button inherits from the <code>+JS</code> class (and JavaScript is +enabled in the browser), that button will possibly show a much faster response +in its action. + +<p>The reason is that the activation of a <code>+JS</code> button will - instead +of doing a normal POST - first try to send only the contents of all GUI +components via an XMLHttpRequest to the server, and receive the updated values +in response. This avoids the flicker caused by reloading and rendering of the +whole page, is much faster, and also does not jump to the beginning of the page +if it is larger than the browser window. The effect is especially noticeable +while scrolling in charts. + +<p>Only if this fails, for example because an error message was issued, or a +dialog popped up, it will fall back, and the form will be POSTed in the normal +way. + +<p>Thus it makes no sense to use the <code>+JS</code> prefix for buttons that +cause a change of the HTML code, open a dialog, or jump to another page. In such +cases, overall performance will even be worse, because the XMLHttpRequest is +tried first (but in vain). + +<p>When JavaScript is disabled int the browser, the XMLHttpRequest will not be +tried at all. The form will be fully usable, though, with identical +functionality and behavior, just a bit slower and not so smooth. + + +<p><hr> +<h2><a name="minApp">A Minimal Complete Application</a></h2> + +<p>The PicoLisp release includes in the "app/" directory a minimal, yet complete +reference application. This application is typical, in the sense that it +implements many of the techniques described in this document, and it can be +easily modified and extended. In fact, we use it as templates for our own +production application development. + +<p>It is a kind of simplified ERP system, containing customers/suppliers, +products (items), orders, and other data. The order input form performs live +updates of customer and product selections, price, inventory and totals +calculations, and generates on-the-fly PDF documents. Fine-grained access +permissions are controlled via users, roles and permissions. It comes localized +in four languages (English, German, Russian and Japanese), with a some initial +data and two sample reports. + + +<p><hr> +<h3><a name="getStarted">Getting Started</a></h3> + +<p>As ever, you may start up the application in debugging mode + +<pre><code> +$ ./dbg app/main.l -main -go +</code></pre> + +<p>or in (non-debug) production mode + +<pre><code> +$ ./p app/main.l -main -go -wait +</code></pre> + +<p>and go to '<code><a +href="http://localhost:8080">http://localhost:8080</a></code>' with your +browser. You can login as user "admin", with password "admin". The demo data +contain several other users, but those are more restricted in their role +permissions. + +<p>Another possibility is to try the online version of this application at <a +href="http://app.7fach.de">app.7fach.de</a>. + + +<h4><a name="localization">Localization</a></h4> + +<p>Before or after you logged in, you can select another language, and click on +the "Change" button. This will effect all GUI components (though not text from +the database), and also the numeric, date and telephone number formats. + + +<h4><a name="navigation">Navigation</a></h4> + +<p>The navigation menu on the left side shows two items "Home" and "logout", and +three submenus "Data", "Report" and "System". + +<p>Both "Home" and "logout" bring you back to the initial login form. Use +"logout" if you want to switch to another user (say, for another set of +permissions), and - more important - before you close your browser, to release +possible locks and process resources on the server. + +<p>The "Data" submenu gives access to application specific data entry and +maintenance: Orders, product items, customers and suppliers. The "Report" +submenu contains two simple inventory and sales reports. And the "System" +submenu leads to role and user administration. + +<p>You can open and close each submenu individually. Keeping more than one +submenu open at a time lets you switch rapidly between different parts of the +application. + +<p>The currently active menu item is indicated by a highlighted list style (no +matter whether you arrived at this page directly via the menu or by clicking on +a link somewhere else). + + +<h4><a name="choosing">Choosing Objects</a></h4> + +<p>Each item in the "Data" or "System" submenu opens a search dialog for that +class of entities. You can specify a search pattern, press the top right +"Search" button (or just ENTER), and scroll through the list of results. + +<p>While the "Role" and "User" entities present simple dialogs (searching just +by name), other entities can be searched by a variety of criteria. In those +cases, a "Reset" button clears the contents of the whole dialog. A new object +can be created with bottom right "New" button. + +<p>In any case, the first column will contain either a "@"-link (to jump to that +object) or a "@"-button (to insert a reference to that object into the current +form). + +<p>By default, the search will list all database objects with an attribute value +greater than or equal to the search criterion. The comparison is done +arithmetically for numbers, and alphabetically (case sensitive!) for text. This +means, if you type "Free" in the "City" field of the "Customer/Supplier" dialog, +the value of "Freetown" will be matched. On the other hand, an entry of "free" +or "town" will yield no hits. + +<p>Some search fields, however, show a different behavior depending on the +application: + +<ul> +<li>The names of persons, companies or products allow a tolerant search, +matching either a slightly misspelled name ("Mühler" instead of "Miller") or a +substring ("Oaks" will match "Seven Oaks Ltd."). + +<li>The search field may specify an upper instead of a lower limit, resulting in +a search for database objects with an attribute value less than or equal to the +search criterion. This is useful, for example in the "Order" dialog, to list +orders according to their number or date, by starting with the newest then and +going backwards. + +</ul> + +<p>Using the bottom left scroll buttons, you can scroll through the result list +without limit. Clicking on a link will bring up the corresponding object. Be +careful here to select the right column: Some dialogs (those for "Item" and +"Order") also provide links for related entities (e.g. "Supplier"). + + +<h4><a name="editing">Editing</a></h4> + +<p>A database object is usually displayed in its own individual form, which is +determined by its entity class. + +<p>The basic layout should be consistent for all classes: Below the heading +(which is usually the same as the invoking menu item) is the object's identifier +(name, number, etc.), and then a row with an "Edit" button on the left, and +"Delete" button, a "Select" button and two navigation links on the right side. + +<p>The form is brought up initially in read-only mode. This is necessary to +prevent more than one user from modifying an object at the same time (and +contrary to the previous PicoLisp Java frameworks, where this was not a problem +because all changes were immediately reflected in the GUIs of other users). + +<p>So if you want to modify an object, you have to gain exclusive access by +clicking on the "Edit" button. The form will be enabled, and the "Edit" button +changes to "Done". Should any other user already have reserved this object, you +will see a message telling his name and process ID. + +<p>An exception to this are objects that were just created with "New". They will +automatically be reserved for you, and the "Edit" button will show up as "Done". + +<p>The "Delete" button pops up an alert, asking for confirmation. If the object +is indeed deleted, this button changes to "Restore" and allows to undelete the +object. Note that objects are never completely deleted from the database as long +as there are any references from other objects. When a "deleted" object is +shown, its identifier appears in square brackets. + +<p>The "Select" button (re-)displays the search dialog for this class of +entities. The search criteria are preserved between invocations of each dialog, +so that you can conveniently browse objects in this context. + +<p>The navigation links, pointing left and right, serve a similar purpose. They +let you step sequentially through all objects of this class, in the order of the +identifier's index. + +<p>Other buttons, depending on the entity, are usually arranged at the bottom of +the form. The bottom rightmost one should always be another "Edit" / "Done" +button. + +<p>As we said in the chapter on <a href="#scrolling">Scrolling</a>, any button +in the form will save changes to the underlying data model. As a special case, +however, the "Done" button releases the object and reverts to "Edit". Besides +this, the edit mode will also cease as soon as another object is displayed, be +it by clicking on an object link (the pencil icon), the top right navigation +links, or a link in a search dialog. + + +<h4><a name="btnLinks">Buttons vs. Links</a></h4> + +<p>The only way to interact with a HTTP-based application server is to click +either on a HTML link, or on a submit button (see also <a +href="#ctlFlow">Control Flow</a>). It is essential to understand the different +effects of such a click on data entered or modified in the current form. + +<ul> +<li>A click on a link will leave or reload the page. Changes are discarded. +<li>A click on a button will commit changes, and perform the associated action. +</ul> + +<p>For that reason the layout design should clearly differentiate between links +and buttons. Image buttons are not a good idea when in other places images are +used for links. The standard button components should be preferred; they are +usually rendered by the browser in a non-ambiguous three-dimensional look and +feel. + +<p>Note that if JavaScript is enabled in the browser, changes will be +automatically committed to the server. + +<p>The enabled or disabled state of a button is an integral part of the +application logic. It must be indicated to the user with appropriate styles. + + +<p><hr> +<h3><a name="dataModel">The Data Model</a></h3> + +<p>The data model for this mini application consists of only six entity classes +(see the E/R diagram at the beginning of "app/er.l"): + +<ul> +<li>The three main entities are <code>+CuSu</code> (Customer/Supplier), +<code>+Item</code> (Product Item) and <code>+Ord</code> (Order). + +<li>A <code>+Pos</code> object is a single position in an order. + +<li><code>+Role</code> and <code>+User</code> objects are needed for +authentication and authorization. + +</ul> + +<p>The classes <code>+Role</code> and <code>+User</code> are defined in +"lib/adm.l". A <code>+Role</code> has a name, a list of permissions, and a list +of users assigned to this role. A <code>+User</code> has a name, a password and +a role. + +<p>In "app/er.l", the <code>+Role</code> class is extended to define an +<code>url&gt;</code> method for it. Any object whose class has such a method is +able to display itself in the GUI. In this case, the file "app/role.l" will be +loaded - with the global variable <code>*ID</code> pointing to it - whenever an +HTML link to this role object is activated. + +<p>The <code>+User</code> class is also extended. In addition to the login name, +a full name, telephone number and email address is declared. And, of course, the +ubiquitous <code>url&gt;</code> method. + +<p>The application logic is centered around orders. An order has a number, a +date, a customer (an instance of <code>+CuSu</code>) and a list of positions +(<code>+Pos</code> objects). The <code>sum&gt;</code> method calculates the +total amount of this order. + +<p>Each position has an <code>+Item</code> object, a price and a quantity. The +price in the position overrides the default price from the item. + +<p>Each item has a number, a description, a supplier (also an instance of +<code>+CuSu</code>), an inventory count (the number of these items that were +counted at the last inventory taking), and a price. The <code>cnt&gt;</code> +method calculates the current stock of this item as the difference of the +inventory and the sold item counts. + +<p>The call to <code>dbs</code> at the end of "app/er.l" configures the physical +database storage. Each of the supplied lists has a number in its CAR which +determines the block size as (64 &lt;&lt; N) of the corresponding database file. +The CDR says that the instances of this class (if the element is a class symbol) +or the tree nodes (if the element is a list of a class symbol and a property +name) are to be placed into that file. This allows for some optimizations in the +database layout. + + +<p><hr> +<h3><a name="usage">Usage</a></h3> + +<p>When you are connected to the application (see <a href="#getStarted">Getting +Started</a>) you might try to do some "real" work with it. Via the "Data" menu +(see <a href="#navigation">Navigation</a>) you can create or modify customers, +suppliers, items and orders, and produce simple overviews via the "Report" menu. + + +<h4><a name="cuSu">Customer/Supplier</a></h4> + +<p align=right>Source in "app/cusu.l" + +<p>The Customer/Supplier search dialog (<code>choCuSu</code> in "app/gui.l") +supports a lot of search criteria. These become necessary when the database +contains a large number of customers, and can filter by zip, by phone number +prefixes, and so on. + +<p>In addition to the basic layout (see <a href="#editing">Editing</a>), the +form is divided into four separate tabs. Splitting a form into several tabs +helps to reduce traffic, with possibly better GUI response. In this case, four +tabs are perhaps overkill, but ok for demonstration purposes, and they leave +room for extensions. + +<p>Be aware that when data were modified in one of the tabs, the "Done" button +has to be pressed before another tab is clicked, because tabs are implemented as +HTML links (see <a href="#btnLinks">Buttons vs. Links</a>). + +<p>New customers or suppliers will automatically be assigned the next free +number. You can enter another number, but an error will result if you try to use +an existing number. The "Name" field is mandatory, you need to overwrite the +"&lt;Name&gt;" clue. + +<p>Phone and fax numbers in the "Contact" tab must be entered in the correct +format, depending on the locale (see <a href="#telFields">Telephone +Numbers</a>). + +<p>The "Memo" tab contains a single text area. It is no problem to use it for +large pieces of text, as it gets stored in a database blob internally. + + +<h4><a name="item">Item</a></h4> + +<p align=right>Source in "app/item.l" + +<p>Items also have a unique number, and a mandatory "Description" field. + +<p>To assign a supplier, click on the "+" button. The Customer/Supplier search +dialog will appear, and you can pick the desired supplier with the "@" button in +the first column. Alternatively, if you are sure to know the exact spelling of +the supplier's name, you can also enter it directly into the text field. + +<p>In the search dialog you may also click on a link, for example to inspect a +possible supplier, and then return to the search dialog with the browser's back +button. The "Edit" mode will then be lost, however, as another object has been +visited (this is described in the last part of <a href="#editing">Editing</a>). + +<p>You can enter an inventory count, the number of items currently in stock. The +following field will automatically reflect the remaining pieces after some of +these items were sold (i.e. referenced in order positions). It cannot be changed +manually. + +<p>The price should be entered with the decimal separator according to the +current locale. It will be formatted with two places after the decimal +separator. + +<p>The "Memo" is for an arbitrary info text, like in <a +href="#cuSu">Customer/Supplier</a> above, stored in a database blob. + +<p>Finally, a JPEG picture can be stored in a blob for this item. Choose a file +with the browser's file select control, and click on the "Install" button. The +picture will appear at the bottom of the page, and the "Install" button changes +to "Uninstall", allowing the picture's removal. + + +<h4><a name="order">Order</a></h4> + +<p align=right>Source in "app/ord.l" + +<p>Oders are identified by number and date. + +<p>The number must be unique. It is assigned when the order is created, and +cannot be changed for compliance reasons. + +<p>The date is initialized to "today" for a newly created order, but may be +changed manually. The date format depends on the locale. It is YYYY-MM-DD (ISO) +by default, DD.MM.YYYY in the German and YYYY/MM/DD in the Japanese locale. As +described in <a href="#timeDateFields">Time &amp; Date</a>, this field allows +input shortcuts, e.g. just enter the day to get the full date in the current +month. + +<p>To assign a customer to this order, click on the "+" button. The +Customer/Supplier search dialog will appear, and you can pick the desired +customer with the "@" button in the first column (or enter the name directly +into the text field), just as described above for <a href="#item">Item</a>s. + +<p>Now enter order the positions: Choose an item with the "+" button. The +"Price" field will be preset with the item's default price, you may change it +manually. Then enter a quantity, and click a button (typically the "+" button to +select the next item, or a scroll button go down in the chart). The form will be +automatically recalculated to show the total prices for this position and the +whole order. + +<p>Instead of the "+" or scroll buttons, as recommended above, you could of +course also press the "Done" button to commit changes. This is all right, but +has the disadvantage that the button must be pressed a second time (now "Edit") +if you want to continue with the entry of more positions. + +<p>The "x" button at the right of each position deletes that position without +further confirmation. It has to be used with care! + +<p>The "^" button is a "bubble" button. It exchanges a row with the row above it. +Therefore, it can be used to rearrange all items in a chart, by "bubbling" them +to their desired positions. + +<p>The "PDF-Print" button generates and displays a PDF document for this order. +The browser should be configured to display downloaded PDF documents in an +appropriate viewer. The source for the postscript generating method is in +"app/lib.l". It produces one or several A4 sized pages, depending on the number +of positions. + + +<h4><a name="reports">Reports</a></h4> + +<p align=right>Sources in "app/inventory.l and "app/sales.l" + +<p>The two reports ("Inventory" and "Sales") come up with a few search fields +and a "Show" button. + +<p>If no search criteria are entered, the "Show" button will produce a listing +of the relevant part of the whole database. This may take a long time and cause +a heavy load on the browser if the database is large. + +<p>So in the normal case, you will limit the domain by stating a range of item +numbers, a description pattern, and/or a supplier for the inventory report, or a +range of order dates and/or a customer for the sales report. If a value in a +range specification is omitted, the range is considered open in that direction. + +<p>At the end of each report appears a "CSV" link. It downloads a file with the +TAB-separated values generated by this report. + +</body> +</html> diff --git a/doc/apply b/doc/apply @@ -0,0 +1,30 @@ + Apply/Mapping + + + ApplyBody + | + V + +-----+-----+ + | / | | | + +-----+--+--+ + | + +-----------+ + | + | +--------------------------+ + | | | + | +--------------------------+ | + | | | | | + | V V | | + | +-----+-----+ +-----+--+--+ +-----+--+--+ + | | | | / | | | | | | | | | | | <-- ApplyArgs + | +--+--+-----+ +--+--+-----+ +--+--+-----+ + | | | | + | V V V + | +-----+-----+ +-----+-----+ +-----+-----+ + +------> | | | ---+---> | | | ---+---> | | | / | + +--+--+-----+ +--+--+-----+ +--+--+-----+ + | | | + V V V + +-----+-----+ +-----+-----+ +-----+-----+ + | 1 | / | | 2 | / | | 3 | / | + +-----+-----+ +-----+-----+ +-----+-----+ diff --git a/doc/db b/doc/db @@ -0,0 +1,91 @@ + Max DB-Size: 7 digits -> 2**42 (4 Tera) Blocks + Blocksize 64 -> (2**48 Bytes (256 TB)) + + Tree + NIL -> (val *DB) + {x} -> (val '{x}) + (var . {x}) -> (get '{x} 'var) + (var . +Cls) -> (get *DB '+Cls 'var) + (var +Cls . {x}) -> (get '{x} '+Cls 'var) + + B-Tree root: + (cnt . node) + + B-Tree node: + (less (key more . value) (key more . value) ..) + + Per node + <Link> BEG EXTERN <6> .. NIX + 6+1+1+6+1 = 15 + + Per key + BEG TRANSIENT <key> EXTERN <7> DOT EXTERN <7> + 1+1+<key>+1+6+1+1+7 = 18 + <key> + + + Key Arguments for DB- and Pilog-functions: + + 123, {abc} -> (123) (123 . T) + T -> All + "abc" -> ("abc") ("abcT" . T) + + (a b) -> (a b) (a b . T) + ((a 1) b 2) -> (a 1) (b 2 . T) + + (a . b) -> (a) (b . T) + (b . a) -> (b . T) (a) + + + loaded/dirty/deleted + + | | | | + | (1) | (2) | (3) | + | | | | + ---------+-----------------+-----------------+-----------------+ + | load | load | empty | + NIL | -> loaded | -> dirty | -> deleted | + | | | | + ---------+-----------------+-----------------+-----------------+ + | | | empty | + loaded | | -> dirty | -> deleted | + | | | | + ---------+-----------------+-----------------+-----------------+ + | | | empty | + dirty | | | -> deleted | + | | | | + ---------+-----------------+-----------------+-----------------+ + | | | | + deleted | | | | + | | | | + + + | | | + | commit | rollback | + | | | + -------------+-----------------+-----------------+ + | | | + NIL | | | + | | | + -------------+-----------------+-----------------+ + | | empty | + (1) loaded | | -> NIL | + | | | + -------------+-----------------+-----------------+ + | save | empty | + (2) dirty | -> loaded | -> NIL | + | | | + -------------+-----------------+-----------------+ + | empty | empty | + (3) deleted | -> NIL | -> NIL | + | | | + + + + +-----+-----+ + | V1 | | | + +-----+--+--+ + | + V + +-----+-----+ +-----+-----+ + | P1 | ---+---> | N | ---+---> @@ + +-----+-----+ +-----+-----+ diff --git a/doc/doc.css b/doc/doc.css @@ -0,0 +1,12 @@ +/* 19may07abu + * (c) Software Lab. Alexander Burger + */ + +body { + margin-left: 80px; + margin-right: 60px +} + +code { + color: rgb(0%,40%,0%); +} diff --git a/doc/family.l b/doc/family.l @@ -0,0 +1,242 @@ +# 04feb10abu +# (c) Software Lab. Alexander Burger + +(load "lib/http.l" "lib/xhtml.l" "lib/form.l" "lib/ps.l") + +### DB ### +(class +Person +Entity) +(rel nm (+Need +Sn +Idx +String)) # Name +(rel pa (+Joint) kids (+Man)) # Father +(rel ma (+Joint) kids (+Woman)) # Mother +(rel mate (+Joint) mate (+Person)) # Partner +(rel job (+Ref +String)) # Occupation +(rel dat (+Ref +Date)) # born +(rel fin (+Ref +Date)) # died +(rel txt (+String)) # Info + +(dm url> (Tab) + (list "@person" '*ID This) ) + + +(class +Man +Person) +(rel kids (+List +Joint) pa (+Person)) # Children + +(class +Woman +Person) +(rel kids (+List +Joint) ma (+Person)) # Children + +(dbs + (0) # (1 . 64) + (2 +Person) # (2 . 256) + (3 (+Person nm)) # (3 . 512) + (3 (+Person job dat fin)) ) # (4 . 512) + + +### GUI ### +(de choPerson (Dst) + (diaform '(Dst) + (<grid> "--.-.-." + "Name" (gui 'nm '(+Focus +Var +TextField) '*PrsNm 20) + "Occupation" (gui 'job '(+Var +TextField) '*PrsJob 20) + "born" (prog + (gui 'dat1 '(+Var +DateField) '*PrsDat1 10) + (gui 'dat2 '(+Var +DateField) '*PrsDat2 10) ) + (searchButton '(init> (: home query))) + "Father" (gui 'pa '(+Var +TextField) '*PrsPa 20) + "Mother" (gui 'ma '(+Var +TextField) '*PrsMa 20) + "Partner" (gui 'mate '(+Var +TextField) '*PrsMate 20) + (resetButton '(nm pa ma mate job dat1 dat2 query)) ) + (gui 'query '(+QueryChart) (cho) + '(goal + (quote + @Nm *PrsNm + @Pa *PrsPa + @Ma *PrsMa + @Mate *PrsMate + @Job *PrsJob + @Dat (and (or *PrsDat1 *PrsDat2) (cons *PrsDat1 (or *PrsDat2 T))) + (select (@@) + ((nm +Person @Nm) + (nm +Person @Pa kids) + (nm +Person @Ma kids) + (nm +Person @Mate mate) + (job +Person @Job) + (dat +Person @Dat) ) + (tolr @Nm @@ nm) + (tolr @Pa @@ pa nm) + (tolr @Ma @@ ma nm) + (tolr @Mate @@ mate nm) + (head @Job @@ job) + (range @Dat @@ dat) ) ) ) + 7 + '((This) (list This This (: pa) (: ma) (: mate) (: job) (: dat))) ) + (<table> 'chart NIL + '((btn) (NIL "Name") (NIL "Father") (NIL "Mother") (NIL "Partner") (NIL "Occupation") (NIL "born")) + (do (cho) + (<row> (alternating) + (gui 1 '(+DstButton) Dst) + (gui 2 '(+ObjView +TextField) '(: nm)) + (gui 3 '(+ObjView +TextField) '(: nm)) + (gui 4 '(+ObjView +TextField) '(: nm)) + (gui 5 '(+ObjView +TextField) '(: nm)) + (gui 6 '(+TextField)) + (gui 7 '(+DateField)) ) ) ) + (<spread> + (scroll (cho)) + (<nbsp> 4) + (prin "Man") + (newButton T Dst '(+Man) 'nm *PrsNm) + (<nbsp>) + (prin "Woman") + (newButton T Dst '(+Woman) 'nm *PrsNm) + (<nbsp> 4) + (cancelButton) ) ) ) + +# Person HTML Page +(de person () + (app) + (action + (html 0 (get (default *ID (val *DB)) 'nm) "lib.css" NIL + (form NIL + (<h2> NIL (<id> (: nm))) + (panel T "Person '@1'" T '(choPerson) 'nm '+Person) + (<p> NIL + (gui '(+E/R +TextField) '(nm : home obj) 40 "Name") + (gui '(+ClassField) '(: home obj) '(("Male" +Man) ("Female" +Woman))) ) + (<grid> 5 + "Occupation" (gui '(+E/R +TextField) '(job : home obj) 20) + "Father" (gui '(+ChoButton) '(choPerson (field 1))) + (gui '(+E/R +Obj +TextField) '(pa : home obj) '(nm +Man) 30) + "born" (gui '(+E/R +DateField) '(dat : home obj) 10) + "Mother" (gui '(+ChoButton) '(choPerson (field 1))) + (gui '(+E/R +Obj +TextField) '(ma : home obj) '(nm +Woman) 30) + "died" (gui '(+E/R +DateField) '(fin : home obj) 10) + "Partner" (gui '(+ChoButton) '(choPerson (field 1))) + (gui '(+E/R +Obj +TextField) '(mate : home obj) '(nm +Person) 30) ) + (gui '(+E/R +Chart) '(kids : home obj) 5 + '((This) (list NIL This (: dat) (: pa) (: ma))) + cadr ) + (<table> NIL NIL + '(NIL (NIL "Children") (NIL "born") (NIL "Father") (NIL "Mother")) + (do 4 + (<row> NIL + (gui 1 '(+ChoButton) '(choPerson (field 1))) + (gui 2 '(+Obj +TextField) '(nm +Person) 20) + (gui 3 '(+E/R +DateField) '(dat curr) 10) + (gui 4 '(+ObjView +TextField) '(: nm) 20) + (gui 5 '(+ObjView +TextField) '(: nm) 20) ) ) + (<row> NIL NIL (scroll 4)) ) + (----) + (gui '(+E/R +TextField) '(txt : home obj) 40 4) + (gui '(+Rid +Button) "Contemporaries" + '(url "@contemporaries" (: home obj)) ) + (gui '(+Rid +Button) "Tree View" + '(url "@treeReport" (: home obj)) ) + (editButton T) ) ) ) ) + + +### Reports ### +# Show all contemporaries of a person +(de contemporaries (*ID) + (action + (html 0 "Contemporaries" "lib.css" NIL + (form NIL + (<h3> NIL (<id> "Contemporaries of " (: nm))) + (ifn (: obj dat) + (<h3> NIL (ht:Prin "No birth date for " (: obj nm))) + (gui '(+QueryChart) 12 + '(goal + (quote + @Obj (: home obj) + @Dat (: home obj dat) + @Beg (- (: home obj dat) 36525) + @Fin (or (: home obj fin) (+ (: home obj dat) 36525)) + (db dat +Person (@Beg . @Fin) @@) + (different @@ @Obj) + (@ >= (get (-> @@) 'fin) (-> @Dat)) + (@ <= (get (-> @@) 'dat) (-> @Fin)) ) ) + 7 + '((This) + (list This (: job) (: dat) (: fin) (: pa) (: ma) (: mate)) ) ) + (<table> NIL (pack (datStr (: obj dat)) " - " (datStr (: obj fin))) + (quote + (NIL "Name") (NIL "Occupation") (NIL "born") (NIL "died") + (NIL "Father") (NIL "Mother") (NIL "Partner") ) + (do 12 + (<row> NIL + (gui 1 '(+ObjView +TextField) '(: nm)) + (gui 2 '(+TextField)) + (gui 3 '(+DateField)) + (gui 4 '(+DateField)) + (gui 5 '(+ObjView +TextField) '(: nm)) + (gui 6 '(+ObjView +TextField) '(: nm)) + (gui 7 '(+ObjView +TextField) '(: nm)) ) ) ) + (scroll 12) + (----) + (gui '(+Rid +Button) "Textfile" + '(let Txt (tmp "Contemporaries.txt") + (out Txt (txt> (chart))) + (url Txt) ) ) + (gui '(+Rid +Button) "PDF" + '(psOut NIL "Contemporaries" + (out (tmp "Contemporaries.txt") + (txt> (chart)) ) + (in (tmp "Contemporaries.txt") + (let (Page 1 Fmt (200 120 50 50 120 120 120) Ttl (line T)) + (a4L) + (font (7 . "Helvetica")) + (indent 30 10) + (down 12) + (font 9 (ps Ttl)) + (down 12) + (table Fmt + "Name" "Occupation" "born" "died" "Father" "Mother" "Partner" ) + (down 6) + (pages 560 + (page T) + (down 12) + (ps (pack Ttl ", Page " (inc 'Page))) + (down 12) ) + (until (eof) + (let L (split (line) "^I") + (down 8) + (table Fmt + (font "Helvetica-Bold" (ps (head 50 (car L)))) + (ps (head 30 (cadr L))) + (ps (get L 3)) + (ps (get L 4)) + (ps (head 30 (get L 5))) + (ps (head 30 (get L 6))) + (ps (head 30 (get L 7))) ) + (down 4) ) ) ) ) + (page) ) ) ) ) ) ) ) + +# Tree display of a person's descendants +(de treeReport (This) + (html 0 "Family Tree View" "lib.css" NIL + (<h3> NIL "Family Tree View") + (<ul> NIL + (recur (This) + (when (try 'url> This 1) + (<li> NIL + (<href> (: nm) (mkUrl @)) + (when (try 'url> (: mate) 1) + (prin " -- ") + (<href> (: mate nm) (mkUrl @)) ) ) + (when (: kids) + (<ul> NIL (mapc recurse (: kids))) ) ) ) ) ) ) + +### RUN ### +(de main () + (pool "doc/family/" *Dbs) + (unless (val *DB) + (put> + (set *DB (request '(+Man) 'nm "Adam")) + 'mate + (request '(+Woman) 'nm "Eve") ) + (commit) ) ) + +(de go () + (rollback) + (server 8080 "@person") ) + +# vi:et:ts=3:sw=3 diff --git a/doc/family/1 b/doc/family/1 Binary files differ. diff --git a/doc/family/2 b/doc/family/2 Binary files differ. diff --git a/doc/family/3 b/doc/family/3 Binary files differ. diff --git a/doc/family/4 b/doc/family/4 Binary files differ. diff --git a/doc/faq.html b/doc/faq.html @@ -0,0 +1,664 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/1998/REC-html40-19980424/loose.dtd"> +<html lang="en"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> +<title>PicoLisp FAQ</title> +<link rel="stylesheet" href="doc.css" type="text/css"> +</head> +<body> +<a href="mailto:abu@software-lab.de">abu@software-lab.de</a> + +<p align=right> +<i>Monk: "If I have nothing in my mind, what shall I do?"</i><br> +<i>Joshu: "Throw it out."</i><br> +<i>Monk: "But if there is nothing, how can I throw it out?"</i><br> +<i>Joshu: "Well, then carry it out."</i><br> +<i>(Zen koan)</i><br> + +<h1>PicoLisp Frequently Asked Questions</h1> + +<p align=right>(c) Software Lab. Alexander Burger + +<p><ul> +<li><a href="#yet">Why did you write yet another Lisp?</a> +<li><a href="#who">Who can use PicoLisp?</a> +<li><a href="#advantages">What are the advantages over other Lisp systems?</a> +<li><a href="#performance">How is the performance compared to other Lisp systems?</a> +<li><a href="#interpreted">What means "interpreted"?</a> +<li><a href="#compiler">Is there (or will be in the future) a compiler available?</a> +<li><a href="#portable">Is it portable?</a> +<li><a href="#webServer">Is PicoLisp a web server?</a> +<li><a href="#lambda">I cannot find the LAMBDA keyword in PicoLisp</a> +<li><a href="#dynamic">Why do you use dynamic variable binding?</a> +<li><a href="#problems">Are there no problems caused by dynamic binding?</a> +<li><a href="#closures">But with dynamic binding I cannot implement closures!</a> +<li><a href="#macros">Do you have macros?</a> +<li><a href="#strings">Why are there no strings?</a> +<li><a href="#arrays">What about arrays?</a> +<li><a href="#bind">What happens when I locally bind a symbol which has a function definition?</a> +<li><a href="#hardware">Would it make sense to build PicoLisp in hardware?</a> +<li><a href="#ask">Where can I ask questions?</a> +</ul> + +<p><hr> +<h2><a name="yet">Why did you write yet another Lisp?</a></h2> + +<p>Because other Lisps are not the way I'd like them to be. They concentrate on +efficient compilation, and lost the one-to-one relationship of language and +virtual machine of an interpreted system, gave up power and flexibility, and +impose unnecessary limitations on the freedom of the programmer. Other reasons +are the case-insensitivity and complexity of current Lisp systems. + + +<p><hr> +<h2><a name="who">Who can use PicoLisp?</a></h2> + +<p>PicoLisp is for programmers who want to control their programming +environment, at all levels, from the application domain down to the bare metal. +Who want use a transparent and simple - yet universal - programming model, and +want to know exactly what is going on. This is an aspect influenced by Forth. + +<p>It does <i>not</i> pretend to be easy to learn. There are already plenty of +languages that do so. It is not for people who don't care what's under the hood, +who just want to get their application running. They are better served with some +standard, "safe" black-box, which may be easier to learn, and which allegedly +better protects them from their own mistakes. + + +<p><hr> +<h2><a name="advantages">What are the advantages over other Lisp systems?</a></h2> + +<h3>Simplicity</h3> +<p>PicoLisp is easy to understand and adapt. There is no compiler enforcing +special rules, and the interpreter is simple and straightforward. There are only +three data types: Numbers, symbols and lists ("LISP" means "List-, Integer- and +Symbol Processing" after all ;-). The memory footprint is minimal, and the +tarball size of the whole system is just a few hundred kilobytes. + +<h3>A Clear Model</h3> +<p>Most other systems define the language, and leave it up to the implementation +to follow the specifications. Therefore, language designers try to be as +abstract and general as possible, leaving many questions and ambiguities to the +users of the language. + +<p>PicoLisp does the opposite. Initially, only the single-cell data structure +was defined, and then the structure of numbers, symbols and lists as they are +composed of these cells. Everything else in the whole system follows from these +axioms. This is documented in the chapter about the <a href="ref.html#vm">The +PicoLisp Machine</a> in the reference manual. + +<h3>Orthogonality</h3> +<p>There is only one symbolic data type, no distinction (confusion) between +symbols, strings, variables, special variables and identifiers. + +<p>Most data-manipulation functions operate on the value cells of symbols as +well as the CARs of list cells: + +<pre><code> +: (let (N 7 L (7 7 7)) (inc 'N) (inc (cdr L)) (cons N L)) +-> (8 7 8 7) +</code></pre> + +<p>There is only a single functional type, no "special forms". As there is no +compiler, functions can be used instead of macros. No special "syntax" +constructs are needed. This allows a completely orthogonal use of functions. For +example, most other Lisps do not allow calls like + +<pre><code> +: (mapcar if '(T NIL T NIL) '(1 2 3 4) '(5 6 7 8)) +-> (1 6 3 8) +</code></pre> + +<p>PicoLisp has no such restrictions. It favors the principle of "Least +Astonishment". + +<h3>Object System</h3> +<p>The OOP system is very powerful, because it is fully dynamic, yet extremely +simple: + +<p><ul> +<li>In other systems you have to statically declare "slots". In PicoLisp, +classes and objects are completely dynamic, they are created and extended at +runtime. "Slots" don't even exist at creation time. They spring into existence +purely dynamically. You can add any new property or any new method to any single +object, at any time, regardless of its class. + +<li>The multiple inheritance is such that not only classes can have several +superclasses, but each individual object can be of more than one class. + +<li>Prefix classes can surgically change the inheritance tree for any class or +object. They behave like Mixins in this regard. + +<li>Fine-control of inheritance in methods with <code><a +href="refS.html#super">super</a></code> and <code><a +href="refE.html#extra">extra</a></code>. + +</ul> + +<h3>Pragmatism</h3> +<p>PicoLisp has many practical features not found in other Lisp dialects. Among +them are: + +<p><ul> +<li>Auto-quoting of lists when the CAR is a number. Instead of <code>'(1 2 +3)</code> you can just write <code>(1 2 3)</code>. This is possible because a +number never makes sense as a function name, and has to be checked at runtime +anyway. + +<li>The <code><a href="refQ.html#quote">quote</a></code> function returns all +unevaluated arguments, instead of just the first one. This is both faster +(<code>quote</code> does not have to take the CAR of its argument list) and +smaller (a single cell instead of two). For example, <code>'A</code> expands to +<code>(quote . A)</code> and <code>'(A B C)</code> expands to <code>(quote A B +C)</code>. + +<li>The symbol <code><a href="ref.html#atres">@</a></code> is automatically +maintained as a local variable, and set implicitly in certain flow- and +logic-functions. This makes it often unnecessary to allocate and assign local +variables. + +<li><a href="tut.html#funio">Functional I/O</a> is more convenient than +explicitly passing around file descriptors. + +<li>A well-defined <a href="ref.html#cmp">ordinal relationship</a> between +arbitrary data types facilitates generalized comparing and sorting. + +<li>Uniform handling of <code>var</code> locations (i.e. values of symbols and +CARs of list cells). + +<li>The universality and usefulness of symbol properties is enforced and +extended with implicit and explicit bindings of the symbol <code><a +href="refT.html#This">This</a></code> in combination with the access functions +<code><a href="ref_.html#=:">=:</a></code>, <code><a +href="ref_.html#:">:</a></code> and <code><a href="ref_.html#::">::</a></code>. + +<li>A very convenient list-building machinery, using the <code><a +href="refL.html#link">link</a></code>, <code><a +href="refY.html#yoke">yoke</a></code>, <code><a +href="refC.html#chain">chain</a></code> and <code><a +href="refM.html#made">made</a></code> functions in the <code><a +href="refM.html#make">make</a></code> environment. + +<li>The syntax of often-used functions is kept non-verbose. For example, instead +of <code>(let ((A 1) (B 2) C 3) ..)</code> you write <code>(let (A 1 B 2 C 3) +..)</code>, or just <code>(let A 1 ..)</code> if there is only a single +variable. + +<li>The use of the hash (<code>#</code>) as a comment character is more adequate +today, and allows a clean hash-bang (<code>#!</code>) syntax for stand-alone +scripts. + +<li>The interpreter is <a href="ref.html#invoc">invoked</a> with a simple and +flexible syntax, where command line arguments are either files to be interpreted +or functions to be directly executed. With that, many tasks can be performed +without writing a separate <a href="tut.html#script">script</a>. + +<li>A sophisticated system of interprocess communication, file locking and +synchronization allows multi-user access to database applications. + +<li>A Prolog interpreter is tightly integrated into the language. Prolog +clauses can call Lisp expressions and vice versa, and a self-adjusting +depth-first search predicate <code>select</code> can be used in database +queries. + +</ul> + +<h3>Persistent Symbols</h3> +<p>Database objects ("external" symbols) are a primary data type in PicoLisp. +They look like normal symbols to the programmer, but are managed (fetched from, +and stored to, the data base) automatically by the system. Symbol manipulation +functions like <code>set</code>, <code>put</code> or <code>get</code>, the +garbage collector, and other parts of the interpreter know about them. + +<h3>Application Server</h3> +<p>Stand-alone system: Does not depend on external programs like Apache or +MySQL. Provides a "live" user interface on the client side, with an application +server session for each connected client. The GUI layout and behavior is +described with s-expressions, generated dynamically at runtime, and interacts +directly with the database structures. + +<h3>Localization</h3> +<p>Internal exclusive and full use of UTF-8 encoding, and self-translating <a +href="ref.html#transient-io">transient symbols</a> (strings), make it easy to +write country- and language-independent applications. + + +<p><hr> +<h2><a name="performance">How is the performance compared to other Lisp systems?</a></h2> + +<p>Despite the fact that PicoLisp is an interpreted-only system, the performance +is quite good. Typical Lisp programs, operating on list data structures, execute +in (interpreted) PicoLisp at about the same speed as in (compiled) CMUCL, and +about two or three times faster than in CLisp or Scheme48. Programs with lots of +numeric calculations, however, are several times slower, mainly due to +PicoLisp's somewhat inefficient implementation of bignums in the 32-bit version. + +<p>But in practice, speed was never a problem, even with the first versions of +PicoLisp in 1988 on a Mac II with a 12 MHz CPU. And certain things are cleaner +and easier to do in plain C anyway. It is very easy to write C functions in +PicoLisp, either in the kernel, as shared object libraries, or even inline in +the Lisp code. + +<p>PicoLisp is very space-effective. Other Lisp systems reserve heap space twice +as much as needed, or use rather large internal structures to store cells and +symbols. Each cell or minimal symbol in PicoLisp consists of only two pointers. +No additional tags are stored, because they are implied in the pointer +encodings. No gaps remain in the heap during allocation, as there are only +objects of a single size. As a result, consing and garbage collection are very +fast, and overall performance benefits from a better cache efficiency. Heap and +stack grow automatically, and are limited only by hardware and operating system +constraints. + + +<p><hr> +<h2><a name="interpreted">What means "interpreted"?</a></h2> + +<p>It means to directly execute Lisp data as program code. No transformation to +another representation of the code (e.g. compilation), and no structural +modifications of these data, takes place. + +<p>Lisp data are the "real" things, like numbers, symbols and lists, which can +be directly handled by the system. They are <i>not</i> the textual +representation of these structures (which is outside the Lisp realm and taken +care of the <code><a href="refR.html#read">read</a></code>ing and <code><a +href="refP.html#print">print</a></code>ing interfaces). + +<p>The following example builds a function and immediately calls it with two +arguments: + +<pre><code> +: ((list (list 'X 'Y) (list '* 'X 'Y)) 3 4) +-> 12 +</code></pre> + +<p>Note that no time is wasted to build up a lexical environment. Variable +bindings take place dynamically during interpretation. + +<p>A PicoLisp function is able to inspect or modify itself while it is running +(though this is rarely done in application programming). The following function +modifies itself by incrementing the '0' in its body: + +<pre><code> +(de incMe () + (do 8 + (printsp 0) + (inc (cdadr (cdadr incMe))) ) ) + +: (incMe) +0 1 2 3 4 5 6 7 -> 8 +: (incMe) +8 9 10 11 12 13 14 15 -> 16 +</code></pre> + +<p>Only an interpreted Lisp can fully support such "Equivalence of Code and +Data". If executable pieces of data are used frequently, like in PicoLisp's +dynamically generated GUI, a fast interpreter is preferable over any compiler. + + +<p><hr> +<h2><a name="compiler">Is there (or will be in the future) a compiler available?</a></h2> + +<p>No. That would contradict the idea of PicoLisp's simple virtual machine +structure. A compiler transforms it to another (physical) machine, with the +result that many assumptions about the machine's behavior won't hold any more. +Besides that, PicoLisp primitive functions evaluate their arguments +independently and are not very much suited for being called from compiled code. +Finally, the gain in execution speed would probably not be worth the effort. +Typical PicoLisp applications often use single-pass code which is loaded, +executed and thrown away; a process that would be considerably slowed down by +compilation. + + +<p><hr> +<h2><a name="portable">Is it portable?</a></h2> + +<p>Yes and No. Though we wrote and tested PicoLisp originally only on Linux, it +now also runs on FreeBSD, Mac OS X (Darwin), Cygwin/Win32, and probably other +POSIX systems. The first versions were even fully portable between DOS, SCO-Unix +and Macintosh systems. But today we have Linux. Linux itself is very portable, +and you can get access to a Linux system almost everywhere. So why bother? + +<p>The GUI is completely platform independent (Browser), and in the times of +Internet an application <u>server</u> does not really need to be portable. + + +<p><hr> +<h2><a name="webServer">Is PicoLisp a web server?</a></h2> + +<p>Not really, but it evolved a great deal into that direction. + +<p>Historically it was the other way round: We had a plain X11 GUI for our +applications, and needed something platform independent. The solution was +obvious: Browsers are installed virtually everywhere. So we developed a protocol +which persuades a browser to function as a GUI front-end to our applications. +This is much simpler than to develop a full-blown web server. + +<p>In a sense, PicoLisp is a "pure" application server, not a web server +handling "web applications". + + +<p><hr> +<h2><a name="lambda">I cannot find the LAMBDA keyword in PicoLisp</a></h2> + +<p>Because it isn't there. The reason is that it is redundant; it is equivalent +to the <code>quote</code> function in any aspect, because there's no distinction +between code and data in PicoLisp, and <code>quote</code> returns the whole +(unevaluated) argument list. If you insist on it, you can define your own +<code>lambda</code>: + +<pre><code> +: (def 'lambda quote) +-> lambda +: ((lambda (X Y) (+ X Y)) 3 4) +-> 7 +: (mapcar (lambda (X) (+ 1 X)) '(1 2 3 4 5)) +-> (2 3 4 5 6) +</code></pre> + + +<p><hr> +<h2><a name="dynamic">Why do you use dynamic variable binding?</a></h2> + +<p>Dynamic binding is very powerful, because there is only one single, +dynamically changing environment active all the time. This makes it possible +(e.g. for program snippets, interspersed with application data and/or passed +over the network) to access the whole application context, freely, yet in a +dynamically controlled manner. And (shallow) dynamic binding is the fastest +method for a Lisp interpreter. + +<p>Lexical binding is more limited by definition, because each environment is +deliberately restricted to the visible (textual) static scope within its +establishing form. Therefore, most Lisps with lexical binding introduce "special +variables" to support dynamic binding as well, and constructs like +<code>labels</code> to extend the scope of variables beyond a single function. + +<p>In PicoLisp, function definitions are normal symbol values. They can be +dynamically rebound like other variables. As a useful real-world example, take +this little gem: + +<pre><code> +(de recur recurse + (run (cdr recurse)) ) +</code></pre> + +<p>It implements anonymous recursion, by defining <code>recur</code> statically +and <code>recurse</code> dynamically. Usually it is very cumbersome to think up +a name for a function (like the following one) which is used only in a single +place. But with <code>recur</code> and <code>recurse</code> you can simply +write: + +<pre><code> +: (mapcar + '((N) + (recur (N) + (if (=0 N) + 1 + (* N (recurse (- N 1))) ) ) ) + (1 2 3 4 5 6 7 8) ) +-> (1 2 6 24 120 720 5040 40320) +</code></pre> + +<p>Needless to say, the call to <code>recurse</code> does not have to reside in +the same function as the corresponding <code>recur</code>. Can you implement +anonymous recursion so elegantly with lexical binding? + + +<p><hr> +<h2><a name="problems">Are there no problems caused by dynamic binding?</a></h2> + +<p>You mean the <i>funarg</i> problem, or problems that arise when a variable +might be bound to <i>itself</i>? For that reason we have a convention in +PicoLisp to use <a href="ref.html#transient-io">transient symbols</a> (instead +of internal symbols) + +<ol> + +<li>for all parameters and locals, when functional arguments or executable lists +are passed through the current dynamic bindings + +<li>for a parameter or local, when that symbol might possibly be (directly or +indirectly) bound to itself, and the bound symbol's value is accessed in the +dynamic context + +</ol> + +<p>This is a form of lexical <i>scoping</i> - though we still have dynamic +<i>binding</i> - of symbols, similar to the <code>static</code> keyword in C. + +<p>In fact, these problems are a real threat, and may lead to mysterious bugs +(other Lisps have similar problems, e.g. with symbol capture in macros). They +can be avoided, however, when the above conventions are observed. As an example, +consider a function which doubles the value in a variable: + +<pre><code> +(de double (Var) + (set Var (* 2 (val Var))) ) +</code></pre> + +<p>This works fine, as long as we call it as <code>(double 'X)</code>, but will +break if we call it as <code>(double 'Var)</code>. Therefore, the correct +implementation of <code>double</code> should be: + +<pre><code> +(de double (<u>Var</u>) + (set <u>Var</u> (* 2 (val <u>Var</u>))) ) +</code></pre> + +<p>If <code>double</code> is defined that way in a separate source file, and/or +isolated via the <code><a href="ref_.html#====">====</a></code> function, then +the symbol <code><u>Var</u></code> is locked into a private lexical context +and cannot conflict with other symbols. + +<p>Admittedly, there are two disadvantages with this solution: + +<ol> + +<li>The rules for when to use transient symbols are a bit complicated. Though it +is safe to use them even when not necessary, it will take more space then and be +more difficult to debug. + +<li>The string-like syntax of transient symbols as variables may look strange to +alumni of other languages. Therefore, the use of <a +href="refT.html#*Tsm">transient symbol markup</a> is recommended. + +</ol> + +Fortunately, these pitfalls do not occur so very often, and seem more likely in +utilities than in production code, so that they can be easily encapsulated. + + +<p><hr> +<h2><a name="closures">But with dynamic binding I cannot implement closures!</a></h2> + +<p>This is not true. Closures are a matter of scope, not of binding. + +<p>For a closure it is necessary to build and maintain an environment. For +lexical bindings, this has <i>always</i> to be done, and in case of compiled +code it is the most efficient strategy anyway, because it is done once by the +compiler, and can then be accessed as stack frames at runtime. + +<p>For an interpreter, however, this is quite an overhead. So it should not be +done automatically at each and every function invocation, but only if needed. + +<p>You have several options in PicoLisp. For simple cases, you can take +advantage of the static scope of <a href="ref.html#transient-io">transient +symbols</a>. For the general case, PicoLisp has built-in functions like <code><a +href="refB.html#bind">bind</a></code> or <code><a +href="refJ.html#job">job</a></code>, which dynamically manage statically scoped +environments. + +<p>As an example, consider a currying function: + +<pre><code> +(de curry Args + (list (car Args) + (list 'list + (lit (cadr Args)) + (list 'cons ''job + (list 'cons + (list 'lit (list 'env (lit (car Args)))) + (lit (cddr Args)) ) ) ) ) ) +</code></pre> + +<p>When called, it returns a function-building function which may be applied to +some argument: + +<pre><code> +: ((curry (X) (N) (* X N)) 3) +-> ((N) (job '((X . 3)) (* X N))) +</code></pre> + +<p>or used as: + +<pre><code> +: (((curry (X) (N) (* X N)) 3) 4) +-> 12 +</code></pre> + +<p>In other cases, you are free to choose a shorter and faster solution. If (as +in the example above) the curried argument is known to be immutable: + +<pre><code> +(de curry Args + (list + (cadr Args) + (list 'fill + (lit (cons (car Args) (cddr Args))) + (lit (cadr Args)) ) ) ) +</code></pre> + +<p>Then the function built above will just be: + +<pre><code> +: ((curry (X) (N) (* X N)) 3) +-> ((X) (* X 3)) +</code></pre> + +<p>In that case, the "environment build-up" is reduced by a simple (lexical) +constant substitution with zero runtime overhead. + +<p>Note that the actual <code><a href="refC.html#curry">curry</a></code> +function is simpler and more pragmatic. It combines both strategies (to use +<code>job</code>, or to substitute), deciding at runtime what kind of function +to build. + + +<p><hr> +<h2><a name="macros">Do you have macros?</a></h2> + +<p>Yes, there is a macro mechanism in PicoLisp, to build and immediately execute +a list of expressions. But it is seldom used. Macros are a kludge. Most things +where you need macros in other Lisps are directly expressible as functions in +PicoLisp, which (as opposed to macros) can be applied, passed around, and +debugged. + + +<p><hr> +<h2><a name="strings">Why are there no strings?</a></h2> + +<p>Because PicoLisp has something better: <a +href="ref.html#transient-io">Transient symbols</a>. They look and behave like +strings in any respect, but are nevertheless true symbols, with a value cell and +a property list. + +<p>This leads to interesting opportunities. The value cell, for example, can +point to other data that represent the string's the translation. This is used +extensively for localization. When a program calls + +<pre><code> + (prinl "Good morning!") +</code></pre> + +<p>then changing the value of the symbol <code>"Good morning!"</code> to its +translation will change the program's output at runtime. + +<p>Transient symbols are also quite memory-conservative. As they are stored in +normal heap cells, no additional overhead for memory management is induced. The +cell holds the symbol's value in its CDR, and the tail in its CAR. If the string +is not longer than 7 bytes, it fits (on the 64-bit version) completely into the +tail, and a single cell suffices. Up to 15 bytes take up two cells, 23 bytes +three etc., so that long strings are not very efficient (needing twice the +memory on the avarage), but this disadvantage is made up by simplicity and +uniformity. And lots of extremely long strings are not the common case, as they +are split up anyway during processing, and stored as plain byte sequences in +external files and databases. + +<p>Because transient symbols are temporarily interned (while <code><a +href="refL.html#load">load</a></code>ing the current source file), they are +shared within the same source and occupy that space only once, even if they +occur multiple times within the same file. + + +<p><hr> +<h2><a name="arrays">What about arrays?</a></h2> + +<p>PicoLisp has no array or vector data type. Instead, lists must be used for +any type of sequentially arranged data. + +<p>We believe that arrays are usually overrated. Textbook wisdom tells that they +have a constant access time O(1) when the index is known. Many other operations +like splits or insertions are rather expensive. Access with a known (numeric) +index is not really typical for Lisp, and even then the advantage of an array is +significant only if it is relatively long. Holding lots of data in long arrays, +however, smells quite like a program design error, and we suspect that often +more structured representations like trees or interconnected objects would be +better. + +<p>In practice, most arrays are rather short, or the program can be designed in +such a way that long arrays (or at least an indexed access) are avoided. + +<p>Using lists, on the other hand, has advantages. We have so many concerted +functions that uniformly operate on lists. There is no separate data type that +has to be handled by the interpreter, garbage collector, I/O, database and so +on. Lists can be made circular. And lists don't cause memory fragmentation. + + +<p><hr> +<h2><a name="bind">What happens when I locally bind a symbol which has a function definition?</a></h2> + +<p>That's not a good idea. The next time that function gets executed within the +dynamic context the system may crash. Therefore we have a convention to use an +upper case first letter for locally bound symbols: + +<pre><code> +(de findCar (Car List) + (when (member Car (cdr List)) + (list Car (car List)) ) ) +</code></pre> + +;-) + + +<p><hr> +<h2><a name="hardware">Would it make sense to build PicoLisp in hardware?</a></h2> + +<p>At least it should be interesting. It would be a machine executing list +(tree) structures instead of linear instruction sequences. "Instruction +prefetch" would look down the CAR- and CDR-chains, and perhaps need only a +single cache for both data and instructions. + +<p>Primitive functions like <code>set</code>, <code>val</code>, <code>if</code> +and <code>while</code>, which are written in <Code>C</code> or assembly language +now, would be implemented in microcode. Plus a few I/O functions for hardware +access. <code>EVAL</code> itself would be a microcode subroutine. + +<p>Only a single heap and a single stack is needed. They grow towards each +other, and cause garbage collection if they get too close. Heap compaction is +trivial due to the single cell size. + +<p>There would be no assembly-language. The lowest level (above the hardware and +microcode levels) are s-expressions: The machine language is <i>Lisp</i>. + + +<p><hr> +<h2><a name="ask">Where can I ask questions?</a></h2> + +<p>The best place is the <a +href="mailto:picolisp@software-lab.de?subject=Subscribe">PicoLisp Mailing +List</a> (see also <a +href="http://www.mail-archive.com/picolisp@software-lab.de/">The Mail +Archive</a>), or the IRC <a href="irc://irc.freenode.net/picolisp">#picolisp</a> +channel on FreeNode.net. + +</body> +</html> diff --git a/doc/fun.l b/doc/fun.l @@ -0,0 +1,9 @@ +# 25jun07abu +# (c) Software Lab. Alexander Burger + +(de fact (N) + (if (=0 N) + 1 + (* N (fact (dec N))) ) ) + +# vi:et:ts=3:sw=3 diff --git a/doc/hello.l b/doc/hello.l @@ -0,0 +1,5 @@ +(load "lib/xhtml.l") + +(html 0 "Hello" NIL NIL + (<h3> NIL "Hello world") + "This is PicoLisp" ) diff --git a/doc/index.html b/doc/index.html @@ -0,0 +1,108 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> + <meta http-equiv="content-type" content="text/html; charset=utf-8"> + <title>PicoLisp Docs</title> + <meta name="generator" content="BBEdit 8.6"> + <script type="text/javascript" language="javascript"> + <!-- +function frameIdAsVariable(aFrame) { + // IE hack + // http://www.greymagic.com/security/advisories/gm011-ie/ + if (aFrame.name == "toc") return tocfid; + if (aFrame.name == "upper") return upfid; +} + +function contentDoc(aFrame) { + if (aFrame.contentDocument) { + return aFrame.contentDocument; + } else { + var fid = frameIdAsVariable(aFrame); + if (fid) { + return fid.document; + } + } + alert("Couldn't access a frame's document for this kind of browser."); +} + +function doTocSublists(upDoc) { + var tocDoc = contentDoc(document.getElementById("tocfid")); + var ul = tocDoc.getElementById("upperul"); + var oldExp = null; + var newSub = null; + for (var i=0; i<ul.childNodes.length; i++) { + var cni = ul.childNodes[i]; + if (cni.firstChild) { + // cni.firstChild is an anchor + if (cni.firstChild.href == upDoc.URL) { + // Found TOC anchor that matches upper document + if (upDoc.URL.indexOf("#") < 0) { + if (cni.lastChild.nodeName != "UL") { + // Expansion required, making sub-list ... + newSub = tocDoc.createElement("ul"); + newSub.className = "sub"; + for (var j=0; j<upDoc.anchors.length; j++) { + var ajText = null; + if (upDoc.anchors[j].innerText) { + ajText = upDoc.anchors[j].innerText; + } else if (upDoc.anchors[j].text) { + ajText = upDoc.anchors[j].text; + } + if (ajText) { + var li = tocDoc.createElement("li"); + var a = tocDoc.createElement("a"); + a.href = upDoc.URL + "#" + upDoc.anchors[j].name; + a.target = "upper"; + a.appendChild(tocDoc.createTextNode(ajText)); + li.appendChild(a); + newSub.appendChild(li); + } + } + cni.appendChild(newSub); + } + } + } else if (cni.lastChild.nodeName == "UL") { + oldExp = cni; + } + } + } + if ((oldExp != null) && (newSub != null)) { + // Remove old sub-list to save TOC space ... + oldExp.removeChild(oldExp.lastChild); + } +} + +function upperLoad(upperFrame) { + try { + var upDoc = contentDoc(upperFrame); + // First modify the targets of the ref anchors ... + var anchors = upDoc.getElementsByTagName("a"); + for (var i=0; i<anchors.length; i++) { + var ai = anchors[i]; + if (ai.href.match(/\/ref\w\.html/)) { + ai.target = "lower"; + } + } + doTocSublists(upDoc); + } catch (e) { + alert(e); + } +} + //--> +</script> +</head> +<frameset cols="15%,85%"> + <frameset rows="*,80"> + <frame id="tocfid" name="toc" src="toc.html"> + <frame name="reflook" src="rlook.html"> + </frameset> + + <frameset rows="50%,50%"> + <frame id="upfid" name="upper" src="ref.html#fun" onload="upperLoad(this);"> + <frame name="lower" src="ref.html"> + </frameset> + +</frameset> + +</html> diff --git a/doc/model b/doc/model @@ -0,0 +1,57 @@ +# 20aug04abu +# (c) Software Lab. Alexander Burger + +Sym Val -> Model list: +( + pos.x pos.y pos.z # Position + rot.a.x rot.a.y rot.a.z # Orientation + rot.b.x rot.b.y rot.b.z + rot.c.x rot.c.y rot.c.z + sym # Submodel + .. + (col1 col2 ["text"] p1.x p1.y p1.z p2.x p2.y p2.z ..) # Face + .. + sym # Submodel + .. + (col1 col2 p1.x p1.y p1.z p2.x p2.y p2.z p3.x p3.y p3.z ..) # Face + .. +) + +<col> <col> # Both sides visible +<col> NIL # Backface culling + NIL <col> # Foreside culling + NIL NIL # Transparent + NIL T # Shadow + + +Transmission format: + hor sky gnd + cnt x y z "text" x y z x y z .. col + cnt x y z NIL x y z x y z x y z .. col + .. + 0 32767 | 0 snx sny + +Transmission size: + (4 + 2 * polygons + 3 * points) * 4 bytes + + +Polygon design rules: + +- All polygons should be convex + (split concave polygons if necessary) + +- Points loop right when seen from the front side + (if the two faces should have different colors) + +- The first three points must not be on a straight line + (to allow the calculation of the normal vector) + +- The first point cannot be the local origin + (if 'aRot' is to be used) + + +z3dField .graf +((x y . "string") ..) + +Transmission format: + cnt x y "string" .. diff --git a/doc/quine b/doc/quine @@ -0,0 +1,24 @@ +With lambda (= 'quote'): + : ('((X) (list (lit X) (lit X))) '((X) (list (lit X) (lit X)))) + -> ('((X) (list (lit X) (lit X))) '((X) (list (lit X) (lit X)))) + + +With 'let': + : (let X '(list 'let 'X (lit X) X) (list 'let 'X (lit X) X)) + -> (let X '(list 'let 'X (lit X) X) (list 'let 'X (lit X) X)) + + +Cheating: + : (de quine NIL + (pp 'quine) ) + -> quine + + : (quine) + (de quine NIL + (pp 'quine) ) + -> quine + + +Succinct: + : T + -> T diff --git a/doc/ref.html b/doc/ref.html @@ -0,0 +1,2455 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/1998/REC-html40-19980424/loose.dtd"> +<html lang="en"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> +<title>PicoLisp Reference</title> +<link rel="stylesheet" href="doc.css" type="text/css"> +</head> +<body> +<a href="mailto:abu@software-lab.de">abu@software-lab.de</a> + +<p align=right> +<i>Perfection is attained</i><br> +<i>not when there is nothing left to add</i><br> +<i>but when there is nothing left to take away</i><br> +<i>(Antoine de Saint-Exupéry)</i><br> + + +<h1>The PicoLisp Reference</h1> + +<p align=right>(c) Software Lab. Alexander Burger + +<p>This document describes the concepts, data types, and kernel functions of the +<a href="http://software-lab.de/down.html">PicoLisp</a> system. + +<p>This is <i>not</i> a Lisp tutorial. For an introduction to Lisp, a +traditional Lisp book like "Lisp" by Winston/Horn (Addison-Wesley 1981) is +recommended. Note, however, that there are significant differences between +PicoLisp and Maclisp (and even greater differences to Common Lisp). + +<p>Please take a look at the <a href="tut.html">PicoLisp Tutorial</a> for an +explanation of some aspects of PicoLisp, and scan through the list of <a +href="faq.html">Frequently Asked Questions (FAQ)</a>. + +<p><ul> +<li><a href="#intro">Introduction</a> +<li><a href="#vm">The PicoLisp Machine</a> + <ul> + <li><a href="#cell">The Cell</a> + <li><a href="#data">Data Types</a> + <ul> + <li><a href="#number">Numbers</a> + <li><a href="#symbol">Symbols</a> + <ul> + <li><a href="#nilSym">NIL</a> + <li><a href="#internal">Internal Symbols</a> + <li><a href="#transient">Transient Symbols</a> + <li><a href="#external">External Symbols</a> + </ul> + <li><a href="#lst">Lists</a> + </ul> + <li><a href="#mem">Memory Management</a> + </ul> +<li><a href="#penv">Programming Environment</a> + <ul> + <li><a href="#invoc">Invocation</a> + <li><a href="#io">Input/Output</a> + <ul> + <li><a href="#num-io">Numbers</a> + <li><a href="#sym-io">Symbols</a> + <ul> + <li><a href="#nilSym-io">NIL</a> + <li><a href="#internal-io">Internal Symbols</a> + <li><a href="#transient-io">Transient Symbols</a> + <li><a href="#external-io">External Symbols</a> + </ul> + <li><a href="#lst-io">Lists</a> + <li><a href="#macro-io">Read-Macros</a> + </ul> + <li><a href="#ev">Evaluation</a> + <li><a href="#int">Interrupt</a> + <li><a href="#errors">Error Handling</a> + <li><a href="#atres">@ Result</a> + <li><a href="#cmp">Comparing</a> + <li><a href="#oop">OO Concepts</a> + <li><a href="#dbase">Database</a> + <ul> + <li><a href="#trans">Transactions</a> + <li><a href="#er">Entities / Relations</a> + </ul> + <li><a href="#pilog">Pilog (PicoLisp Prolog)</a> + <li><a href="#conv">Naming Conventions</a> + <li><a href="#trad">Breaking Traditions</a> + <li><a href="#bugs">Bugs</a> + </ul> +<li><a href="#fun">Function Reference</a> +<li><a href="#down">Download</a> +</ul> + + +<p><hr> +<h2><a name="intro">Introduction</a></h2> + +<p>PicoLisp is the result of a language design study, trying to answer the +question "What is a minimal but useful architecture for a virtual machine?". +Because opinions differ about what is meant by "minimal" and "useful", there are +many answers to that question, and people might consider other solutions more +"minimal" or more "useful". But from a practical point of view, PicoLisp has +proven to be a valuable answer to that question. + +<p>First of all, PicoLisp is a virtual machine architecture, and then a +programming language. It was designed in a "bottom up" way, and "bottom up" is +also the most natural way to understand and to use it: <i>Form Follows +Function</i>. + +<p>PicoLisp has been used in several commercial and research programming +projects since 1988. Its internal structures are simple enough, allowing an +experienced programmer always to fully understand what's going on under the +hood, and its language features, efficiency and extensibility make it suitable +for almost any practical programming task. + +<p>In a nutshell, emphasis was put on four design objectives. The PicoLisp +system should be + +<p><dl> + +<dt>Simple +<dd>The internal data structure should be as simple as possible. Only one single +data structure is used to build all higher level constructs. + +<dt>Unlimited +<dd>There are no limits imposed upon the language due to limitations of the +virtual machine architecture. That is, there is no upper bound in symbol name +length, number digit counts, stack depth, or data structure and buffer sizes, +except for the total memory size of the host machine. + +<dt>Dynamic +<dd>Behavior should be as dynamic as possible ("run"-time vs. "compile"-time). +All decisions are delayed till runtime where possible. This involves matters +like memory management, dynamic symbol binding, and late method binding. + +<dt>Practical +<dd>PicoLisp is not just a toy of theoretical value. It is in use since 1988 in +actual application development, research and production. + +</dl> + + +<p><hr> +<h2><a name="vm">The PicoLisp Machine</a></h2> + +<p>An important point in the PicoLisp philosophy is the knowledge about the +architecture and data structures of the internal machinery. The high-level +constructs of the programming language directly map to that machinery, making +the whole system both understandable and predictable. + +<p>This is similar to assembly language programming, where the programmer has +complete control over the machine. + + +<p><hr> +<h3><a name="cell">The Cell</a></h3> + +<p>The PicoLisp virtual machine is both simpler and more powerful than most +current (hardware) processors. At the lowest level, it is constructed from a +single data structure called "cell": + +<pre><code> + +-----+-----+ + | CAR | CDR | + +-----+-----+ +</code></pre> + +<p>A cell is a pair of machine words, which traditionally are called CAR and CDR +in the Lisp terminology. These words can represent either a numeric value +(scalar) or the address of another cell (pointer). All higher level data +structures are built out of cells. + +<p>The type information of higher level data is contained in the pointers to +these data. Assuming the implementation on a byte-addressed physical machine, +and a pointer size of typically 4 bytes, each cell has a size of 8 bytes. +Therefore, the pointer to a cell must point to an 8-byte boundary, and its +bit-representation will look like: + +<pre><code> + xxxxxxxxxxxxxxxxxxxxxxxxxxxxx000 +</code></pre> + +<p>(the <code>'x'</code> means "don't care"). For the individual data types, the +pointer is adjusted to point to other parts of a cell, in effect setting some of +the lower three bits to non-zero values. These bits are then used by the +interpreter to determine the data type. + +<p>In any case, bit(0) - the least significant of these bits - is reserved as a +mark bit for garbage collection. + +<p>Initially, all cells in the memory are unused (free), and linked together to +form a "free list". To create higher level data types at runtime, cells are +taken from that free list, and returned by the garbage collector when they are +no longer needed. All memory management is done via that free list; there are no +additional buffers, string spaces or special memory areas (With two exceptions: +A certain fixed area of memory is set aside to contain the executable code and +global variables of the interpreter itself, and a standard push down stack for +return addresses and temporary storage. Both are not directly accessible by the +programmer). + + +<p><hr> +<h3><a name="data">Data Types</a></h3> + +<p>On the virtual machine level, PicoLisp supports + +<p><ul> +<li>three base data types: Numbers, Symbols and Cons Pairs (Lists) +<li>the three scope variations of symbols: Internal, Transient and External +<li>and the special symbol <code>NIL</code>. +</ul> + +<p>They are all built from the single cell data structure, and all runtime data +cannot consist of any other types than these three. + +<p>The following diagram shows the complete data type hierarchy, consisting of +the three base types and the symbol variations: + +<pre><code> + cell + | + +--------+--------+ + | | | + Number Symbol List + | + | + +--------+--------+--------+ + | | | | + NIL Internal Transient External +</code></pre> + + +<p><hr> +<h4><a name="number">Numbers</a></h4> + +<p>A number can represent a signed integral value of arbitrary size. The CARs of +one or more cells hold the number's "digits" (each in the machine's word size), +to store the number's binary representation. + +<pre><code> + Number + | + V + +-----+-----+ +-----+-----+ +-----+-----+ + |'DIG'| ---+---> |'DIG'| ---+---> |'DIG'| / | + +-----+-----+ +-----+-----+ +-----+-----+ +</code></pre> + +<p>The first cell holds the least significant digit. The least significant bit +of that digit represents the sign. + +<p>The pointer to a number points into the middle of the CAR, with an offset of +2 from the cell's start address. Therefore, the bit pattern of a number will be: + +<pre><code> + xxxxxxxxxxxxxxxxxxxxxxxxxxxxx010 +</code></pre> + +<p>Thus, a number is recognized by the interpreter when bit(1) is non-zero. + + +<p><hr> +<h4><a name="symbol">Symbols</a></h4> + +<p>A symbol is more complex than a number. Each symbol has a value, and +optionally a name and an arbitrary number of properties. The CDR of a symbol +cell is also called VAL, and the CAR points to the symbol's tail. As a minimum, +a symbol consists of a single cell, and has no name or properties: + +<pre><code> + Symbol + | + V + +-----+-----+ + | / | VAL | + +-----+-----+ +</code></pre> + +<p>That is, the symbol's tail is empty (points to <code>NIL</code>, as indicated +by the '/' character). + +<p>The pointer to a symbol points to the CDR of the cell, with an offset of 4 +from the cell's start address. Therefore, the bit pattern of a symbol will be: + +<pre><code> + xxxxxxxxxxxxxxxxxxxxxxxxxxxxx100 +</code></pre> + +<p>Thus, a symbol is recognized by the interpreter when bit(2) is non-zero. + +<p>A property is a key-value-pair, represented as a cell in the symbol's tail. +This is called a "property list". The property list may be terminated by a +number representing the symbol's name. In the following example, a symbol with +the name <code>"abc"</code> has three properties: + +<pre><code> + Symbol + | + V + +-----+-----+ + | | | VAL | + +--+--+-----+ + | tail + | + V name + +-----+-----+ +-----+-----+ +-----+-----+ +-----+-----+ + | | | ---+---> | KEY | ---+---> | | | ---+---> |'cba'| / | + +--+--+-----+ +-----+-----+ +--+--+-----+ +-----+-----+ + | | + V V + +-----+-----+ +-----+-----+ + | VAL | KEY | | VAL | KEY | + +-----+-----+ +-----+-----+ +</code></pre> + +<p>Each property in a symbol's tail is either a symbol (then it represents a +boolean value), or a cell with the property key in its CDR and the property +value in its CAR. In both cases, the key should be a symbol, because searches in +the property list are performed using pointer comparisons. + +<p>The name of a symbol is stored as a number at the end of the tail. It +contains the characters of the name in UTF-8 encoding, using between one and +three 8-bit-bytes per character. The first byte of the first character is stored +in the lowest 8 bits of the number. + +<p>All symbols have the above structure, but depending on scope and +accessibility there are actually four types of symbols: <code><a +href="#nilSym">NIL</a></code>, <a href="#internal">internal</a>, <a +href="#transient">transient</a> and <a href="#external">external</a> symbols. + + +<p><hr> +<h5><a name="nilSym">NIL</a></h5> + +<p><code>NIL</code> is a special symbol which exists exactly once in the whole +system. It is used + +<p><ul> +<li>as an end-of-list marker +<li>to represent the empty list +<li>to represent the boolean value "false" +<li>to represent a string of length zero +<li>to represent the value "Not a Number" +<li>as the root of all class hierarchies +</ul> + +<p>For that, <code>NIL</code> has a special structure: + +<pre><code> + NIL: / + | + V + +-----+-----+-----+-----+ + | / | / | / | / | + +-----+--+--+-----+-----+ +</code></pre> + +<p>The reason for that structure is <code>NIL</code>'s dual nature both as a +symbol and as a list: + +<p><ul> +<li>As a symbol, it should give <code>NIL</code> for its VAL, and be without +properties + +<li>For the empty list, <code>NIL</code> should give <code>NIL</code> both for +its CAR and for its CDR + +</ul> + +<p>These requirements are fulfilled by the above structure. + + +<p><hr> +<h5><a name="internal">Internal Symbols</a></h5> + +<p>Internal Symbols are all those "normal" symbols, as they are used for +function definitions and variable names. They are "interned" into an index +structure, so that it is possible to find an internal symbol by searching for +its name. + +<p>There cannot be two different internal symbols with the same name. + +<p>Initially, a new internal symbol's VAL is <code>NIL</code>. + + +<p><hr> +<h5><a name="transient">Transient Symbols</a></h5> + +<p>Transient symbols are only interned into a index structure for a certain time +(e.g. while reading the current source file), and are released after that. That +means, a transient symbol cannot be accessed then by its name, and there may be +several transient symbols in the system having the same name. + +<p>Transient symbols are used + +<p><ul> +<li>as text strings + +<li>as identifiers with a limited access scope (like, for example, +<code>static</code> identifiers in the C language family) + +<li>as anonymous, dynamically created objects (without a name) + +</ul> + +<p>Initially, a new transient symbol's VAL is that symbol itself. + +<p>A transient symbol without a name can be created with the <code><a +href="refB.html#box">box</a></code> or <code><a +href="refN.html#new">new</a></code> functions. + + +<p><hr> +<h5><a name="external">External Symbols</a></h5> + +<p>External symbols reside in a database file (or a similar resources (see +<code><a href="refE.html#*Ext">*Ext</a></code>)), and are loaded into memory - +and written back to the file - dynamically as needed, and transparent to the +programmer. + +<p>The interpreter recognizes external symbols internally by an additional tag +bit in the tail structure. + +<p>There cannot be two different external symbols with the same name. External +symbols are maintained in index structures while they are loaded into memory, +and have their external location (disk file and block offset) directly coded +into their names. + +<p>Initially, a new external symbol's VAL is <code>NIL</code>, unless otherwise +specified at creation time. + + +<p><hr> +<h4><a name="lst">Lists</a></h4> + +<p>A list is a sequence of one or more cells, holding numbers, symbols, or +lists. Lists are used in PicoLisp to emulate composite data structures like +arrays, trees, stacks or queues. + +<p>In contrast to lists, numbers and symbols are collectively called "Atoms". + +<p>Typically, the CDR of each cell in a list points to the following cell, +except for the last cell which points <code>NIL</code>. If, however, the CDR of +the last cell points to an atom, that cell is called a "dotted pair" (because of +its I/O syntax with a dot '.' between the two values). + + +<p><hr> +<h3><a name="mem">Memory Management</a></h3> + +<p>The PicoLisp interpreter has complete knowledge of all data in the system, +due to the type information associated with every pointer. Therefore, an +efficient garbage collector mechanism can easily be implemented. PicoLisp +employs a simple but fast mark-and-sweep garbage collector. + +<p>As the collection process is very fast (in the order of milliseconds per +megabyte), it was not necessary to develop more complicated, time-consuming and +error-prone garbage collection algorithms (e.g. incremental collection). A +compacting garbage collector is also not necessary, because the single cell data +type cannot cause heap fragmentation. + + +<p><hr> +<h2><a name="penv">Programming Environment</a></h2> + +<p>Lisp was chosen as the programming language, because of its clear and simple +structure. + +<p>In some previous versions, a Forth-like syntax was also implemented on top of +a similar virtual machine (Lifo). Though that language was more flexible and +expressive, the traditional Lisp syntax proved easier to handle, and the virtual +machine can be kept considerably simpler. + +PicoLisp inherits the major advantages of classical Lisp systems like + +<p><ul> +<li>Dynamic data types and structures +<li>Formal equivalence of code and data +<li>Functional programming style +<li>An interactive environment +</ul> + +<p>In the following, some concepts and peculiarities of the PicoLisp language +and environment are described. + + +<p><hr> +<h3><a name="invoc">Invocation</a></h3> + +<p>When PicoLisp is invoked from the command line, an arbitrary number of +arguments may follow the command name. + +<p>By default, each argument is the name of a file to be executed by the +interpreter. If, however, the argument's first character is a hyphen '-', then +the rest of that argument is taken as a Lisp function call (without the +surrounding parentheses). A hyphen by itself as an argument stops evaluation of +the rest of the command line (it may be processed later using the <code><a +href="refA.html#argv">argv</a></code> and <code><a +href="refO.html#opt">opt</a></code> functions). This mechanism corresponds to +calling <code>(<a href="refL.html#load">load</a> T)</code>. + +<p>As a convention, PicoLisp source files have the extension "<code>.l</code>". + +<p>Note that the PicoLisp executable itself does not expect or accept any +command line flags or options. They are reserved for application programs. + +<p>The simplest and shortest invocation of PicoLisp does nothing, and exits +immediately by calling <code><a href="refB.html#bye">bye</a></code>: + +<pre><code> +$ bin/picolisp -bye +$ +</code></pre> + +<p>In interactive mode, the PicoLisp interpreter (see <code><a +href="refL.html#load">load</a></code>) will also exit when an empty line is +entered: + +<pre><code> +$ bin/picolisp +: # Typed ENTER +$ +</code></pre> + +<p>To start up the standard PicoLisp environment, several files should be +loaded. The most commonly used things are in "lib.l" and in a bunch of other +files, which are in turn loaded by "ext.l". Thus, a typical call would be: + +<pre><code> +$ bin/picolisp lib.l ext.l +</code></pre> + +<p>The recommended way, however, is to call the "p" shell script, which includes +"lib.l" and "ext.l". Given that your current project is loaded by some file +"myProject.l" and your startup function is <code>main</code>, your invocation +would look like: + +<pre><code> +$ ./p myProject.l -main +</code></pre> + +<p>For interactive development and debugging it is recommended also to load +"dbg.l" (or use './dbg' instead of './p'), to get the vi-style command line +editor, single-stepping, tracing and other debugging utilities. + +<pre><code> +$ ./dbg myProject.l -main +</code></pre> + +<p>In any case, the directory part of the first file name supplied on the +command line (normally, the path to "lib.l") is remembered internally as the +<u>PicoLisp Home Directory</u>. This path is later automatically substituted for +any leading "<code>@</code>" character in file name arguments to I/O functions +(see <code><a href="refP.html#path">path</a></code>). + + +<p><hr> +<h3><a name="io">Input/Output</a></h3> + +<p>In Lisp, each internal data structure has a well-defined external +representation in human-readable format. All kinds of data can be written to a +file, and restored later to their original form by reading that file. + +<p>In normal operation, the PicoLisp interpreter continuously executes an +infinite "read-eval-print loop". It reads one expression at a time, evaluates +it, and prints the result to the console. Any input into the system, like data +structures and function definitions, is done in a consistent way no matter +whether it is entered at the console or read from a file. + +<p>Comments can be embedded in the input stream with the hash <code>#</code> +character. Everything up to the end of that line will be ignored by the reader. + +<pre><code> +: (* 1 2 3) # This is a comment +-> 6 +</code></pre> + +<p>A comment spanning several lines may be enclosed between <code>#{</code> and +<code>}#</code>. + + +<p>Here is the I/O syntax for the individual PicoLisp data types: + + +<p><hr> +<h4><a name="num-io">Numbers</a></h4> + +<p>A number consists of an arbitrary number of digits (<code>'0'</code> through +<code>'9'</code>), optionally preceded by a sign character (<code>'+'</code> or +<code>'-'</code>). Legal number input is: + +<pre><code> +: 7 +-> 7 +: -12345678901245678901234567890 +-> -12345678901245678901234567890 +</code></pre> + +<p>Fixed-point numbers can be input by embedding a decimal point +<code>'.'</code>, and setting the global variable <code><a +href="refS.html#*Scl">*Scl</a></code> appropriately: + +<pre><code> +: *Scl +-> 0 + +: 123.45 +-> 123 +: 456.78 +-> 457 + +: (setq *Scl 3) +-> 3 +: 123.45 +-> 123450 +: 456.78 +-> 456780 +</code></pre> + +<p>Thus, fixed-point input simply scales the number to an integer value +corresponding to the number of digits in <code><a +href="refS.html#*Scl">*Scl</a></code>. + +<p>Formatted output of scaled fixed-point values can be done with the <code><a +href="refF.html#format">format</a></code> function: + +<pre><code> +: (format 1234567890 2) +-> "12345678.90" +: (format 1234567890 2 "." ",") +-> "12,345,678.90" +</code></pre> + + +<p><hr> +<h4><a name="sym-io">Symbols</a></h4> + +<p>The reader is able to recognize the individual symbol types from their +syntactic form. A symbol name should - of course - not look like a legal number +(see above). + +<p>In general, symbol names are case-sensitive. <code>car</code> is not the same +as CAR. + + +<p><hr> +<h5><a name="nilSym-io">NIL</a></h5> + +<p>Besides for standard normal form, <code>NIL</code> is also recognized as +<code>()</code>, <code>[]</code> or <code>""</code>. + +<pre><code> +: NIL +-> NIL +: () +-> NIL +: "" +-> NIL +</code></pre> + +<p>Output will always appear as <code>NIL</code>. + + +<p><hr> +<h5><a name="internal-io">Internal Symbols</a></h5> + +<p>Internal symbol names can consist of any printable (non-whitespace) +character, except for the following meta characters: + +<pre><code> + " ' ( ) , [ ] ` ~ { } +</code></pre> + +<p>It is possible, though, to include these special characters into symbol names +by escaping them with a backslash '<code>\</code>'. + +<p>The dot '<code>.</code>' has a dual nature. It is a meta character when +standing alone, denoting a <a href="#dotted">dotted pair</a>, but can otherwise +be used in symbol names. + +<p>As a rule, anything not recognized by the reader as another data type will be +returned as an internal symbol. + + +<p><hr> +<h5><a name="transient-io">Transient Symbols</a></h5> + +<p>In an interactive environment (console), transient symbols should appear as +an <u>underlined</u> sequence of characters. Where this is not possible (e.g. +for representation in files), or inconvenient (while editing), double quotes +'<code>"</code>' are used instead of underlining. + +<p>The underlining of transient symbols is controlled by the global variable +<code><a href="refT.html#*Tsm">*Tsm</a></code>, and can be switched off +completely with + +<pre><code> +: (off *Tsm) +</code></pre> + +<p>Keyboard input of transient symbols is always via the double quote key. + +<p>A transient symbol may be used (and, in double quote representation, also +look) like a string constant in other languages. However, it is a real symbol, +and may be assigned a value or a function definition, and properties. + +<p>Initially, a transient symbol's value is that symbol itself, so that it does +not need to be quoted for evaluation: + +<pre><code> +: <u>This is a string</u> # "This is a string" if *Tsm is off +-> <u>This is a string</u> +</code></pre> + +<p>However, care must be taken when assigning a value to a transient symbol. +This may cause unexpected behavior: + +<pre><code> +: (setq <u>This is a string</u> 12345) # (setq "This is a string" 12345) +-> 12345 +: <u>This is a string</u> +-> 12345 +</code></pre> + +<p>The name of a transient symbol can contain any character except zero. A +double quote character can be escaped with a backslash '<code>\</code>', and a +backslash itself has to be escaped with another backslash. Control characters +can be written with a preceding hat '<code>^</code>' character. + +<pre><code> +: <u>We^Ird\\Str\"ing</u> +-> <u>We^Ird\\Str"ing</u> +: (chop @) +-> (<u>W</u> <u>e</u> <u>^I</u> <u>r</u> <u>d</u> <u>\\</u> <u>S</u> <u>t</u> <u>r</u> <u>"</u> <u>i</u> <u>n</u> <u>g</u>) +</code></pre> + +<p>The index for transient symbols is cleared automatically before and after +<code><a href="refL.html#load">load</a></code>ing a source file, or it can be +reset explicitly with the <code><a href="ref_.html#====">====</a></code> +function. With that mechanism, it is possible to create symbols with a local +access scope, not accessible from other parts of the program. + +<p>A special case of transient symbols are <i>anonymous symbols</i>. These are +symbols without name (see <code><a href="refB.html#box">box</a></code>, <code><a +href="refB.html#box?">box?</a></code> or <code><a +href="refN.html#new">new</a></code>). They print as a dollar sign +(<code>$</code>) followed by a decimal digit string (actually their machine +address). + +<p>To allow an easier copy/paste of the examples, most of the documentation uses +the double quote notation for transient symbols. + + +<p><hr> +<h5><a name="external-io">External Symbols</a></h5> + +<p>External symbol names are surrounded by braces (<code>'{'</code> and +<code>'}'</code>). The characters of the symbol's name itself identify the +physical location of the external object. This is + +<ul> +<li>in the 32-bit version: The number of the database file, and - separated by a +hyphen - the starting block in the database file. Both numbers are encoded in +base-64 notation (characters '<code>0</code>' through '<code>9</code>', +'<code>:</code>', '<code>;</code>', '<code>A</code>' through '<code>Z</code>' +and '<code>a</code>' through '<code>z</code>'). + +<li>in the 64-bit version: The number of the database file minus 1 in "hax" +notation (i.e. hexadecimal/alpha notation, where '@' is zero, 'A' is 1 and 'O' +is 15 (from "alpha" to "omega")), immediately followed (without a hyphen) the +starting block in octal ('0' through '7'). + +</ul> + +<p>In both cases, the database file (and possibly the hypen) are omitted for the +first (default) file. + +<p><hr> +<h4><a name="lst-io">Lists</a></h4> + +<p>Lists are surrounded by parentheses (<code>'('</code> and <code>')'</code>). + +<p><code>(A)</code> is a list consisting of a single cell, with the symbol +<code>A</code> in its CAR, and <code>NIL</code> in its CDR. + +<p><code>(A B C)</code> is a list consisting of three cells, with the symbols +<code>A</code>, <code>B</code> and <code>C</code> respectively in their CAR, and +<code>NIL</code> in the last cell's CDR. + +<p><a name="dotted"><code>(A . B)</code></a> is a "dotted pair", a list +consisting of a single cell, with the symbol <code>A</code> in its CAR, and +<code>B</code> in its CDR. + +<p>PicoLisp has built-in support for reading and printing simple circular lists. +If the dot in a dotted-pair notation is immediately followed by a closing +parenthesis, it indicates that the CDR of the last cell points back to the +beginning of that list. + +<pre><code> +: (let L '(a b c) (conc L L)) +-> (a b c .) +: (cdr '(a b c .)) +-> (b c a .) +: (cddddr '(a b c .)) +-> (b c a .) +</code></pre> + +<p>A similar result can be achieved with the function <code><a +href="refC.html#circ">circ</a></code>. Such lists must be used with care, +because many functions won't terminate or will crash when given such a list. + + +<p><hr> +<h4><a name="macro-io">Read-Macros</a></h4> + +<p>Read-macros in PicoLisp are special forms that are recognized by the reader, +and modify its behavior. Note that they take effect immediately while reading an +expression, and are not seen by the <code>eval</code> in the main loop. + +<p>The most prominent read-macro in Lisp is the single quote character +<code>'</code>, which expands to a call of the <code><a +href="refQ.html#quote">quote</a></code> function. Note that the single quote +character is also printed instead of the full function name. + +<pre><code> +: '(a b c) +-> (a b c) +: '(quote . a) +-> 'a +: (cons 'quote 'a) # (quote . a) +-> 'a +: (list 'quote 'a) # (quote a) +-> '(a) +</code></pre> + +<p>A comma (<code>,</code>) will cause the reader to collect the following data +item into an <code><a href="refI.html#idx">idx</a></code> tree in the global +variable <code><a href="refU.html#*Uni">*Uni</a></code>, and to return a +previously inserted equal item if present. This makes it possible to create a +unique list of references to data which do normally not follow the rules of +pointer equality. + +<p>A single backquote character <code>`</code> will cause the reader to evaluate +the following expression, and return the result. + +<pre><code> +: '(a `(+ 1 2 3) z) +-> (a 6 z) +</code></pre> + +<p>A tilde character <code>~</code> inside a list will cause the reader to +evaluate the following expression, and splice the result into the list. + +<pre><code> +: '(a b c ~(list 'd 'e 'f) g h i) +-> (a b c d e f g h i) +</code></pre> + +<p>Brackets (<code>'['</code> and <code>']'</code>) can be used as super +parentheses. A closing bracket will match the innermost opening bracket, or all +currently open parentheses. + +<pre><code> +: '(a (b (c (d] +-> (a (b (c (d)))) +: '(a (b [c (d])) +-> (a (b (c (d)))) +</code></pre> + +<p>Finally, reading the sequence '<code>{}</code>' will result in a new +anonymous symbol with value <code>NIL</code>, equivalent to a call to <code><a +href="refB.html#box">box</a></code> without arguments. + +<pre><code> +: '({} {} {}) +-> ($134599965 $134599967 $134599969) +: (mapcar val @) +-> (NIL NIL NIL) +</code></pre> + + +<p><hr> +<h3><a name="ev">Evaluation</a></h3> + +<p>PicoLisp tries to evaluate any expression encountered in the read-eval-print +loop. Basically, it does so by applying the following three rules: + +<p><ul> +<li>A number evaluates to itself. + +<li>A symbol evaluates to its value (VAL). + +<li>A list is evaluated as a function call, with the CAR as the function and the +CDR the arguments to that function. These arguments are in turn evaluated +according to these three rules. + +</ul> + +<pre><code> +: 1234 +-> 1234 # Number evaluates to itself +: *Pid +-> 22972 # Symbol evaluates to its VAL +: (+ 1 2 3) +-> 6 # List is evaluated as a function call +</code></pre> + +<p>For the third rule, however, things get a bit more involved. First - as a +special case - if the CAR of the list is a number, the whole list is returned as +it is: + +<pre><code> +: (1 2 3 4 5 6) +-> (1 2 3 4 5 6) +</code></pre> + +<p>This is not really a function call but just a convenience to avoid having to +quote simple data lists. + +<p>Otherwise, if the CAR is a symbol or a list, PicoLisp tries to obtain an +executable function from that, by either using the symbol's value, or by +evaluating the list. + +<p>What is an executable function? Or, said in another way, what can be applied +to a list of arguments, to result in a function call? A legal function in +PicoLisp is + +<p><dl> +<dt>either +<dd>a <u>number</u>. When a number is used as a function, it is simply taken as +a pointer to executable code that will be called with the list of (unevaluated) +arguments as its single parameter. It is up to that code to evaluate the +arguments, or not. Some functions do not evaluate their arguments (e.g. +<code>quote</code>) or evaluate only some of their arguments (e.g. +<code>setq</code>). + +<dt>or +<dd>a <u>lambda expression</u>. A lambda expression is a list, whose CAR is +either a symbol or a list of symbols, and whose CDR is a list of expressions. +Note: In contrast to other Lisp implementations, the symbol LAMBDA itself does +not exist in PicoLisp but is implied from context. + +</dl> + +<p>A few examples should help to understand the practical consequences of these +rules. In the most common case, the CAR will be a symbol defined as a function, +like the <code>*</code> in: + +<pre><code> +: (* 1 2 3) # Call the function '*' +-> 6 +</code></pre> + +<p>Inspecting the VAL of <code>*</code>, however, gives + +<pre><code> +: * # Get the VAL of the symbol '*' +-> 67291944 +</code></pre> + +<p>The VAL of <code>*</code> is a number. In fact, it is the numeric +representation of a C-function pointer, i.e. a pointer to executable code. This +is the case for all built-in functions of PicoLisp. + +<p>Other functions in turn are written as Lisp expressions: + +<pre><code> +: (de foo (X Y) # Define the function 'foo' + (* (+ X Y) (+ X Y)) ) +-> foo +: (foo 2 3) # Call the function 'foo' +-> 25 +: foo # Get the VAL of the symbol 'foo' +-> ((X Y) (* (+ X Y) (+ X Y))) +</code></pre> + +<p>The VAL of <code>foo</code> is a list. It is the list that was assigned to +<code>foo</code> with the <code>de</code> function. It would be perfectly legal +to use <code>setq</code> instead of <code>de</code>: + +<pre><code> +: (setq foo '((X Y) (* (+ X Y) (+ X Y)))) +-> ((X Y) (* (+ X Y) (+ X Y))) +: (foo 2 3) +-> 25 +</code></pre> + +<p>If the VAL of <code>foo</code> were another symbol, that symbol's VAL would +be used instead to search for an executable function. + +<p>As we said above, if the CAR of the evaluated expression is not a symbol but +a list, that list is evaluated to obtain an executable function. + +<pre><code> +: ((intern (pack "c" "a" "r")) (1 2 3)) +-> 1 +</code></pre> + +<p>Here, the <code>intern</code> function returns the symbol <code>car</code> +whose VAL is used then. It is also legal, though quite dangerous, to use the +code-pointer directly: + +<pre><code> +: car +-> 67306152 +: ((* 2 33653076) (1 2 3)) +-> 1 +</code></pre> + +<p>When an executable function is defined in Lisp itself, we call it a <a +name="lambda"><u>lambda expression</u></a>. A lambda expression always has a +list of executable expressions as its CDR. The CAR, however, must be a either a +list of symbols, or a single symbol, and it controls the evaluation of the +arguments to the executable function according to the following rules: + +<p><dl> + +<dt>When the CAR is a list of symbols +<dd>For each of these symbols an argument is evaluated, then the symbols are +bound simultaneously to the results. The body of the lambda expression is +executed, then the VAL's of the symbols are restored to their original values. +This is the most common case, a fixed number of arguments is passed to the +function. + +<dt>Otherwise, when the CAR is the symbol <code>@</code> +<dd>All arguments are evaluated and the results kept internally in a list. The +body of the lambda expression is executed, and the evaluated arguments can be +accessed sequentially with the <code><a href="refA.html#args">args</a></code>, +<code><a href="refN.html#next">next</a></code>, <code><a +href="refA.html#arg">arg</a></code> and <code><a +href="refR.html#rest">rest</a></code> functions. This allows to define functions +with a variable number of evaluated arguments. + +<dt>Otherwise, when the CAR is a single symbol +<dd>The symbol is bound to the whole unevaluated argument list. The body of the +lambda expression is executed, then the symbol is restored to its original +value. This allows to define functions with unevaluated arguments. Any kind of +interpretation and evaluation of the argument list can be done inside the +expression body. + +</dl> + +<p>In all cases, the return value is the result of the last expression in the +body. + +<pre><code> +: (de foo (X Y Z) # CAR is a list of symbols + (list X Y Z) ) # Return a list of all arguments +-> foo +: (foo (+ 1 2) (+ 3 4) (+ 5 6)) +-> (3 7 11) # all arguments are evaluated +</code></pre> + +<pre><code> +: (de foo X # CAR is a single symbol + X ) # Return the argument +-> foo +: (foo (+ 1 2) (+ 3 4) (+ 5 6)) +-> ((+ 1 2) (+ 3 4) (+ 5 6)) # the whole unevaluated list is returned +</code></pre> + +<pre><code> +: (de foo @ # CAR is the symbol '@' + (list (next) (next) (next)) ) # Return the first three arguments +-> foo +: (foo (+ 1 2) (+ 3 4) (+ 5 6)) +-> (3 7 11) # all arguments are evaluated +</code></pre> + +<p>Note that these forms can also be combined. For example, to evaluate only the +first two arguments, bind the results to <code>X</code> and <code>Y</code>, and +bind all other arguments (unevaluated) to <code>Z</code>: + +<pre><code> +: (de foo (X Y . Z) # CAR is a list with a dotted-pair tail + (list X Y Z) ) # Return a list of all arguments +-> foo +: (foo (+ 1 2) (+ 3 4) (+ 5 6)) +-> (3 7 ((+ 5 6))) # two arguments are evaluated +</code></pre> + +<p>Or, a single argument followed by a variable number of arguments: + +<pre><code> +: (de foo (X . @) # CAR is a dotted-pair with '@' + (println X) # print the first evaluated argument + (while (args) # while there are more arguments + (println (next)) ) ) # print the next one +-> foo +: (foo (+ 1 2) (+ 3 4) (+ 5 6)) +3 # X +7 # Next arg +11 +-> 11 +</code></pre> + +<p>In general, if more than the expected number of arguments is supplied to a +function, these extra arguments will be ignored. Missing arguments default to +<code>NIL</code>. + + +<p><hr> +<h3><a name="int">Interrupt</a></h3> + +<p>During the evaluation of an expression, the PicoLisp interpreter can be +interrupted at any time by hitting <code>Ctrl-C</code>. It will then enter the +breakpoint routine, as if <code><a href="ref_.html#!">!</a></code> were called. + +<p>Hitting ENTER at that point will continue evaluation, while <code>(<a +href="refQ.html#quit">quit</a>)</code> will abort evaluation and return the +interpreter to the top level. See also <code><a +href="refD.html#debug">debug</a></code>, <code><a +href="refE.html#e">e</a></code>, <code><a href="ref_.html#^">^</a></code> and +<code><a href="refD.html#*Dbg">*Dbg</a></code> + + +<p><hr> +<h3><a name="errors">Error Handling</a></h3> + +<p>When a runtime error occurs, execution is stopped and an error handler is +entered. + +<p>The error handler resets the I/O channels to the console, and displays the +location (if possible) and the reason of the error, followed by an error +message. That message is also stored in the global <code><a +href="refM.html#*Msg">*Msg</a></code>, and the location of the error in <code><a +href="ref_.html#^">^</a></code>. If the VAL of the global <code><a +href="refE.html#*Err">*Err</a></code> is non-<code>NIL</code> it is executed as +a <code>prg</code> body. If the standard input is from a terminal, a +read-eval-print loop (with a question mark "<code>?</code>" as prompt) is +entered (the loop is exited when an empty line is input). Then all pending +<code><a href="refF.html#finally">finally</a></code> expressions are executed, +all variable bindings restored, and all files closed. If the standard input is +not from a terminal, the interpreter terminates. Otherwise it is reset to its +top-level state. + +<pre><code> +: (de foo (A B) (badFoo A B)) # 'foo' calls an undefined symbol +-> foo +: (foo 3 4) # Call 'foo' +!? (badFoo A B) # Error handler entered +badFoo -- Undefined +? A # Inspect 'A' +-> 3 +? B # Inspect 'B' +-> 4 +? # Empty line: Exit +: +</code></pre> + +<p>Errors can be caught with <code><a href="refC.html#catch">catch</a></code>, +if a list of substrings of possible error messages is supplied for the first +argument. In such a case, the matching substring (or the whole error message if +the substring is <code>NIL</code>) is returned. + + +<p><hr> +<h3><a name="atres">@ Result</a></h3> + +<p>In certain situations, the result of the last evaluation is stored in the VAL +of the symbol <code>@</code>. This can be very convenient, because it often +makes the assignment to temporary variables unnecessary. + +<p><dl> + +<dt><code><a href="refL.html#load">load</a></code> +<dd>In read-eval loops, the last three results which were printed at the console +are available in <code>@@@</code>, <code>@@</code> and <code>@</code>, in that +order (i.e the latest result is in <code>@</code>). + +<pre><code> +: (+ 1 2 3) +-> 6 +: (/ 128 4) +-> 32 +: (- @ @@) # Subtract the last two results +-> 26 +</code></pre> + +<p><dt>Flow functions +<dd>Flow- and logic-functions store the result of their controlling expression - +respectively non-<code>NIL</code> results of their conditional expression - in +<code>@</code>. + +<pre><code> +: (while (read) (println 'got: @)) +abc # User input +got: abc # print result +123 # User input +got: 123 # print result +NIL +-> 123 + +: (setq L (1 2 3 4 5 1 2 3 4 5)) +-> (1 2 3 4 5 1 2 3 4 5) +: (and (member 3 L) (member 3 (cdr @)) (set @ 999)) +-> 999 +: L +-> (1 2 3 4 5 1 2 999 4 5) +</code></pre> + +<p>Functions with controlling expressions are + <a href="refC.html#case">case</a>, + <a href="refP.html#prog1">prog1</a>, + <a href="refP.html#prog2">prog2</a>, +and the bodies of <code><a href="refR.html#*Run">*Run</a></code> tasks. + +<p>Functions with conditional expressions are + <a href="refA.html#and">and</a>, + <a href="refC.html#cond">cond</a>, + <a href="refD.html#do">do</a>, + <a href="refF.html#for">for</a>, + <a href="refI.html#if">if</a>, + <a href="refI.html#if2">if2</a>, + <a href="refI.html#ifn">ifn</a>, + <a href="refL.html#loop">loop</a>, + <a href="refN.html#nand">nand</a>, + <a href="refN.html#nond">nond</a>, + <a href="refN.html#nor">nor</a>, + <a href="refN.html#not">not</a>, + <a href="refO.html#or">or</a>, + <a href="refS.html#state">state</a>, + <a href="refU.html#unless">unless</a>, + <a href="refU.html#until">until</a>, + <a href="refW.html#when">when</a> and + <a href="refW.html#while">while</a>. + +</dl> + +<p><code>@</code> is generally local to functions and methods, its value is +automatically saved upon function entry and restored at exit. + + +<p><hr> +<h3><a name="cmp">Comparing</a></h3> + +<p>In PicoLisp, it is legal to compare data items of arbitrary type. Any two +items are either + +<p><dl> + +<dt>Identical +<dd>They are the same memory object (pointer equality). For example, two +internal symbols with the same name are identical. In the 64-bit version, also +short numbers (up to 60 bits) are pointer-equal. + +<dt>Equal +<dd>They are equal in every respect (structure equality), but need not to be +identical. Examples are numbers with the same value, transient symbols with the +same name or lists with equal elements. + +<dt>Or they have a well-defined ordinal relationship +<dd>Numbers are comparable by their numeric value, strings by their name, and +lists recursively by their elements (if the CAR's are equal, their CDR's are +compared). For differing types, the following rule applies: Numbers are less +than symbols, and symbols are less than lists. As special cases, +<code>NIL</code> is always less than anything else, and <code>T</code> is always +greater than anything else. + +</dl> + +<p>To demonstrate this, <code><a href="refS.html#sort">sort</a></code> a list of +mixed data types: + +<pre><code> +: (sort '("abc" T (d e f) NIL 123 DEF)) +-> (NIL 123 DEF "abc" (d e f) T) +</code></pre> + +<p>See also <code><a href="refM.html#max">max</a></code>, <code><a +href="refM.html#min">min</a></code>, <code><a +href="refR.html#rank">rank</a></code>, <code><a href="ref_.html#<"><</a></code>, +<code><a href="ref_.html#=">=</a></code>, <code><a +href="ref_.html#>">></a></code> etc. + + +<p><hr> +<h3><a name="oop">OO Concepts</a></h3> + +<p>PicoLisp comes with built-in object oriented extensions. There seems to be a +common agreement upon three criteria for object orientation: + +<p><dl> +<dt>Encapsulation +<dd>Code and data are encapsulated into <u>objects</u>, giving them both a +<u>behavior</u> and a <u>state</u>. Objects communicate by sending and receiving +<u>messages</u>. + +<dt>Inheritance +<dd>Objects are organized into <u>classes</u>. The behavior of an object is +inherited from its class(es) and superclass(es). + +<dt>Polymorphism +<dd>Objects of different classes may behave differently in response to the same +message. For that, classes may define different methods for each message. + +</dl> + +<p>PicoLisp implements both objects and classes with symbols. Object-local data +are stored in the symbol's property list, while the code (methods) and links to +the superclasses are stored in the symbol's VAL (encapsulation). + +<p>In fact, there is no formal difference between objects and classes (except +that objects usually are anonymous symbols containing mostly local data, while +classes are named internal symbols with an emphasis on method definitions). At +any time, a class may be assigned its own local data (class variables), and any +object can receive individual method definitions in addition to (or overriding) +those inherited from its (super)classes. + +<p>PicoLisp supports multiple inheritance. The VAL of each object is a (possibly +empty) association list of message symbols and method bodies, concatenated with +a list of classes. When a message is sent to an object, it is searched in the +object's own method list, and then (with a left-to-right depth-first search) in +the tree of its classes and superclasses. The first method found is executed and +the search stops. The search may be explicitly continued with the <code><a +href="refE.html#extra">extra</a></code> and <code><a +href="refS.html#super">super</a></code> functions. + +<p>Thus, which method is actually executed when a message is sent to an object +depends on the classes that the object is currently linked to (polymorphism). As +the method search is fully dynamic (late binding), an object's type (i.e. its +classes and method definitions) can be changed even at runtime! + +<p>While a method body is being executed, the global variable <code><a +href="refT.html#This">This</a></code> is set to the current object, allowing +the use of the short-cut property functions <code><a +href="ref_.html#=:">=:</a></code>, <code><a href="ref_.html#:">:</a></code> +and <code><a href="ref_.html#::">::</a></code>. + + +<p><hr> +<h3><a name="dbase">Database</a></h3> + +<p>On the lowest level, a PicoLisp database is just a collection of <a +href="#external">external symbols</a>. They reside in a database file, and are +dynamically swapped in and out of memory. Only one database can be open at a +time (<code><a href="refP.html#pool">pool</a></code>). + +<p>In addition, further external symbols can be specified to originate from +arbitrary sources via the <code><a href="refE.html#*Ext">*Ext</a></code> +mechanism. + +<p>Whenever an external symbol's value or property list is accessed, it will be +automatically fetched into memory, and can then be used like any other symbol. +Modifications will be written to disk only when <code><a +href="refC.html#commit">commit</a></code> is called. Alternatively, all +modifications since the last call to <code>commit</code> can be discarded by +calling <code><a href="refR.html#rollback">rollback</a></code>. + +<p><hr> +<h4><a name="trans">Transactions</a></h4> + +<p>In the typical case there will be multiple processes operating on the same +database. These processes should be all children of the same parent process, +which takes care of synchronizing read/write operations and heap contents. Then +a database transaction is normally initiated by calling <code>(<a +href="refD.html#dbSync">dbSync</a>)</code>, and closed by calling <code>(<a +href="refC.html#commit">commit</a> 'upd)</code>. Short transactions, involving +only a single DB operation, are available in functions like <code><a +href="refN.html#new!">new!</a></code> and methods like <code><a +href="refE.html#entityMesssages">put!></a></code> (by convention with an +exclamation mark), which implicitly call <code>(dbSync)</code> and <code>(commit +'upd)</code> themselves. + +<p>A transaction proceeds through five phases: + +<p><ol> +<li><code><a href="refD.html#dbSync">dbSync</a></code> waits to get a <code><a +href="refL.html#lock">lock</a></code> on the root object <code><a +href="refD.html#*DB">*DB</a></code>. Other processes continue reading and +writing meanwhile. + +<li><code><a href="refD.html#dbSync">dbSync</a></code> calls <code><a +href="refS.html#sync">sync</a></code> to synchronize with changes from other +processes. We hold the shared lock, but other processes may continue reading. + +<li>We make modifications to the internal state of external symbols with +<code><a href="refE.html#entityMesssages">put>, set>, lose></a></code> etc. We - +and also other processes - can still read the DB. + +<li>We call <code>(<a href="refC.html#commit">commit</a> 'upd)</code>. +<code>commit</code> obtains an exclusive lock (no more read operations by other +processes), writes an optional transaction log, and then all modified symbols. +As <code><a href="refU.html#upd">upd</a></code> is passed to 'commit', other +processes synchronize with these changes. + +<li>Finally, all locks are released by 'commit' + +</ol> + +<p><hr> +<h4><a name="er">Entities / Relations</a></h4> + +<p>The symbols in a database can be used to store arbitrary information +structures. In typical use, some symbols represent nodes of search trees, by +holding keys, values, and links to subtrees in their VAL's. Such a search tree +in the database is called <u>index</u>. + +<p>For the most part, other symbols in the database are objects derived from the +<code><a href="refE.html#+Entity">+Entity</a></code> class. + +<p>Entities depend on objects of the <code><a +href="refR.html#+relation">+relation</a></code> class hierarchy. +Relation-objects manage the property values of entities, they define the +application database model and are responsible for the integrity of mutual +object references and index trees. + +<p>Relations are stored as properties in the entity classes, their methods are +invoked as daemons whenever property values in an entity are changed. When +defining an <code><a href="refE.html#+Entity">+Entity</a></code> class, relations are defined - in addition to +the method definitions of a normal class - with the <code><a +href="refR.html#rel">rel</a></code> function. Predefined relation classes +include + +<p><ul> +<li>Primitive types like + <dl> + <dt><code><a href="refS.html#+Symbol">+Symbol</a></code> + <dd>Symbolic data + <dt><code><a href="refS.html#+String">+String</a></code> + <dd>Strings (just a general case of symbols) + <dt><code><a href="refN.html#+Number">+Number</a></code> + <dd>Integers and fixed-point numbers + <dt><code><a href="refD.html#+Date">+Date</a></code> + <dd>Calendar date values, represented by a number + <dt><code><a href="refT.html#+Time">+Time</a></code> + <dd>Time-of-the-day values, represented by a number + <dt><code><a href="refB.html#+Blob">+Blob</a></code> + <dd>"Binary large objects" stored in separate files + </dl> +<li>Object-to-object relations + <dl> + <dt><code><a href="refL.html#+Link">+Link</a></code> + <dd>A reference to some other entity + <dt><code><a href="refH.html#+Hook">+Hook</a></code> + <dd>A reference to an entity holding object-local index trees + <dt><code><a href="refJ.html#+Joint">+Joint</a></code> + <dd>A bi-directional reference to some other entity + </dl> +<li>Container prefix classes like + <dl> + <dt><code><a href="refL.html#+List">+List</a></code> + <dd>A list of any of the other primitive or object relation types + <dt><code><a href="refB.html#+Bag">+Bag</a></code> + <dd>A list containing a mixture of any of the other types + </dl> +<li>Index prefix classes + <dl> + <dt><code><a href="refR.html#+Ref">+Ref</a></code> + <dd>An index with other primitives or entities as key + <dt><code><a href="refK.html#+Key">+Key</a></code> + <dd>A unique index with other primitives or entities as key + <dt><code><a href="refI.html#+Idx">+Idx</a></code> + <dd>A full-text index, typically for strings + <dt><code><a href="refS.html#+Sn">+Sn</a></code> + <dd>Tolerant index, using a modified Soundex-Algorithm + </dl> +<li>Booleans + <dl> + <dt><code><a href="refB.html#+Bool">+Bool</a></code> + <dd><code>T</code> or <code>NIL</code> + </dl> +<li>And a catch-all class + <dl> + <dt><code><a href="refA.html#+Any">+Any</a></code> + <dd>Not specified, may be any of the above relations + </dl> +</ul> + + +<p><hr> +<h3><a name="pilog">Pilog (PicoLisp Prolog)</a></h3> + +<p>A declarative language is built on top of PicoLisp, that has the semantics of +Prolog, but uses the syntax of Lisp. + +<p>For an explanation of Prolog's declarative programming style, an introduction +like "Programming in Prolog" by Clocksin/Mellish (Springer-Verlag 1981) is +recommended. + +<p>Facts and rules can be declared with the <code><a +href="refB.html#be">be</a></code> function. For example, a Prolog fact +'<code>likes(john,mary).</code>' is written in Pilog as: + +<pre><code> +(be likes (John Mary)) +</code></pre> + +<p>and a rule '<code>likes(john,X) :- likes(X,wine), likes(X,food).</code>' is +in Pilog: + +<pre><code> +(be likes (John @X) (likes @X wine) (likes @X food)) +</code></pre> + +<p>As in Prolog, the difference between facts and rules is that the latter ones +have conditions, and usually contain variables. + +<p>A variable in Pilog is any symbol starting with an at-mark character +("<code>@</code>"). The symbol <code>@</code> itself can be used as an anonymous +variable: It will match during unification, but will not be bound to the matched +values. + +<p>The <i>cut</i> operator of Prolog (usually written as an exclamation mark +(<code>!</code>)) is the symbol <code>T</code> in Pilog. + +<p>An interactive query can be done with the <code><a +href="ref_.html#?">?</a></code> function: + +<pre><code> +(? (likes John @X)) +</code></pre> + +<p>This will print all solutions, waiting for user input after each line. If a +non-empty line (not just a ENTER key, but for example a dot (<code>.</code>) +followed by ENTER) is typed, it will terminate. + +<p>Pilog can be called from Lisp and vice versa: + +<ul> + +<li>The interface from Lisp is via the functions <code><a +href="refG.html#goal">goal</a></code> (prepare a query from Lisp data) and +<code><a href="refP.html#prove">prove</a></code> (return an association list of +successful bindings), and the application level functions <code><a +href="refP.html#pilog">pilog</a></code> and <code><a +href="refS.html#solve">solve</a></code>. + +<li>When the CAR of a Pilog clause is a Pilog variable, the CDR is executed as a +Lisp expression and the result unified with that variable. + +<li>Within such a Lisp expression in a Pilog clause, the current bindings of +Pilog variables can be accessed with the <code><a +href="ref_.html#->">-&gt</a></code> function. + +</ul> + +<p><hr> +<h3><a name="conv">Naming Conventions</a></h3> + +<p>It was necessary to introduce - and adhere to - a set of conventions for +PicoLisp symbol names. Because all (internal) symbols have a global scope (there +are no packages or name spaces), and each symbol can only have either a value or +function definition, it would otherwise be very easy to introduce name +conflicts. Besides this, source code readability is increased when the scope of +a symbol is indicated by its name. + +<p>These conventions are not hard-coded into the language, but should be so into +the head of the programmer. Here are the most commonly used ones: + +<p><ul> +<li>Global variables start with an asterisk "<code>*</code>" +<li>Functions and other global symbols start with a lower case letter +<li>Locally bound symbols start with an upper case letter +<li>Local functions start with an underscore "<code>_</code>" +<li>Classes start with a plus-sign "<code>+</code>", where the first letter + <ul> + <li>is in lower case for abstract classes + <li>and in upper case for normal classes + </ul> +<li>Methods end with a right arrow "<code>></code>" +<li>Class variables may be indicated by an upper case letter +</ul> + +<p>For historical reasons, the global constant symbols <code>T</code> and +<code>NIL</code> do not obey these rules, and are written in upper case. + +<p>For example, a local variable could easily overshadow a function definition: + +<pre><code> +: (de max-speed (car) + (.. (get car 'speeds) ..) ) +-> max-speed +</code></pre> + +<p>Inside the body of <code>max-speed</code> (and all other functions called +during that execution) the kernel function <code>car</code> is redefined to some +other value, and will surely crash if something like <code>(car Lst)</code> is +executed. Instead, it is safe to write: + +<pre><code> +: (de max-speed (Car) # 'Car' with upper case first letter + (.. (get Car 'speeds) ..) ) +-> max-speed +</code></pre> + +<p>Note that there are also some strict naming rules (as opposed to the +voluntary conventions) that are required by the corresponding kernel +functionalities, like: + +<p><ul> +<li>Transient symbols are enclosed in double quotes (see <a +href="#transient-io">Transient Symbols</a>) <li>External symbols are enclosed in +braces (see <a href="#external-io">External Symbols</a>) <li>Pattern-Wildcards +start with an at-mark "<code>@</code>" (see <a href="refM.html#match">match</a> +and <a href="refF.html#fill">fill</a>) <li>Symbols referring to a shared library +contain a colon "<code>lib:sym</code>" </ul> + +<p>With that, the last of the above conventions (local functions start with an +underscore) is not really necessary, because true local scope can be enforced +with transient symbols. + + +<p><hr> +<h3><a name="trad">Breaking Traditions</a></h3> + +<p>PicoLisp does not try very hard to be compatible with traditional Lisp +systems. If you are used to some other Lisp dialects, you may notice the +following differences: + +<p><dl> + +<dt>Case Sensitivity +<dd>PicoLisp distinguishes between upper case and lower case characters in +symbol names. Thus, <code>CAR</code> and <code>car</code> are different symbols, +which was not the case in traditional Lisp systems. + +<dt><code>QUOTE</code> +<dd>In traditional Lisp, the <code>QUOTE</code> function returns its +<i>first</i> unevaluated argument. In PicoLisp, on the other hand, +<code>quote</code> returns <i>all</i> (unevaluated) argument(s). + +<dt><code>LAMBDA</code> +<dd>The <code>LAMBDA</code> function, in some way at the heart of traditional +Lisp, is completely missing (and <code>quote</code> is used instead). + +<dt><code>PROG</code> +<dd>The <code>PROG</code> function of traditional Lisp, with its GOTO and ENTER +functionality, is also missing. PicoLisp's <code>prog</code> function is just a +simple sequencer (as <code>PROGN</code> in some Lisps). + +<dt>Function/Value +<dd>In PicoLisp, a symbol cannot have a value <i>and</i> a function definition +at the same time. Though this is a disadvantage at first sight, it allows a +completely uniform handling of functional data. + +</dl> + + +<p><hr> +<h3><a name="bugs">Bugs</a></h3> + +<p>The names of the symbols <code>T</code> and <code>NIL</code> violate the <a +href="#conv">naming conventions</a>. They are global symbols, and should +therefore start with an asterisk "<code>*</code>". It is too easy to bind them +to some other value by mistake: + +<pre><code> +(de foo (R S T) + ... +</code></pre> + +<p>However, <code><a href="refL.html#lint">lint</a></code> will issue a warning +in such a case. + + +<p><hr> +<h2><a name="fun">Function Reference</a></h2> + +<p>This section provides a reference manual for the kernel functions, and some +extensions. See the thematically grouped list of indexes below. + +<p>Though PicoLisp is a dynamically typed language (resolved at runtime, as +opposed to statically (compile-time) typed languages), many functions can only +accept and/or return a certain set of data types. For each function, the +expected argument types and return values are described with the following +abbreviations: + +<p>The primary data types: + +<p><ul> +<li><code>num</code> - Number +<li><code>sym</code> - Symbol +<li><code>lst</code> - List +</ul> + +<p>Other (derived) data types + +<p><ul> +<li><code>any</code> - Anything: Any primary data type +<li><code>flg</code> - Flag: Boolean value (<code>NIL</code> or non-<code>NIL</code>) +<li><code>cnt</code> - A count or a small number +<li><code>dat</code> - Date: Days since first of March, in the year 0 A.D. +<li><code>tim</code> - Time: Seconds since midnight +<li><code>obj</code> - Object/Class: A symbol with methods and/or classes +<li><code>var</code> - Variable: Either a symbol or a cell +<li><code>exe</code> - Executable: A list as executable expression (<code>eval</code>) +<li><code>prg</code> - Prog-Body: A list of executable expressions (<code>run</code>) +<li><code>fun</code> - Function: Either a number (code-pointer), a symbol (message) or a list (lambda) +<li><code>msg</code> - Message: A symbol sent to an object (to invoke a method) +<li><code>cls</code> - Class: A symbol defined as an object's class +<li><code>typ</code> - Type: A list of <code>cls</code> symbols +<li><code>pat</code> - Pattern: A symbol whose name starts with an at-mark "<code>@</code>" +<li><code>pid</code> - Process ID: A number, the ID of a Unix process +<li><code>tree</code> - Database index tree specification +<li><code>hook</code> - Database hook object +</ul> + +<p> +<a href="refA.html">A</a> +<a href="refB.html">B</a> +<a href="refC.html">C</a> +<a href="refD.html">D</a> +<a href="refE.html">E</a> +<a href="refF.html">F</a> +<a href="refG.html">G</a> +<a href="refH.html">H</a> +<a href="refI.html">I</a> +<a href="refJ.html">J</a> +<a href="refK.html">K</a> +<a href="refL.html">L</a> +<a href="refM.html">M</a> +<a href="refN.html">N</a> +<a href="refO.html">O</a> +<a href="refP.html">P</a> +<a href="refQ.html">Q</a> +<a href="refR.html">R</a> +<a href="refS.html">S</a> +<a href="refT.html">T</a> +<a href="refU.html">U</a> +<a href="refV.html">V</a> +<a href="refW.html">W</a> +<a href="refX.html">X</a> +<a href="refY.html">Y</a> +<a href="refZ.html">Z</a> +<a href="ref_.html">Other</a> + +<p><dl> + +<dt>Symbol Functions +<dd><code> + <a href="refN.html#new">new</a> + <a href="refS.html#sym">sym</a> + <a href="refS.html#str">str</a> + <a href="refC.html#char">char</a> + <a href="refN.html#name">name</a> + <a href="refS.html#sp?">sp?</a> + <a href="refP.html#pat?">pat?</a> + <a href="refF.html#fun?">fun?</a> + <a href="refA.html#all">all</a> + <a href="refI.html#intern">intern</a> + <a href="refE.html#extern">extern</a> + <a href="ref_.html#====">====</a> + <a href="refQ.html#qsym">qsym</a> + <a href="refL.html#loc">loc</a> + <a href="refB.html#box?">box?</a> + <a href="refS.html#str?">str?</a> + <a href="refE.html#ext?">ext?</a> + <a href="refT.html#touch">touch</a> + <a href="refZ.html#zap">zap</a> + <a href="refL.html#length">length</a> + <a href="refS.html#size">size</a> + <a href="refF.html#format">format</a> + <a href="refC.html#chop">chop</a> + <a href="refP.html#pack">pack</a> + <a href="refG.html#glue">glue</a> + <a href="refP.html#pad">pad</a> + <a href="refA.html#align">align</a> + <a href="refC.html#center">center</a> + <a href="refT.html#text">text</a> + <a href="refW.html#wrap">wrap</a> + <a href="refP.html#pre?">pre?</a> + <a href="refS.html#sub?">sub?</a> + <a href="refL.html#low?">low?</a> + <a href="refU.html#upp?">upp?</a> + <a href="refL.html#lowc">lowc</a> + <a href="refU.html#uppc">uppc</a> + <a href="refF.html#fold">fold</a> + <a href="refV.html#val">val</a> + <a href="refG.html#getd">getd</a> + <a href="refS.html#set">set</a> + <a href="refS.html#setq">setq</a> + <a href="refD.html#def">def</a> + <a href="refD.html#de">de</a> + <a href="refD.html#dm">dm</a> + <a href="refR.html#recur">recur</a> + <a href="refU.html#undef">undef</a> + <a href="refR.html#redef">redef</a> + <a href="refD.html#daemon">daemon</a> + <a href="refP.html#patch">patch</a> + <a href="refX.html#xchg">xchg</a> + <a href="refO.html#on">on</a> + <a href="refO.html#off">off</a> + <a href="refO.html#onOff">onOff</a> + <a href="refZ.html#zero">zero</a> + <a href="refO.html#one">one</a> + <a href="refD.html#default">default</a> + <a href="refE.html#expr">expr</a> + <a href="refS.html#subr">subr</a> + <a href="refL.html#let">let</a> + <a href="refL.html#let?">let?</a> + <a href="refU.html#use">use</a> + <a href="refA.html#accu">accu</a> + <a href="refP.html#push">push</a> + <a href="refP.html#push1">push1</a> + <a href="refP.html#pop">pop</a> + <a href="refC.html#cut">cut</a> + <a href="refD.html#del">del</a> + <a href="refQ.html#queue">queue</a> + <a href="refF.html#fifo">fifo</a> + <a href="refI.html#idx">idx</a> + <a href="refL.html#lup">lup</a> + <a href="refC.html#cache">cache</a> + <a href="refL.html#locale">locale</a> + <a href="refD.html#dirname">dirname</a> +</code> + +<dt>Property Access +<dd><code> + <a href="refP.html#put">put</a> + <a href="refG.html#get">get</a> + <a href="refP.html#prop">prop</a> + <a href="ref_.html#;">;</a> + <a href="ref_.html#=:">=:</a> + <a href="ref_.html#:">:</a> + <a href="ref_.html#::">::</a> + <a href="refP.html#putl">putl</a> + <a href="refG.html#getl">getl</a> + <a href="refW.html#wipe">wipe</a> + <a href="refM.html#meta">meta</a> +</code> + +<dt>Predicates +<dd><code> + <a href="refA.html#atom">atom</a> + <a href="refP.html#pair">pair</a> + <a href="refL.html#lst?">lst?</a> + <a href="refN.html#num?">num?</a> + <a href="refS.html#sym?">sym?</a> + <a href="refF.html#flg?">flg?</a> + <a href="refS.html#sp?">sp?</a> + <a href="refP.html#pat?">pat?</a> + <a href="refF.html#fun?">fun?</a> + <a href="refB.html#box?">box?</a> + <a href="refS.html#str?">str?</a> + <a href="refE.html#ext?">ext?</a> + <a href="refB.html#bool">bool</a> + <a href="refN.html#not">not</a> + <a href="ref_.html#==">==</a> + <a href="refN.html#n==">n==</a> + <a href="ref_.html#=">=</a> + <a href="ref_.html#<>"><&gt</a> + <a href="ref_.html#=0">=0</a> + <a href="ref_.html#=T">=T</a> + <a href="refN.html#n0">n0</a> + <a href="refN.html#nT">nT</a> + <a href="ref_.html#<">&lt;</a> + <a href="ref_.html#<=">&lt;=</a> + <a href="ref_.html#>">&gt;</a> + <a href="ref_.html#>=">&gt;=</a> + <a href="refM.html#match">match</a> +</code> + +<dt>Arithmetics +<dd><code> + <a href="ref_.html#+">+</a> + <a href="ref_.html#-">-</a> + <a href="ref_.html#*">*</a> + <a href="ref_.html#/">/</a> + <a href="ref_.html#%">%</a> + <a href="ref_.html#*/">*/</a> + <a href="ref_.html#**">**</a> + <a href="refI.html#inc">inc</a> + <a href="refD.html#dec">dec</a> + <a href="ref_.html#>>">>></a> + <a href="refL.html#lt0">lt0</a> + <a href="refG.html#ge0">ge0</a> + <a href="refG.html#gt0">gt0</a> + <a href="refA.html#abs">abs</a> + <a href="refB.html#bit?">bit?</a> + <a href="ref_.html#&">&</a> + <a href="ref_.html#|">|</a> + <a href="refX.html#x|">x|</a> + <a href="refS.html#sqrt">sqrt</a> + <a href="refS.html#seed">seed</a> + <a href="refR.html#rand">rand</a> + <a href="refM.html#max">max</a> + <a href="refM.html#min">min</a> + <a href="refL.html#length">length</a> + <a href="refS.html#size">size</a> + <a href="refA.html#accu">accu</a> + <a href="refF.html#format">format</a> + <a href="refP.html#pad">pad</a> + <a href="refO.html#oct">oct</a> + <a href="refH.html#hex">hex</a> + <a href="refF.html#fmt64">fmt64</a> + <a href="refM.html#money">money</a> +</code> + +<dt>List Processing +<dd><code> + <a href="refC.html#car">car</a> + <a href="refC.html#cdr">cdr</a> + <a href="refC.html#caar">caar</a> + <a href="refC.html#cadr">cadr</a> + <a href="refC.html#cdar">cdar</a> + <a href="refC.html#cddr">cddr</a> + <a href="refC.html#caaar">caaar</a> + <a href="refC.html#caadr">caadr</a> + <a href="refC.html#cadar">cadar</a> + <a href="refC.html#caddr">caddr</a> + <a href="refC.html#cdaar">cdaar</a> + <a href="refC.html#cdadr">cdadr</a> + <a href="refC.html#cddar">cddar</a> + <a href="refC.html#cdddr">cdddr</a> + <a href="refC.html#cadddr">cadddr</a> + <a href="refC.html#cddddr">cddddr</a> + <a href="refN.html#nth">nth</a> + <a href="refC.html#con">con</a> + <a href="refC.html#cons">cons</a> + <a href="refC.html#conc">conc</a> + <a href="refC.html#circ">circ</a> + <a href="refR.html#rot">rot</a> + <a href="refL.html#list">list</a> + <a href="refN.html#need">need</a> + <a href="refR.html#range">range</a> + <a href="refF.html#full">full</a> + <a href="refM.html#make">make</a> + <a href="refM.html#made">made</a> + <a href="refC.html#chain">chain</a> + <a href="refL.html#link">link</a> + <a href="refY.html#yoke">yoke</a> + <a href="refC.html#copy">copy</a> + <a href="refM.html#mix">mix</a> + <a href="refA.html#append">append</a> + <a href="refD.html#delete">delete</a> + <a href="refD.html#delq">delq</a> + <a href="refR.html#replace">replace</a> + <a href="refI.html#insert">insert</a> + <a href="refR.html#remove">remove</a> + <a href="refP.html#place">place</a> + <a href="refS.html#strip">strip</a> + <a href="refS.html#split">split</a> + <a href="refR.html#reverse">reverse</a> + <a href="refF.html#flip">flip</a> + <a href="refT.html#trim">trim</a> + <a href="refC.html#clip">clip</a> + <a href="refH.html#head">head</a> + <a href="refT.html#tail">tail</a> + <a href="refS.html#stem">stem</a> + <a href="refF.html#fin">fin</a> + <a href="refL.html#last">last</a> + <a href="refM.html#member">member</a> + <a href="refM.html#memq">memq</a> + <a href="refM.html#mmeq">mmeq</a> + <a href="refS.html#sect">sect</a> + <a href="refD.html#diff">diff</a> + <a href="refI.html#index">index</a> + <a href="refO.html#offset">offset</a> + <a href="refA.html#assoc">assoc</a> + <a href="refA.html#asoq">asoq</a> + <a href="refR.html#rank">rank</a> + <a href="refS.html#sort">sort</a> + <a href="refU.html#uniq">uniq</a> + <a href="refG.html#group">group</a> + <a href="refL.html#length">length</a> + <a href="refS.html#size">size</a> + <a href="refV.html#val">val</a> + <a href="refS.html#set">set</a> + <a href="refX.html#xchg">xchg</a> + <a href="refP.html#push">push</a> + <a href="refP.html#push1">push1</a> + <a href="refP.html#pop">pop</a> + <a href="refC.html#cut">cut</a> + <a href="refQ.html#queue">queue</a> + <a href="refF.html#fifo">fifo</a> + <a href="refI.html#idx">idx</a> + <a href="refB.html#balance">balance</a> + <a href="refG.html#get">get</a> + <a href="refF.html#fill">fill</a> + <a href="refA.html#apply">apply</a> +</code> + +<dt>Control Flow +<dd><code> + <a href="refL.html#load">load</a> + <a href="refA.html#args">args</a> + <a href="refN.html#next">next</a> + <a href="refA.html#arg">arg</a> + <a href="refR.html#rest">rest</a> + <a href="refP.html#pass">pass</a> + <a href="refQ.html#quote">quote</a> + <a href="refA.html#as">as</a> + <a href="refP.html#pid">pid</a> + <a href="refL.html#lit">lit</a> + <a href="refE.html#eval">eval</a> + <a href="refR.html#run">run</a> + <a href="refM.html#macro">macro</a> + <a href="refC.html#curry">curry</a> + <a href="refD.html#def">def</a> + <a href="refD.html#de">de</a> + <a href="refD.html#dm">dm</a> + <a href="refR.html#recur">recur</a> + <a href="refR.html#recurse">recurse</a> + <a href="refU.html#undef">undef</a> + <a href="refB.html#box">box</a> + <a href="refN.html#new">new</a> + <a href="refT.html#type">type</a> + <a href="refI.html#isa">isa</a> + <a href="refM.html#method">method</a> + <a href="refM.html#meth">meth</a> + <a href="refS.html#send">send</a> + <a href="refT.html#try">try</a> + <a href="refS.html#super">super</a> + <a href="refE.html#extra">extra</a> + <a href="refW.html#with">with</a> + <a href="refB.html#bind">bind</a> + <a href="refJ.html#job">job</a> + <a href="refL.html#let">let</a> + <a href="refL.html#let?">let?</a> + <a href="refU.html#use">use</a> + <a href="refA.html#and">and</a> + <a href="refO.html#or">or</a> + <a href="refN.html#nand">nand</a> + <a href="refN.html#nor">nor</a> + <a href="refX.html#xor">xor</a> + <a href="refB.html#bool">bool</a> + <a href="refN.html#not">not</a> + <a href="refN.html#nil">nil</a> + <a href="refT.html#t">t</a> + <a href="refP.html#prog">prog</a> + <a href="refP.html#prog1">prog1</a> + <a href="refP.html#prog2">prog2</a> + <a href="refI.html#if">if</a> + <a href="refI.html#if2">if2</a> + <a href="refI.html#ifn">ifn</a> + <a href="refW.html#when">when</a> + <a href="refU.html#unless">unless</a> + <a href="refC.html#cond">cond</a> + <a href="refN.html#nond">nond</a> + <a href="refC.html#case">case</a> + <a href="refS.html#state">state</a> + <a href="refW.html#while">while</a> + <a href="refU.html#until">until</a> + <a href="refL.html#loop">loop</a> + <a href="refD.html#do">do</a> + <a href="refA.html#at">at</a> + <a href="refF.html#for">for</a> + <a href="refC.html#catch">catch</a> + <a href="refT.html#throw">throw</a> + <a href="refF.html#finally">finally</a> + <a href="ref_.html#!">!</a> + <a href="refE.html#e">e</a> + <a href="ref_.html#$">$</a> + <a href="refS.html#sys">sys</a> + <a href="refC.html#call">call</a> + <a href="refT.html#tick">tick</a> + <a href="refI.html#ipid">ipid</a> + <a href="refO.html#opid">opid</a> + <a href="refK.html#kill">kill</a> + <a href="refQ.html#quit">quit</a> + <a href="refT.html#task">task</a> + <a href="refF.html#fork">fork</a> + <a href="refP.html#pipe">pipe</a> + <a href="refL.html#later">later</a> + <a href="refT.html#timeout">timeout</a> + <a href="refA.html#abort">abort</a> + <a href="refB.html#bye">bye</a> +</code> + +<dt>Mapping +<dd><code> + <a href="refA.html#apply">apply</a> + <a href="refP.html#pass">pass</a> + <a href="refM.html#maps">maps</a> + <a href="refM.html#map">map</a> + <a href="refM.html#mapc">mapc</a> + <a href="refM.html#maplist">maplist</a> + <a href="refM.html#mapcar">mapcar</a> + <a href="refM.html#mapcon">mapcon</a> + <a href="refM.html#mapcan">mapcan</a> + <a href="refF.html#filter">filter</a> + <a href="refE.html#extract">extract</a> + <a href="refS.html#seek">seek</a> + <a href="refF.html#find">find</a> + <a href="refP.html#pick">pick</a> + <a href="refC.html#cnt">cnt</a> + <a href="refS.html#sum">sum</a> + <a href="refM.html#maxi">maxi</a> + <a href="refM.html#mini">mini</a> + <a href="refF.html#fish">fish</a> + <a href="refB.html#by">by</a> +</code> + +<dt>Input/Output +<dd><code> + <a href="refP.html#path">path</a> + <a href="refI.html#in">in</a> + <a href="refI.html#ipid">ipid</a> + <a href="refO.html#out">out</a> + <a href="refO.html#opid">opid</a> + <a href="refP.html#pipe">pipe</a> + <a href="refC.html#ctl">ctl</a> + <a href="refA.html#any">any</a> + <a href="refS.html#sym">sym</a> + <a href="refS.html#str">str</a> + <a href="refL.html#load">load</a> + <a href="refH.html#hear">hear</a> + <a href="refT.html#tell">tell</a> + <a href="refK.html#key">key</a> + <a href="refP.html#poll">poll</a> + <a href="refP.html#peek">peek</a> + <a href="refC.html#char">char</a> + <a href="refS.html#skip">skip</a> + <a href="refE.html#eol">eol</a> + <a href="refE.html#eof">eof</a> + <a href="refF.html#from">from</a> + <a href="refT.html#till">till</a> + <a href="refL.html#line">line</a> + <a href="refF.html#format">format</a> + <a href="refS.html#scl">scl</a> + <a href="refR.html#read">read</a> + <a href="refP.html#print">print</a> + <a href="refP.html#println">println</a> + <a href="refP.html#printsp">printsp</a> + <a href="refP.html#prin">prin</a> + <a href="refP.html#prinl">prinl</a> + <a href="refM.html#msg">msg</a> + <a href="refS.html#space">space</a> + <a href="refB.html#beep">beep</a> + <a href="refT.html#tab">tab</a> + <a href="refF.html#flush">flush</a> + <a href="refR.html#rewind">rewind</a> + <a href="refR.html#rd">rd</a> + <a href="refP.html#pr">pr</a> + <a href="refW.html#wr">wr</a> + <a href="refR.html#rpc">rpc</a> + <a href="refW.html#wait">wait</a> + <a href="refS.html#sync">sync</a> + <a href="refE.html#echo">echo</a> + <a href="refI.html#info">info</a> + <a href="refF.html#file">file</a> + <a href="refD.html#dir">dir</a> + <a href="refL.html#lines">lines</a> + <a href="refO.html#open">open</a> + <a href="refC.html#close">close</a> + <a href="refP.html#port">port</a> + <a href="refL.html#listen">listen</a> + <a href="refA.html#accept">accept</a> + <a href="refH.html#host">host</a> + <a href="refC.html#connect">connect</a> + <a href="refU.html#udp">udp</a> + <a href="refS.html#script">script</a> + <a href="refO.html#once">once</a> + <a href="refR.html#rc">rc</a> + <a href="refA.html#acquire">acquire</a> + <a href="refR.html#release">release</a> + <a href="refP.html#pretty">pretty</a> + <a href="refP.html#pp">pp</a> + <a href="refS.html#show">show</a> + <a href="refV.html#view">view</a> + <a href="refH.html#here">here</a> + <a href="refP.html#prEval">prEval</a> + <a href="refM.html#mail">mail</a> +</code> + +<dt>Object Orientation +<dd><code> + <a href="refC.html#*Class">*Class</a> + <a href="refC.html#class">class</a> + <a href="refD.html#dm">dm</a> + <a href="refR.html#rel">rel</a> + <a href="refV.html#var">var</a> + <a href="refV.html#var:">var:</a> + <a href="refN.html#new">new</a> + <a href="refT.html#type">type</a> + <a href="refI.html#isa">isa</a> + <a href="refM.html#method">method</a> + <a href="refM.html#meth">meth</a> + <a href="refS.html#send">send</a> + <a href="refT.html#try">try</a> + <a href="refO.html#object">object</a> + <a href="refE.html#extend">extend</a> + <a href="refS.html#super">super</a> + <a href="refE.html#extra">extra</a> + <a href="refW.html#with">with</a> + <a href="refT.html#This">This</a> + <a href="refC.html#can">can</a> + <a href="refD.html#dep">dep</a> +</code> + +<dt>Database +<dd><code> + <a href="refP.html#pool">pool</a> + <a href="refJ.html#journal">journal</a> + <a href="refI.html#id">id</a> + <a href="refS.html#seq">seq</a> + <a href="refL.html#lieu">lieu</a> + <a href="refL.html#lock">lock</a> + <a href="refC.html#commit">commit</a> + <a href="refR.html#rollback">rollback</a> + <a href="refM.html#mark">mark</a> + <a href="refF.html#free">free</a> + <a href="refD.html#dbck">dbck</a> + <a href="refD.html#dbs">dbs</a> + <a href="refD.html#dbs+">dbs+</a> + <a href="refD.html#db:">db:</a> + <a href="refT.html#tree">tree</a> + <a href="refD.html#db">db</a> + <a href="refA.html#aux">aux</a> + <a href="refC.html#collect">collect</a> + <a href="refG.html#genKey">genKey</a> + <a href="refU.html#useKey">useKey</a> + <a href="refR.html#+relation">+relation</a> + <a href="refA.html#+Any">+Any</a> + <a href="refB.html#+Bag">+Bag</a> + <a href="refB.html#+Bool">+Bool</a> + <a href="refN.html#+Number">+Number</a> + <a href="refD.html#+Date">+Date</a> + <a href="refT.html#+Time">+Time</a> + <a href="refS.html#+Symbol">+Symbol</a> + <a href="refS.html#+String">+String</a> + <a href="refL.html#+Link">+Link</a> + <a href="refJ.html#+Joint">+Joint</a> + <a href="refB.html#+Blob">+Blob</a> + <a href="refH.html#+Hook">+Hook</a> + <a href="refI.html#+index">+index</a> + <a href="refK.html#+Key">+Key</a> + <a href="refR.html#+Ref">+Ref</a> + <a href="refR.html#+Ref2">+Ref2</a> + <a href="refI.html#+Idx">+Idx</a> + <a href="refS.html#+Sn">+Sn</a> + <a href="refF.html#+Fold">+Fold</a> + <a href="refA.html#+Aux">+Aux</a> + <a href="refD.html#+Dep">+Dep</a> + <a href="refL.html#+List">+List</a> + <a href="refN.html#+Need">+Need</a> + <a href="refM.html#+Mis">+Mis</a> + <a href="refA.html#+Alt">+Alt</a> + <a href="refB.html#blob">blob</a> + <a href="refD.html#dbSync">dbSync</a> + <a href="refN.html#new!">new!</a> + <a href="refS.html#set!">set!</a> + <a href="refP.html#put!">put!</a> + <a href="refI.html#inc!">inc!</a> + <a href="refB.html#blob!">blob!</a> + <a href="refU.html#upd">upd</a> + <a href="refR.html#rel">rel</a> + <a href="refR.html#request">request</a> + <a href="refO.html#obj">obj</a> + <a href="refF.html#fmt64">fmt64</a> + <a href="refR.html#root">root</a> + <a href="refF.html#fetch">fetch</a> + <a href="refS.html#store">store</a> + <a href="refC.html#count">count</a> + <a href="refL.html#leaf">leaf</a> + <a href="refM.html#minKey">minKey</a> + <a href="refM.html#maxKey">maxKey</a> + <a href="refI.html#init">init</a> + <a href="refS.html#step">step</a> + <a href="refS.html#scan">scan</a> + <a href="refI.html#iter">iter</a> + <a href="refP.html#prune">prune</a> + <a href="refZ.html#zapTree">zapTree</a> + <a href="refC.html#chkTree">chkTree</a> + <a href="refD.html#db/3">db/3</a> + <a href="refD.html#db/4">db/4</a> + <a href="refD.html#db/5">db/5</a> + <a href="refV.html#val/3">val/3</a> + <a href="refL.html#lst/3">lst/3</a> + <a href="refM.html#map/3">map/3</a> + <a href="refI.html#isa/2">isa/2</a> + <a href="refS.html#same/3">same/3</a> + <a href="refB.html#bool/3">bool/3</a> + <a href="refR.html#range/3">range/3</a> + <a href="refH.html#head/3">head/3</a> + <a href="refF.html#fold/3">fold/3</a> + <a href="refP.html#part/3">part/3</a> + <a href="refT.html#tolr/3">tolr/3</a> + <a href="refS.html#select/3">select/3</a> + <a href="refR.html#remote/2">remote/2</a> +</code> + +<dt>Pilog +<dd><code> + <a href="refP.html#prove">prove</a> + <a href="ref_.html#->">-&gt</a> + <a href="refU.html#unify">unify</a> + <a href="refB.html#be">be</a> + <a href="refR.html#repeat">repeat</a> + <a href="refA.html#asserta">asserta</a> + <a href="refA.html#assertz">assertz</a> + <a href="refR.html#retract">retract</a> + <a href="refR.html#rules">rules</a> + <a href="refG.html#goal">goal</a> + <a href="refF.html#fail">fail</a> + <a href="refP.html#pilog">pilog</a> + <a href="refS.html#solve">solve</a> + <a href="refQ.html#query">query</a> + <a href="ref_.html#?">?</a> + <a href="refR.html#repeat/0">repeat/0</a> + <a href="refF.html#fail/0">fail/0</a> + <a href="refT.html#true/0">true/0</a> + <a href="refN.html#not/1">not/1</a> + <a href="refC.html#call/1">call/1</a> + <a href="refO.html#or/2">or/2</a> + <a href="refN.html#nil/1">nil/1</a> + <a href="refE.html#equal/2">equal/2</a> + <a href="refD.html#different/2">different/2</a> + <a href="refA.html#append/3">append/3</a> + <a href="refM.html#member/2">member/2</a> + <a href="refD.html#delete/3">delete/3</a> + <a href="refP.html#permute/2">permute/2</a> + <a href="refU.html#uniq/2">uniq/2</a> + <a href="refA.html#asserta/1">asserta/1</a> + <a href="refA.html#assertz/1">assertz/1</a> + <a href="refR.html#retract/1">retract/1</a> + <a href="refC.html#clause/2">clause/2</a> + <a href="refS.html#show/1">show/1</a> + <a href="refD.html#db/3">db/3</a> + <a href="refD.html#db/4">db/4</a> + <a href="refD.html#db/5">db/5</a> + <a href="refV.html#val/3">val/3</a> + <a href="refL.html#lst/3">lst/3</a> + <a href="refM.html#map/3">map/3</a> + <a href="refI.html#isa/2">isa/2</a> + <a href="refS.html#same/3">same/3</a> + <a href="refB.html#bool/3">bool/3</a> + <a href="refR.html#range/3">range/3</a> + <a href="refH.html#head/3">head/3</a> + <a href="refF.html#fold/3">fold/3</a> + <a href="refP.html#part/3">part/3</a> + <a href="refT.html#tolr/3">tolr/3</a> + <a href="refS.html#select/3">select/3</a> + <a href="refR.html#remote/2">remote/2</a> +</code> + +<dt>Debugging +<dd><code> + <a href="refP.html#pretty">pretty</a> + <a href="refP.html#pp">pp</a> + <a href="refS.html#show">show</a> + <a href="refL.html#loc">loc</a> + <a href="refD.html#*Dbg">*Dbg</a> + <a href="refD.html#doc">doc</a> + <a href="refM.html#more">more</a> + <a href="refD.html#depth">depth</a> + <a href="refW.html#what">what</a> + <a href="refW.html#who">who</a> + <a href="refC.html#can">can</a> + <a href="refD.html#dep">dep</a> + <a href="refD.html#debug">debug</a> + <a href="refD.html#d">d</a> + <a href="refU.html#unbug">unbug</a> + <a href="refU.html#u">u</a> + <a href="refV.html#vi">vi</a> + <a href="refL.html#ld">ld</a> + <a href="refT.html#trace">trace</a> + <a href="refU.html#untrace">untrace</a> + <a href="refT.html#traceAll">traceAll</a> + <a href="refP.html#proc">proc</a> + <a href="refH.html#hd">hd</a> + <a href="refB.html#bench">bench</a> + <a href="refE.html#edit">edit</a> + <a href="refL.html#lint">lint</a> + <a href="refL.html#lintAll">lintAll</a> + <a href="refS.html#select">select</a> + <a href="refU.html#update">update</a> +</code> + +<dt>System Functions +<dd><code> + <a href="refC.html#cmd">cmd</a> + <a href="refA.html#argv">argv</a> + <a href="refO.html#opt">opt</a> + <a href="refV.html#version">version</a> + <a href="refG.html#gc">gc</a> + <a href="refR.html#raw">raw</a> + <a href="refA.html#alarm">alarm</a> + <a href="refP.html#protect">protect</a> + <a href="refH.html#heap">heap</a> + <a href="refE.html#env">env</a> + <a href="refU.html#up">up</a> + <a href="refD.html#date">date</a> + <a href="refT.html#time">time</a> + <a href="refU.html#usec">usec</a> + <a href="refS.html#stamp">stamp</a> + <a href="refD.html#dat$">dat$</a> + <a href="ref_.html#$dat">$dat</a> + <a href="refD.html#datSym">datSym</a> + <a href="refD.html#datStr">datStr</a> + <a href="refS.html#strDat">strDat</a> + <a href="refE.html#expDat">expDat</a> + <a href="refD.html#day">day</a> + <a href="refW.html#week">week</a> + <a href="refU.html#ultimo">ultimo</a> + <a href="refT.html#tim$">tim$</a> + <a href="ref_.html#$tim">$tim</a> + <a href="refT.html#telStr">telStr</a> + <a href="refE.html#expTel">expTel</a> + <a href="refL.html#locale">locale</a> + <a href="refA.html#allowed">allowed</a> + <a href="refA.html#allow">allow</a> + <a href="refP.html#pwd">pwd</a> + <a href="refC.html#cd">cd</a> + <a href="refC.html#chdir">chdir</a> + <a href="refC.html#ctty">ctty</a> + <a href="refI.html#info">info</a> + <a href="refD.html#dir">dir</a> + <a href="refD.html#dirname">dirname</a> + <a href="refE.html#errno">errno</a> + <a href="refN.html#native">native</a> + <a href="refC.html#call">call</a> + <a href="refT.html#tick">tick</a> + <a href="refK.html#kill">kill</a> + <a href="refQ.html#quit">quit</a> + <a href="refT.html#task">task</a> + <a href="refF.html#fork">fork</a> + <a href="refF.html#forked">forked</a> + <a href="refP.html#pipe">pipe</a> + <a href="refT.html#timeout">timeout</a> + <a href="refM.html#mail">mail</a> + <a href="refT.html#test">test</a> + <a href="refB.html#bye">bye</a> +</code> + +<dt>Globals +<dd><code> + <a href="#nilSym">NIL</a> + <a href="refO.html#*OS">*OS</a> + <a href="refD.html#*DB">*DB</a> + <a href="refT.html#T">T</a> + <a href="refS.html#*Solo">*Solo</a> + <a href="refP.html#*PPid">*PPid</a> + <a href="refP.html#*Pid">*Pid</a> + <a href="ref_.html#@">@</a> + <a href="ref_.html#@@">@@</a> + <a href="ref_.html#@@@">@@@</a> + <a href="refT.html#This">This</a> + <a href="refD.html#*Dbg">*Dbg</a> + <a href="refZ.html#*Zap">*Zap</a> + <a href="refS.html#*Scl">*Scl</a> + <a href="refC.html#*Class">*Class</a> + <a href="refD.html#*Dbs">*Dbs</a> + <a href="refR.html#*Run">*Run</a> + <a href="refR.html#*Hup">*Hup</a> + <a href="refS.html#*Sig1">*Sig1</a> + <a href="refS.html#*Sig2">*Sig2</a> + <a href="ref_.html#^">^</a> + <a href="refE.html#*Err">*Err</a> + <a href="refM.html#*Msg">*Msg</a> + <a href="refU.html#*Uni">*Uni</a> + <a href="refL.html#*Led">*Led</a> + <a href="refT.html#*Tsm">*Tsm</a> + <a href="refA.html#*Adr">*Adr</a> + <a href="refA.html#*Allow">*Allow</a> + <a href="refF.html#*Fork">*Fork</a> + <a href="refB.html#*Bye">*Bye</a> +</code> + +</dl> + +<p><hr> +<h2><a name="down">Download</a></h2> + +<p>The <code>PicoLisp</code> system can be downloaded from the <a +href="http://software-lab.de/down.html">PicoLisp Download</a> page. + +</body> +</html> diff --git a/doc/refA.html b/doc/refA.html @@ -0,0 +1,567 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/1998/REC-html40-19980424/loose.dtd"> +<html lang="en"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> +<title>A</title> +<link rel="stylesheet" href="doc.css" type="text/css"> +</head> +<body> + +<h1>A</h1> + +<dl> + +<dt><a name="*Adr"><code>*Adr</code></a> +<dd>A global variable holding the IP address of last recently accepted client. +See also <code><a href="refL.html#listen">listen</a></code> and <code><a +href="refA.html#accept">accept</a></code>. + +<pre><code> +: *Adr +-> "127.0.0.1" +</code></pre> + +<dt><a name="*Allow"><code>*Allow</code></a> +<dd>A global variable holding allowed access patterns. If its value is +non-<code>NIL</code>, it should contain a list where the CAR is an <code><a +href="refI.html#idx">idx</a></code> tree of allowed items, and the CDR a list of +prefix strings. See also <code><a href="refA.html#allow">allow</a></code>, +<code><a href="refA.html#allowed">allowed</a></code> and <code><a +href="refP.html#pre?">pre?</a></code>. + +<pre><code> +: (allowed ("app/" "img/") # Initialize + "@start" "@stop" "favicon.ico" "lib.css" "@psh" ) +-> NIL +: (allow "@myFoo") # additional item +-> "@myFoo" +: (allow "myDir/" T) # additional prefix +-> "myDir/" + +: *Allow +-> (("@stop" ("@psh" ("@myFoo") "@start") "favicon.ico" NIL "lib.css") "app/" "img/" "myDir/") + +: (idx *Allow) # items +-> ("@myFoo" "@psh" "@start" "@stop" "favicon.ico" "lib.css") +: (cdr *Allow) # prefixes +-> ("app/" "img/" "myDir/") +</code></pre> + +<dt><a name="+Alt"><code>+Alt</code></a> +<dd>Prefix class specifying an alternative class for a <code><a +href="refR.html#+relation">+relation</a></code>. This allows indexes or other +side effects to be maintained in a class different from the current one. See +also <code><a href="ref.html#dbase">Database</a></code>. + +<pre><code> +(class +EuOrd +Ord) # EU-specific order subclass +(rel nr (+Alt +Key +Number) +XyOrd) # Maintain the key in the +XyOrd index +</code></pre> + +<dt><a name="+Any"><code>+Any</code></a> +<dd>Class for unspecified relations, a subclass of <code><a +href="refR.html#+relation">+relation</a></code>. Objects of that class accept +and maintain any type of Lisp data. Used often when there is no other suitable +relation class available. See also <code><a +href="ref.html#dbase">Database</a></code>. + +<p>In the following example <code>+Any</code> is used simply for the reason that +there is no direct way to specify dotted pairs: + +<pre><code> +(rel loc (+Any)) # Locale, e.g. ("DE" . "de") +</code></pre> + +<dt><a name="+Aux"><code>+Aux</code></a> +<dd>Prefix class maintaining auxiliary keys for <code><a +href="refR.html#+relation">+relation</a></code>s, in addition to <code><a +href="refR.html#+Ref">+Ref</a></code> or <code><a +href="refI.html#+Idx">+Idx</a></code> indexes. Expects a list of auxiliary +attributes of the same object, and combines all keys in that order into a single +index key. See also <code><a href="refA.html#aux">aux</a></code> and <code><a +href="ref.html#dbase">Database</a></code>. + +<pre><code> +(rel nr (+Ref +Number)) # Normal, non-unique index +(rel nm (+Aux +Ref +String) (nr txt)) # Combined name/number/text index +(rel txt (+Aux +Sn +Idx +String) (nr)) # Text/number plus tolerant text index +</code></pre> + +<dt><a name="abort"><code>(abort 'cnt . prg) -> any</code></a> +<dd>Aborts the execution of <code>prg</code> if it takes longer than +<code>cnt</code> seconds, and returns <code>NIL</code>. Otherwise, the result of +<code>prg</code> is returned. <code><a href="refA.html#alarm">alarm</a></code> +is used internally, so care must be taken not to interfer with other calls to +<code>alarm</code>. + +<pre><code> +: (abort 20 (in Sock (rd))) # Wait maximally 20 seconds for socket data +</code></pre> + +<dt><a name="abs"><code>(abs 'num) -> num</code></a> +<dd>Returns the absolute value of the <code>num</code> argument. + +<pre><code> +: (abs -7) +-> 7 +: (abs 7) +-> 7 +</code></pre> + +<dt><a name="accept"><code>(accept 'cnt) -> cnt | NIL</code></a> +<dd>Accepts a connection on descriptor <code>cnt</code> (as received by <code><a +href="refP.html#port">port</a></code>), and returns the new socket descriptor +<code>cnt</code>. The global variable <code>*Adr</code> is set to the IP address +of the client. See also <code><a href="refL.html#listen">listen</a></code>, +<code><a href="refC.html#connect">connect</a></code> and <code><a +href="refA.html#*Adr">*Adr</a></code>. + +<pre><code> +: (setq *Socket + (accept (port 6789)) ) # Accept connection at port 6789 +-> 4 +</code></pre> + +<dt><a name="accu"><code>(accu 'var 'any 'num)</code></a> +<dd>Accumulates <code>num</code> into a sum, using the key <code>any</code> in +an association list stored in <code>var</code>. See also <code><a +href="refA.html#assoc">assoc</a></code>. + +<pre><code> +: (off Sum) +-> NIL +: (accu 'Sum 'a 1) +-> (a . 1) +: (accu 'Sum 'a 5) +-> 6 +: (accu 'Sum 22 100) +-> (22 . 100) +: Sum +-> ((22 . 100) (a . 6)) +</code></pre> + +<dt><a name="acquire"><code>(acquire 'sym) -> flg</code></a> +<dd>Tries to acquire the mutex represented by the file <code>sym</code>, by +obtaining an exclusive lock on that file with <code><a +href="refC.html#ctl">ctl</a></code>, and then trying to write the PID of the +current process into that file. It fails if the file already holds the PID of +some other existing process. See also <code><a +href="refR.html#release">release</a></code>, <code><a +href="refP.html#*Pid">*Pid</a></code> and <code><a +href="refR.html#rc">rc</a></code>. + +<pre><code> +: (acquire "sema1") +-> 28255 +</code></pre> + +<dt><a name="alarm"><code>(alarm 'cnt . prg) -> cnt</code></a> +<dd>Sets an alarm timer scheduling <code>prg</code> to be executed after +<code>cnt</code> seconds, and returns the number of seconds remaining until any +previously scheduled alarm was due to be delivered. Calling <code>(alarm +0)</code> will cancel an alarm. + +<pre><code> +: (prinl (tim$ (time) T)) (alarm 10 (prinl (tim$ (time) T))) +16:36:14 +-> 0 +: 16:36:24 + +: (alarm 10 (bye 0)) +-> 0 +$ +</code></pre> + +<dt><a name="align"><code>(align 'cnt 'any) -> sym</code></a> +<dt><code>(align 'lst 'any ..) -> sym</code> +<dd>Returns a transient symbol with all <code>any</code> arguments <code><a +href="refP.html#pack">pack</a></code>ed in an aligned format. In the first form, +<code>any</code> will be left-aligned if <code>cnt</code> ist negative, +otherwise right-aligned. In the second form, all <code>any</code> arguments are +packed according to the numbers in <code>lst</code>. See also <code><a +href="refT.html#tab">tab</a></code>, <code><a +href="refC.html#center">center</a></code> and <code><a +href="refW.html#wrap">wrap</a></code>. + +<pre><code> +: (align 4 "a") +-> " a" +: (align -4 12) +-> "12 " +: (align (4 4 4) "a" 12 "b") +-> " a 12 b" +</code></pre> + +<dt><a name="all"><code>(all ['T | '0]) -> lst</code></a> +<dd>Returns a new list of all <a href="ref.html#internal">internal</a> symbols +in the system (if called without arguments, or with <code>NIL</code>). Otherwise +(if the argument is <code>T</code>), all current <a +href="ref.html#transient">transient</a> symbols are returned. Else all current +<a href="ref.html#external">external</a> symbols are returned. + +<pre><code> +: (all) # All internal symbols +-> (inc> leaf nil inc! accept ... + +# Find all symbols starting with an underscore character +: (filter '((X) (= "_" (car (chop X)))) (all)) +-> (_put _nacs _oct _lintq _lst _map _iter _dbg2 _getLine _led ... +</code></pre> + +<dt><a name="allow"><code>(allow 'sym ['flg]) -> sym</code></a> +<dd>Maintains an index structure of allowed access patterns in the global +variable <code><a href="refA.html#*Allow">*Allow</a></code>. If the value of +<code>*Allow</code> is non-<code>NIL</code>, <code>sym</code> is added to the +<code><a href="refI.html#idx">idx</a></code> tree in the CAR of +<code>*Allow</code> (if <code>flg</code> is <code>NIL</code>), or to the list of +prefix strings (if <code>flg</code> is non-<code>NIL</code>). See also <code><a +href="refA.html#allowed">allowed</a></code>. + +<pre><code> +: *Allow +-> (("@stop" ("@psh" NIL "@start") "favicon.ico" NIL "lib.css") "app/" "img/") +: (allow "@myFoo") # additionally allowed item +-> "@myFoo" +: (allow "myDir/" T) # additionally allowed prefix +-> "myDir/" +</code></pre> + +<dt><a name="allowed"><code>(allowed lst [sym ..])</code></a> +<dd>Creates an index structure of allowed access patterns in the global variable +<code><a href="refA.html#*Allow">*Allow</a></code>. <code>lst</code> should +consist of prefix strings (to be checked at runtime with <code><a +href="refP.html#pre?">pre?</a></code>), and the <code>sym</code> arguments +should specify the initially allowed items. See also <code><a +href="refA.html#allow">allow</a></code>. + +<pre><code> +: (allowed ("app/" "img/") # allowed prefixes + "@start" "@stop" "favicon.ico" "lib.css" "@psh" ) # allowed items +-> NIL +</code></pre> + +<dt><a name="and"><code>(and 'any ..) -> any</code></a> +<dd>Logical AND. The expressions <code>any</code> are evaluated from left to +right. If <code>NIL</code> is encountered, <code>NIL</code> is returned +immediately. Else the result of the last expression is returned. + +<pre><code> +: (and (= 3 3) (read)) +abc # User input +-> abc +: (and (= 3 4) (read)) +-> NIL +</code></pre> + +<dt><a name="any"><code>(any 'sym) -> any</code></a> +<dd>Parses <code>any</code> from the name of <code>sym</code>. This is the +reverse operation of <code><a href="refS.html#sym">sym</a></code>. See also +<code><a href="refS.html#str">str</a></code>. + +<pre><code> +: (any "(a b # Comment^Jc d)") +-> (a b c d) +: (any "\"A String\"") +-> "A String" +</code></pre> + +<dt><a name="append"><code>(append 'lst ..) -> lst</code></a> +<dd>Appends all argument lists. See also <code><a +href="refC.html#conc">conc</a></code>, <code><a +href="refI.html#insert">insert</a></code>, <code><a +href="refD.html#delete">delete</a></code> and <code><a +href="refR.html#remove">remove</a></code>. + +<pre><code> +: (append '(a b c) (1 2 3)) +-> (a b c 1 2 3) +: (append (1) (2) (3) 4) +-> (1 2 3 . 4) +</code></pre> + +<dt><a name="append/3"><code>append/3</code></a> +<dd><a href="ref.html#pilog">Pilog</a> predicate that succeeds if appending the +first two list arguments is equal to the third argument. See also <code><a +href="refA.html#append">append</a></code> and <code><a +href="refM.html#member/2">member/2</a></code>. + +<pre><code> +: (? (append @X @Y (a b c))) + @X=NIL @Y=(a b c) + @X=(a) @Y=(b c) + @X=(a b) @Y=(c) + @X=(a b c) @Y=NIL +-> NIL +</code></pre> + +<dt><a name="apply"><code>(apply 'fun 'lst ['any ..]) -> any</code></a> +<dd>Applies <code>fun</code> to <code>lst</code>. If additional <code>any</code> +arguments are given, they are applied as leading elements of <code>lst</code>. +<code>(apply 'fun 'lst 'any1 'any2)</code> is equivalent to <code>(apply 'fun +(cons 'any1 'any2 'lst))</code>. + +<pre><code> +: (apply + (1 2 3)) +-> 6 +: (apply * (5 6) 3 4) +-> 360 +: (apply '((X Y Z) (* X (+ Y Z))) (3 4 5)) +-> 27 +: (apply println (3 4) 1 2) +1 2 3 4 +-> 4 +</code></pre> + +<dt><a name="arg"><code>(arg ['cnt]) -> any</code></a> +<dd>Can only be used inside functions with a variable number of arguments (with +<code>@</code>). If <code>cnt</code> is not given, the value that was returned +from the last call to <code>next</code>) is returned. Otherwise, the +<code>cnt</code>'th remaining argument is returned. See also <code><a +href="refA.html#args">args</a></code>, <code><a +href="refN.html#next">next</a></code>, <code><a +href="refR.html#rest">rest</a></code> and <code><a +href="refP.html#pass">pass</a></code>. + +<pre><code> +: (de foo @ (println (next) (arg))) # Print argument twice +-> foo +: (foo 123) +123 123 +-> 123 +: (de foo @ + (println (arg 1) (arg 2)) + (println (next)) + (println (arg 1) (arg 2)) ) +-> foo +: (foo 'a 'b 'c) +a b +a +b c +-> c +</code></pre> + +<dt><a name="args"><code>(args) -> flg</code></a> +<dd>Can only be used inside functions with a variable number of arguments (with +<code>@</code>). Returns <code>T</code> when there are more arguments to be +fetched from the internal list. See also <code><a +href="refN.html#next">next</a></code>, <code><a +href="refA.html#arg">arg</a></code>, <code><a +href="refR.html#rest">rest</a></code> and <code><a +href="refP.html#pass">pass</a></code>. + +<pre><code> +: (de foo @ (println (args))) # Test for arguments +-> foo +: (foo) # No arguments +NIL +-> NIL +: (foo NIL) # One argument +T +-> T +: (foo 123) # One argument +T +-> T +</code></pre> + +<dt><a name="argv"><code>(argv [var ..] [. sym]) -> lst|sym</code></a> +<dd>If called without arguments, <code>argv</code> returns a list of strings +containing all remaining command line arguments. Otherwise, the +<code>var/sym</code> arguments are subsequently bound to the command line +arguments. A hyphen "<code>-</code>" can be used to stop <code>load</code>ing +further arguments. See also <code><a href="refC.html#cmd">cmd</a></code>, +<code><a href="ref.html#invoc">Invocation</a></code> and <code><a +href="refO.html#opt">opt</a></code>. + +<pre><code> +$ ./p -"println 'OK" - abc 123 +OK +: (argv) +-> ("abc" "123") +: (argv A B) +-> "123" +: A +-> "abc" +: B +-> "123" +: (argv . Lst) +-> ("abc" "123") +: Lst +-> ("abc" "123") +</code></pre> + +<dt><a name="as"><code>(as 'any1 . any2) -> any2 | NIL</code></a> +<dd>Returns <code>any2</code> unevaluated when <code>any1</code> evaluates to +non-<code>NIL</code>. Otherwise <code>NIL</code> is returned. <code>(as Flg A B +C)</code> is equivalent to <code>(and Flg '(A B C))</code>. See also <code><a +href="refQ.html#quote">quote</a></code>. + +<pre><code> +: (as (= 3 3) A B C) +-> (A B C) +</code></pre> + +<dt><a name="asoq"><code>(asoq 'any 'lst) -> lst</code></a> +<dd>Searches an association list. Returns the first element from +<code>lst</code> with <code>any</code> as its CAR, or <code>NIL</code> if no +match is found. <code><a href="ref_.html#==">==</a></code> is used for +comparison (pointer equality). See also <code><a +href="refA.html#assoc">assoc</a></code>, <code><a +href="refD.html#delq">delq</a></code>, <code><a +href="refM.html#memq">memq</a></code>, <code><a +href="refM.html#mmeq">mmeq</a></code> and <a href="ref.html#cmp">Comparing</a>. + +<pre><code> +: (asoq 999 '((999 1 2 3) (b . 7) ("ok" "Hello"))) +-> NIL +: (asoq 'b '((999 1 2 3) (b . 7) ("ok" "Hello"))) +-> (b . 7) +</code></pre> + +<dt><a name="asserta"><code>(asserta 'lst) -> lst</code></a> +<dd>Inserts a new <a href="ref.html#pilog">Pilog</a> fact or rule before all +other rules. See also <code><a href="refB.html#be">be</a></code>, <code><a +href="refA.html#assertz">assertz</a></code> and <code><a +href="refR.html#retract">retract</a></code>. + +<pre><code> +: (be a (2)) # Define two facts +-> a +: (be a (3)) +-> a + +: (asserta '(a (1))) # Insert new fact in front +-> (((1)) ((2)) ((3))) + +: (? (a @N)) # Query + @N=1 + @N=2 + @N=3 +-> NIL +</code></pre> + +<dt><a name="asserta/1"><code>asserta/1</code></a> +<dd><a href="ref.html#pilog">Pilog</a> predicate that inserts a new fact or rule +before all other rules. See also <code><a +href="refA.html#asserta">asserta</a></code>, <code><a +href="refA.html#assertz/1">assertz/1</a></code> and <code><a +href="refR.html#retract/1">retract/1</a></code>. + +<pre><code> +: (? (asserta (a (2)))) +-> T +: (? (asserta (a (1)))) +-> T +: (rules 'a) +1 (be a (1)) +2 (be a (2)) +-> a +</code></pre> + +<dt><a name="assertz"><code>(assertz 'lst) -> lst</code></a> +<dd>Appends a new <a href="ref.html#pilog">Pilog</a> fact or rule behind all +other rules. See also <code><a href="refB.html#be">be</a></code>, <code><a +href="refA.html#asserta">asserta</a></code> and <code><a +href="refR.html#retract">retract</a></code>. + +<pre><code> +: (be a (1)) # Define two facts +-> a +: (be a (2)) +-> a + +: (assertz '(a (3))) # Append new fact at the end +-> (((1)) ((2)) ((3))) + +: (? (a @N)) # Query + @N=1 + @N=2 + @N=3 +-> NIL +</code></pre> + +<dt><a name="assertz/1"><code>assertz/1</code></a> +<dd><a href="ref.html#pilog">Pilog</a> predicate that appends a new fact or rule +behind all other rules. See also <code><a +href="refA.html#assertz">assertz</a></code>, <code><a +href="refA.html#asserta/1">asserta/1</a></code> and <code><a +href="refR.html#retract/1">retract/1</a></code>. + +<pre><code> +: (? (assertz (a (1)))) +-> T +: (? (assertz (a (2)))) +-> T +: (rules 'a) +1 (be a (1)) +2 (be a (2)) +-> a +</code></pre> + +<dt><a name="assoc"><code>(assoc 'any 'lst) -> lst</code></a> <dd>Searches an +association list. Returns the first element from <code>lst</code> with its CAR +equal to <code>any</code>, or <code>NIL</code> if no match is found. See also +<code><a href="refA.html#asoq">asoq</a></code>. + +<pre><code> +: (assoc "b" '((999 1 2 3) ("b" . 7) ("ok" "Hello"))) +-> ("b" . 7) +: (assoc 999 '((999 1 2 3) ("b" . 7) ("ok" "Hello"))) +-> (999 1 2 3) +: (assoc 'u '((999 1 2 3) ("b" . 7) ("ok" "Hello"))) +-> NIL +</code></pre> + +<dt><a name="at"><code>(at '(cnt1 . cnt2) . prg) -> any</code></a> +<dd>Increments <code>cnt1</code> (destructively), and returns <code>NIL</code> +when it is less than <code>cnt2</code>. Otherwise, <code>cnt1</code> is reset to +zero and <code>prg</code> is executed. Returns the result of <code>prg</code>. + +<pre><code> +: (do 11 (prin ".") (at (0 . 3) (prin "!"))) +...!...!...!..-> NIL +</code></pre> + +<dt><a name="atom"><code>(atom 'any) -> flg</code></a> +<dd>Returns <code>T</code> when the argument <code>any</code> is an atom (a +number or a symbol). See also <code><a href="refP.html#pair">pair</a></code>. + +<pre><code> +: (atom 123) +-> T +: (atom 'a) +-> T +: (atom NIL) +-> T +: (atom (123)) +-> NIL +</code></pre> + +<dt><a name="aux"><code>(aux 'var 'cls ['hook] 'any ..) -> sym</code></a> +<dd>Returns a database object of class <code>cls</code>, where the value for +<code>var</code> corresponds to <code>any</code> and the following arguments. +<code>var</code>, <code>cls</code> and <code>hook</code> should specify a +<code><a href="refT.html#tree">tree</a></code> for <code>cls</code> or one of +its superclasses, for a relation with auxiliary keys. For multi-key accesses, +<code>aux</code> is simlar to - but faster than - <code>db</code>, because it +can use a single tree access. See also <code><a +href="refD.html#db">db</a></code>, <code><a +href="refC.html#collect">collect</a></code>, <code><a +href="refF.html#fetch">fetch</a></code>, <code><a +href="refI.html#init">init</a></code>, <code><a +href="refS.html#step">step</a></code> and <code><a +href="refA.html#+Aux">+Aux</a></code>. + +<pre><code> +(class +PS +Entity) +(rel par (+Dep +Joint) (sup) ps (+Part)) # Part +(rel sup (+Aux +Ref +Link) (par) NIL (+Supp))# Supplier +... + (aux 'sup '+PS # Access PS object + (db 'nr '+Supp 1234) + (db 'nr '+Part 5678) ) +</code></pre> + +</dl> + +</body> +</html> diff --git a/doc/refB.html b/doc/refB.html @@ -0,0 +1,319 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/1998/REC-html40-19980424/loose.dtd"> +<html lang="en"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> +<title>B</title> +<link rel="stylesheet" href="doc.css" type="text/css"> +</head> +<body> + +<h1>B</h1> + +<dl> + +<dt><a name="*Blob"><code>*Blob</code></a> +<dd>A global variable holding the pathname of the database blob directory. See +also <code><a href="refB.html#blob">blob</a></code>. + +<pre><code> +: *Blob +-> "blob/app/" +</code></pre> + +<dt><a name="*Bye"><code>*Bye</code></a> +<dd>A global variable holding a (possibly empty) <code>prg</code> body, to be +executed just before the termination of the PicoLisp interpreter. See also +<code><a href="refB.html#bye">bye</a></code> and <code><a +href="refT.html#tmp">tmp</a></code>. + +<pre><code> +: (push1 '*Bye '(call 'rm "myfile.tmp")) # Remove a temporary file +-> (call 'rm "myfile.tmp") +</code></pre> + +<dt><a name="+Bag"><code>+Bag</code></a> +<dd>Class for a list of arbitrary relations, a subclass of <code><a +href="refR.html#+relation">+relation</a></code>. Objects of that class maintain +a list of heterogeneous relations. Typically used in combination with the +<code><a href="refL.html#+List">+List</a></code> prefix class, to maintain small +two-dimensional tables within oubjects. See also <code><a +href="ref.html#dbase">Database</a></code>. + +<pre><code> +(rel pos (+List +Bag) # Positions + ((+Ref +Link) NIL (+Item)) # Item + ((+Number) 2) # Price + ((+Number)) # Quantity + ((+String)) # Memo text + ((+Number) 2) ) # Total amount +</code></pre> + +<dt><a name="+Blob"><code>+Blob</code></a> +<dd>Class for blob relations, a subclass of <code><a +href="refR.html#+relation">+relation</a></code>. Objects of that class maintain +blobs, as stubs in database objects pointing to actual files for arbitrary +(often binary) data. The files themselves reside below the path specified by the +<code><a href="refB.html#*Blob">*Blob</a></code> variable. See also <code><a +href="ref.html#dbase">Database</a></code>. + +<pre><code> +(rel jpg (+Blob)) # Picture +</code></pre> + +<dt><a name="+Bool">+Bool<code></code></a> +<dd>Class for boolean relations, a subclass of <code><a +href="refR.html#+relation">+relation</a></code>. Objects of that class expect +either <code>T</code> or <code>NIL</code> as value (though, as always, only +non-<code>NIL</code> will be physically stored in objects). See also <code><a +href="ref.html#dbase">Database</a></code>. + +<pre><code> +(rel ok (+Ref +Bool)) # Indexed flag +</code></pre> + +<dt><a name="balance"><code>(balance 'var 'lst ['flg])</code></a> +<dd>Builds a balanced binary <code><a href="refI.html#idx">idx</a></code> tree +in <code>var</code>, from the sorted list in <code>lst</code>. Normally (if +random or, in the worst case, ordered data) are inserted with <code>idx</code>, +the tree will not be balanced. But if <code>lst</code> is properly sorted, its +contents will be inserted in an optimally balanced way. If <code>flg</code> is +non-<code>NIL</code>, the index tree will be augmented instead of being +overwritten. See also <code><a href="ref.html#cmp">Comparing</a></code> and +<code><a href="refS.html#sort">sort</a></code>. + +<pre><code> +# Normal idx insert +: (off I) +-> NIL +: (for X (1 4 2 5 3 6 7 9 8) (idx 'I X T)) +-> NIL +: (depth I) +-> 7 + +# Balanced insert +: (balance 'I (sort (1 4 2 5 3 6 7 9 8))) +-> NIL +: (depth I) +-> 4 + +# Augment +: (balance 'I (sort (10 40 20 50 30 60 70 90 80)) T) +-> NIL +: (idx 'I) +-> (1 2 3 4 5 6 7 8 9 10 20 30 40 50 60 70 80 90) +</code></pre> + +<dt><a name="be"><code>(be sym . any) -> sym</code></a> +<dd>Declares a <a href="ref.html#pilog">Pilog</a> fact or rule for the +<code>sym</code> argument, by concatenating the <code>any</code> argument to the +<code>T</code> property of <code>sym</code>. See also <code><a +href="refA.html#asserta">asserta</a></code>, <code><a +href="refA.html#assertz">assertz</a></code>, <code><a +href="refR.html#retract">retract</a></code>, <code><a +href="refG.html#goal">goal</a></code> and <code><a +href="refP.html#prove">prove</a></code>. + +<pre><code> +: (be likes (John Mary)) +-> likes +: (be likes (John @X) (likes @X wine) (likes @X food)) +-> likes +: (get 'likes T) +-> (((John Mary)) ((John @X) (likes @X wine) (likes @X food))) +: (? (likes John @X)) + @X=Mary +-> NIL +</code></pre> + +<dt><a name="beep"><code>(beep) -> any</code></a> +<dd>Send the bell character to the console. See also <code><a +href="refP.html#prin">prin</a></code> and <code><a +href="refC.html#char">char</a></code>. + +<pre><code> +: (beep) +-> "^G" +</code></pre> + +<dt><a name="bench"><code>(bench . prg) -> any</code></a> +<dd>Benchmarks <code>prg</code>, by printing the time it took to execute, and +returns the result. See also <code><a href="refU.html#usec">usec</a></code>. + +<pre><code> +: (bench (wait 2000)) +1.996 sec +-> NIL +</code></pre> + +<dt><a name="bind"><code>(bind 'sym|lst . prg) -> any</code></a> +<dd>Binds value(s) to symbol(s). The first argument must evaluate to a symbol, +or a list of symbols or symbol-value pairs. The values of these symbols are +saved (and the symbols bound to the values in the case of pairs), +<code>prg</code> is executed, then the symbols are restored to their original +values. During execution of <code>prg</code>, the values of the symbols can be +temporarily modified. The return value is the result of <code>prg</code>. See +also <code><a href="refL.html#let">let</a></code>, <code><a +href="refJ.html#job">job</a></code> and <code><a +href="refU.html#use">use</a></code>. + +<pre><code> +: (setq X 123) # X is 123 +-> 123 +: (bind 'X (setq X "Hello") (println X)) # Set X to "Hello", print it +"Hello" +-> "Hello" +: (bind '((X . 3) (Y . 4)) (println X Y) (* X Y)) +3 4 +-> 12 +: X +-> 123 # X is restored to 123 +</code></pre> + +<dt><a name="bit?"><code>(bit? 'num ..) -> num | NIL</code></a> +<dd>Returns the first <code>num</code> argument when all bits which are 1 in the +first argument are also 1 in all following arguments. When one of those +arguments evaluates to <code>NIL</code>, it is returned immediately. See also +<code><a href="ref_.html#&">&</a></code>, <code><a +href="ref_.html#|">|</a></code> and <code><a href="refX.html#x|">x|</a></code>. + +<pre><code> +: (bit? 7 15 255) +-> 7 +: (bit? 1 3) +-> 1 +: (bit? 1 2) +-> NIL +</code></pre> + +<dt><a name="blob"><code>(blob 'obj 'sym) -> sym</code></a> +<dd>Returns the blob file name for <code>var</code> in <code>obj</code>. See +also <code><a href="refB.html#*Blob">*Blob</a></code>, <code><a +href="refB.html#blob!">blob!</a></code> and <code><a +href="refP.html#pack">pack</a></code>. + +<pre><code> +: (show (db 'nr '+Item 1)) +{3-1} (+Item) + jpg + pr 29900 + inv 100 + sup {2-1} + nm "Main Part" + nr 1 +-> {3-1} +: (blob '{3-1} 'jpg) +-> "blob/app/3/-/1.jpg" +</code></pre> + +<dt><a name="blob!"><code>(blob! 'obj 'sym 'file)</code></a> +<dd>Stores the contents of <code>file</code> in a <code><a +href="refB.html#blob">blob</a></code>. See also <code><a +href="refE.html#entityMesssages">put!></a></code>. + +<pre><code> +(blob! *ID 'jpg "picture.jpg") +</code></pre> + +<dt><a name="bool"><code>(bool 'any) -> flg</code></a> +<dd>Returns <code>T</code> when the argument <code>any</code> is +non-<code>NIL</code>. This function is only needed when <code>T</code> is +strictly required for a "true" condition (Usually, any non-<code>NIL</code> +value is considered to be "true"). See also <code><a +href="refF.html#flg?">flg?</a></code>. + +<pre><code> +: (and 3 4) +-> 4 +: (bool (and 3 4)) +-> T +</code></pre> + +<dt><a name="bool/3"><code>bool/3</code></a> +<dd><a href="ref.html#pilog">Pilog</a> predicate that succeeds if the first +argument has the same truth value as the result of applying the <code><a +href="refG.html#get">get</a></code> algorithm to the following arguments. +Typically used as filter predicate in <code><a +href="refS.html#select/3">select/3</a></code> database queries. See also +<code><a href="refB.html#bool">bool</a></code>, <code><a +href="refI.html#isa/2">isa/2</a></code>, <code><a +href="refS.html#same/3">same/3</a></code>, <code><a +href="refR.html#range/3">range/3</a></code>, <code><a +href="refH.html#head/3">head/3</a></code>, <code><a +href="refF.html#fold/3">fold/3</a></code>, <code><a +href="refP.html#part/3">part/3</a></code> and <code><a +href="refT.html#tolr/3">tolr/3</a></code>. + +<pre><code> +: (? @OK NIL # Find orders where the 'ok' flag is not set + (db nr +Ord @Ord) + (bool @OK @Ord ok) ) + @OK=NIL @Ord={3-7} +-> NIL +</code></pre> + +<dt><a name="box"><code>(box 'any) -> sym</code></a> +<dd>Creates and returns a new anonymous symbol. The initial value is set to the +<code>any</code> argument. See also <code><a href="refN.html#new">new</a></code> +and <code><a href="refB.html#box?">box?</a></code>. + +<pre><code> +: (show (box '(A B C))) +$134425627 (A B C) +-> $134425627 +</code></pre> + +<dt><a name="box?"><code>(box? 'any) -> sym | NIL</code></a> +<dd>Returns the argument <code>any</code> when it is an anonymous symbol, +otherwise <code>NIL</code>. See also <code><a +href="refB.html#box">box</a></code>, <code><a +href="refS.html#str?">str?</a></code> and <code><a +href="refE.html#ext?">ext?</a></code>. + +<pre><code> +: (box? (new)) +-> $134563468 +: (box? 123) +-> NIL +: (box? 'a) +-> NIL +: (box? NIL) +-> NIL +</code></pre> + +<dt><a name="by"><code>(by 'fun1 'fun2 'lst ..) -> lst</code></a> +<dd>Applies <code>fun1</code> to each element of <code>lst</code>. When +additional <code>lst</code> arguments are given, their elements are also passed +to <code>fun1</code>. Each result of <code>fun1</code> is CONSed with its +corresponding argument form the original <code>lst</code>, and collected into a +list which is passed to <code>fun2</code>. For the list returned from +<code>fun2</code>, the CAR elements returned by <code>fun1</code> are +(destructively) removed from each element. + +<pre><code> +: (let (A 1 B 2 C 3) (by val sort '(C A B))) +-> (A B C) +: (by '((N) (bit? 1 N)) group (3 11 6 2 9 5 4 10 12 7 8 1)) +-> ((3 11 9 5 7 1) (6 2 4 10 12 8)) +</code></pre> + +<dt><a name="bye"><code>(bye 'cnt|NIL)</code></a> +<dd>Executes all pending <code><a href="refF.html#finally">finally</a></code> +expressions, closes all open files, executes the <code>VAL</code> of the global +variable <code><a href="refB.html#*Bye">*Bye</a></code> (should be a +<code>prg</code>), flushes standard output, and then exits the PicoLisp +interpreter. The process return value is <code>cnt</code>, or 0 if the argument +is missing or <code>NIL</code>. + +<pre><code> +: (setq *Bye '((println 'OK) (println 'bye))) +-> ((println 'OK) (println 'bye)) +: (bye) +OK +bye +$ +</code></pre> + +</dl> + +</body> +</html> diff --git a/doc/refC.html b/doc/refC.html @@ -0,0 +1,657 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/1998/REC-html40-19980424/loose.dtd"> +<html lang="en"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> +<title>C</title> +<link rel="stylesheet" href="doc.css" type="text/css"> +</head> +<body> + +<h1>C</h1> + +<dl> + +<dt><a name="*Class"><code>*Class</code></a> +<dd>A global variable holding the current class. See also <code><a +href="ref.html#oop">OO Concepts</a></code>, <code><a +href="refC.html#class">class</a></code>, <code><a +href="refE.html#extend">extend</a></code>, <code><a +href="refD.html#dm">dm</a></code> and <code><a +href="refV.html#var">var</a></code> and <code><a +href="refR.html#rel">rel</a></code>. + +<pre><code> +: (class +Test) +-> +Test +: *Class +-> +Test +</code></pre> + +<dt><a name="cache"><code>(cache 'var 'sym . prg) -> any</code></a> +<dd>Speeds up some calculations, by holding previously calculated results in an +<code><a href="refI.html#idx">idx</a></code> tree structure. <code>sym</code> +must be a transient symbol representing a unique key for the argument(s) to the +calculation. + +<pre><code> +: (de fibonacci (N) + (cache '*Fibonacci (format N) + (if (> 2 N) + 1 + (+ + (fibonacci (dec N)) + (fibonacci (- N 2)) ) ) ) ) +-> fibonacci +: (fibonacci 22) +-> 28657 +: (fibonacci 10000) +-> 5443837311356528133873426099375038013538 ... # (2090 digits) +</code></pre> + +<dt><a name="call"><code>(call 'any ..) -> flg</code></a> +<dd>Calls an external system command. The <code>any</code> arguments specify the +command and its arguments. Returns <code>T</code> if the command was executed +successfully. + +<pre><code> +: (when (call 'test "-r" "file.l") # Test if file exists and is readable + (load "file.l") # Load it + (call 'rm "file.l") ) # Remove it +</code></pre> + +<dt><a name="call/1"><code>call/1</code></a> +<dd><a href="ref.html#pilog">Pilog</a> predicate that succeeds if the argument +term can be proven. + +<pre><code> +: (be mapcar (@ NIL NIL)) +-> mapcar +: (be mapcar (@P (@X . @L) (@Y . @M)) + (call @P @X @Y) # Call the given predicate + (mapcar @P @L @M) ) +-> mapcar +: (? (mapcar change (you are a computer) @Z)) +-> NIL +: (? (mapcar change (you are a computer) @Z) T) +-> NIL +: (? (mapcar permute ((a b c) (d e f)) @X)) + @X=((a b c) (d e f)) + @X=((a b c) (d f e)) + @X=((a b c) (e d f)) + ... + @X=((a c b) (d e f)) + @X=((a c b) (d f e)) + @X=((a c b) (e d f)) + ... +</code></pre> + +<dt><a name="can"><code>(can 'msg) -> lst</code></a> +<dd>Returns a list of all classes that accept the message <code>msg</code>. See +also <code><a href="ref.html#oop">OO Concepts</a></code>, <code><a +href="refC.html#class">class</a></code>, <code><a +href="refD.html#dep">dep</a></code>, <code><a +href="refW.html#what">what</a></code> and <code><a +href="refW.html#who">who</a></code>. + +<pre><code> +: (can 'zap>) +-> ((zap> . +relation) (zap> . +Blob) (zap> . +Entity)) +: (more @ pp) +(dm (zap> . +relation) (Obj Val)) + +(dm (zap> . +Blob) (Obj Val) + (and + Val + (call 'rm "-f" (blob Obj (: var))) ) ) + +(dm (zap> . +Entity) NIL + (for X (getl This) + (let V (or (atom X) (pop 'X)) + (and (meta This X) (zap> @ This V)) ) ) ) + +-> NIL +</code></pre> + +<dt><a name="car"><code>(car 'var) -> any</code></a> +<dd>List access: Returns the value of <code>var</code> if it is a symbol, or the +first element if it is a list. See also <code><a +href="refC.html#cdr">cdr</a></code> and <code><a +href="refC.html#cXr">c..r</a></code>. + +<pre><code> +: (car (1 2 3 4 5 6)) +-> 1 +</code></pre> + +<dt><a name="cXr"><code>(c[ad]*ar 'var) -> any</code></a> +<dt><code>(c[ad]*dr 'lst) -> any</code> +<dd>List access shortcuts. Combinations of the <code><a +href="refC.html#car">car</a></code> and <code><a +href="refC.html#cdr">cdr</a></code> functions, with up to four letters 'a' and +'d'. + +<pre><code> +: (cdar '((1 . 2) . 3)) +-> 2 +</code></pre> + +<dt><a name="case"><code>(case 'any (any1 . prg1) (any2 . prg2) ..) -> any</code></a> +<dd>Multi-way branch: <code>any</code> is evaluated and compared to the CAR +elements <code>anyN</code> of each clause. If one of them is a list, +<code>any</code> is in turn compared to all elements of that list. +<code>T</code> is a catch-all for any value. If a comparison succeeds, +<code>prgN</code> is executed, and the result returned. Otherwise +<code>NIL</code> is returned. See also <code><a +href="refS.html#state">state</a></code>. + +<pre><code> +: (case (char 66) ("A" (+ 1 2 3)) (("B" "C") "Bambi") ("D" (* 1 2 3))) +-> "Bambi" +</code></pre> + +<dt><a name="catch"><code>(catch 'any . prg) -> any</code></a> +<dd>Sets up the environment for a non-local jump which may be caused by <code><a +href="refT.html#throw">throw</a></code> or by a runtime error. If +<code>any</code> is an atom, it is used by <code>throw</code> as a jump label +(with <code>T</code> being a catch-all for any label), and a <code>throw</code> +called during the execution of <code>prg</code> will immediately return the +thrown value. Otherwise, <code>any</code> should be a list of strings, to catch +any error whose message contains one of these strings, and this will immediately +return the matching string. If neither <code>throw</code> nor an error occurs, +the result of <code>prg</code> is returned. See also <code><a +href="refF.html#finally">finally</a></code>, <code><a +href="refQ.html#quit">quit</a></code> and +<code><a href="ref.html#errors">Error Handling</a></code>. + +<pre><code> +: (catch 'OK (println 1) (throw 'OK 999) (println 2)) +1 +-> 999 +: (catch '("No such file") (in "doesntExist" (foo))) +-> "No such file" +</code></pre> + +<dt><a name="cd"><code>(cd 'any) -> sym</code></a> +<dd>Changes the current directory to <code>any</code>. The old directory is +returned on success, otherwise <code>NIL</code>. See also <code><a +href="refD.html#dir">dir</a></code> and <code><a +href="refP.html#pwd">pwd</a></code>. + +<pre><code> +: (when (cd "lib") + (println (sum lines (dir))) + (cd @) ) +10955 +</code></pre> + +<dt><a name="cdr"><code>(cdr 'lst) -> any</code></a> +<dd>List access: Returns all but the first element of <code>lst</code>. See also +<code><a href="refC.html#car">car</a></code> and <code><a +href="refC.html#cXr">c..r</a></code>. + +<pre><code> +: (cdr (1 2 3 4 5 6)) +-> (2 3 4 5 6) +</code></pre> + +<dt><a name="center"><code>(center 'cnt|lst 'any ..) -> sym</code></a> +<dd>Returns a transient symbol with all <code>any</code> arguments <code><a +href="refP.html#pack">pack</a></code>ed in a centered format. Trailing blanks +are omitted. See also <code><a href="refA.html#align">align</a></code>, <code><a +href="refT.html#tab">tab</a></code> and <code><a +href="refW.html#wrap">wrap</a></code>. + +<pre><code> +: (center 4 12) +-> " 12" +: (center 4 "a") +-> " a" +: (center 7 "a") +-> " a" +: (center (3 3 3) "a" "b" "c") +-> " a b c" +</code></pre> + +<dt><a name="chain"><code>(chain 'lst ..) -> lst</code></a> +<dd>Concatenates (destructively) one or several new list elements +<code>lst</code> to the end of the list in the current <code><a +href="refM.html#make">make</a></code> environment. This operation is efficient +also for long lists, because a pointer to the last element of the result list is +maintained. <code>chain</code> returns the last linked argument. See also +<code><a href="refL.html#link">link</a></code>, <code><a +href="refY.html#yoke">yoke</a></code> and <code><a +href="refM.html#made">made</a></code>. + +<pre><code> +: (make (chain (list 1 2 3) NIL (cons 4)) (chain (list 5 6))) +-> (1 2 3 4 5 6) +</code></pre> + +<dt><a name="char"><code>(char) -> sym</code></a> +<dt><code>(char 'cnt) -> sym</code> +<dt><code>(char T) -> sym</code> +<dt><code>(char 'sym) -> cnt</code> +<dd>When called without arguments, the next character from the current input +stream is returned as a single-character transient symbol, or <code>NIL</code> +upon end of file. When called with a number <code>cnt</code>, a character with +the corresponding unicode value is returned. As a special case, <code>T</code> +is accepted to produce a byte value greater than any first byte in a UTF-8 +character (used as a top value in comparisons). Otherwise, when called with a +symbol <code>sym</code>, the numeric unicode value of the first character of the +name of that symbol is returned. See also <code><a +href="refP.html#peek">peek</a></code>, <code><a +href="refS.html#skip">skip</a></code>, <code><a +href="refK.html#key">key</a></code>, <code><a +href="refL.html#line">line</a></code>, <code><a +href="refT.html#till">till</a></code> and <code><a +href="refE.html#eof">eof</a></code>. + +<pre><code> +: (char) # Read character from console +A # (typed 'A' and a space/return) +-> "A" +: (char 100) # Convert unicode to symbol +-> "d" +: (char T) # Special case, catch all +-> # (not printable) +: (char "d") # Convert symbol to unicode +-> 100 +</code></pre> + +<dt><a name="chdir"><code>(chdir 'any . prg) -> any</code></a> +<dd>Changes the current directory to <code>any</code> with <code><a +href="refC.html#cd">cd</a></code> during the execution of <code>prg</code>. Then +the previous directory will be restored and the result of <code>prg</code> +returned. See also <code><a href="refD.html#dir">dir</a></code> and <code><a +href="refP.html#pwd">pwd</a></code>. + +<pre><code> +: (pwd) +-> "/usr/abu/pico" +: (chdir "src" (pwd)) +-> "/usr/abu/pico/src" +: (pwd) +-> "/usr/abu/pico" +</code></pre> + +<dt><a name="chkTree"><code>(chkTree 'sym ['fun]) -> num</code></a> +<dd>Checks a database tree node (and recursively all sub-nodes) for consistency. +Returns the total number of nodes checked. Optionally, <code>fun</code> is +called with the key and value of each node, and should return <code>NIL</code> +for failure. See also <code><a href="refT.html#tree">tree</a></code> and +<code><a href="refR.html#root">root</a></code>. + +<pre><code> +: (show *DB '+Item) +{C} NIL + sup (7 . {7-3}) + nr (7 . {7-1}) # 7 nodes in the 'nr' tree, base node is {7-1} + pr (7 . {7-4}) + nm (77 . {7-6}) +-> {C} +: (chkTree '{7-1}) # Check that node +-> 7 +</code></pre> + +<dt><a name="chop"><code>(chop 'any) -> lst</code></a> +<dd>Returns <code>any</code> as a list of single-character strings. If +<code>any</code> is <code>NIL</code> or a symbol with no name, <code>NIL</code> +is returned. A list argument is returned unchanged. + +<pre><code> +: (chop 'car) +-> ("c" "a" "r") +: (chop "Hello") +-> ("H" "e" "l" "l" "o") +</code></pre> + +<dt><a name="circ"><code>(circ 'any ..) -> lst</code></a> +<dd>Produces a circular list of all <code>any</code> arguments by <code><a +href="refC.html#cons">cons</a></code>ing them to a list and then connecting the +CDR of the last cell to the first cell. See also <code><a +href="refL.html#list">list</a></code>. + +<pre><code> +: (circ 'a 'b 'c) +-> (a b c .) +</code></pre> + +<dt><a name="class"><code>(class sym . typ) -> obj</code></a> +<dd>Defines <code>sym</code> as a class with the superclass(es) +<code>typ</code>. As a side effect, the global variable <code><a +href="refC.html#*Class">*Class</a></code> is set to <code>obj</code>. See also +<code><a href="refE.html#extend">extend</a></code>, <code><a +href="refD.html#dm">dm</a></code>, <code><a href="refV.html#var">var</a></code>, +<code><a href="refR.html#rel">rel</a></code>, <code><a +href="refT.html#type">type</a></code>, <code><a +href="refI.html#isa">isa</a></code> and <code><a +href="refO.html#object">object</a></code>. + +<pre><code> +: (class +A +B +C +D) +-> +A +: +A +-> (+B +C +D) +: (dm foo> (X) (bar X)) +-> foo> +: +A +-> ((foo> (X) (bar X)) +B +C +D) +</code></pre> + +<dt><a name="clause/2"><code>clause/2</code></a> +<dd><a href="ref.html#pilog">Pilog</a> predicate that succeeds if the first +argument is a predicate which has the second argument defined as a clause. + +<pre><code> +: (? (clause append ((NIL @X @X)))) +-> T + +: (? (clause append @C)) + @C=((NIL @X @X)) + @C=(((@A . @X) @Y (@A . @Z)) (append @X @Y @Z)) +-> NIL +</code></pre> + +<dt><a name="clip"><code>(clip 'lst) -> lst</code></a> +<dd>Returns a copy of <code>lst</code> with all white space characters or +<code>NIL</code> elements removed from both sides. See also <code><a +href="refT.html#trim">trim</a></code>. + +<pre><code> +: (clip '(NIL 1 NIL 2 NIL)) +-> (1 NIL 2) +: (clip '(" " a " " b " ")) +-> (a " " b) +</code></pre> + +<dt><a name="close"><code>(close 'cnt) -> cnt | NIL</code></a> +<dd>Closes a file descriptor <code>cnt</code>, and returns it when successful. +Should not be called inside an <code><a href="refO.html#out">out</a></code> body +for that descriptor. See also <code><a href="refO.html#open">open</a></code>, +<code><a href="refL.html#listen">listen</a></code> and <code><a +href="refC.html#connect">connect</a></code>. + +<pre><code> +: (close 2) # Close standard error +-> 2 +</code></pre> + +<dt><a name="cmd"><code>(cmd ['any]) -> sym</code></a> +<dd>When called without an argument, the name of the command that invoked the +picolisp interpreter is returned. Otherwise, the command name is set to +<code>any</code>. Setting the name may not work on some operating systems. Note +that the new name must not be longer than the original one. See also <code><a +href="refA.html#argv">argv</a></code> and <code><a +href="ref.html#invoc">Invocation</a></code>. + +<pre><code> +$ ./dbg +: (cmd) +-> "./bin/picolisp" +: (cmd "!/bin/picolust") +-> "!/bin/picolust" +: (cmd) +-> "!/bin/picolust" +</code></pre> + +<dt><a name="cnt"><code>(cnt 'fun 'lst ..) -> cnt</code></a> +<dd>Applies <code>fun</code> to each element of <code>lst</code>. When +additional <code>lst</code> arguments are given, their elements are also passed +to <code>fun</code>. Returns the count of non-<code>NIL</code> values returned +from <code>fun</code>. + +<pre><code> +: (cnt cdr '((1 . T) (2) (3 4) (5))) +-> 2 +</code></pre> + +<dt><a name="collect"><code>(collect 'var 'cls ['hook] ['any|beg ['end [var ..]]])</code></a> +<dd>Returns a list of all database objects of class <code>cls</code>, where the +values for the <code>var</code> arguments correspond to the <code>any</code> +arguments, or where the values for the <code>var</code> arguments are in the +range <code>beg</code> .. <code>end</code>. <code>var</code>, <code>cls</code> +and <code>hook</code> should specify a <code><a +href="refT.html#tree">tree</a></code> for <code>cls</code> or one of its +superclasses. If additional <code>var</code> arguments are given, the final +values for the result list are obtained by applying the <code><a +href="refG.html#get">get</a></code> algorithm. See also <code><a +href="refD.html#db">db</a></code>, <code><a href="refA.html#aux">aux</a></code>, +<code><a href="refF.html#fetch">fetch</a></code>, <code><a +href="refI.html#init">init</a></code> and <code><a +href="refS.html#step">step</a></code>.