Changes In Branch selfcontained Through [f4a40c5778] Excluding Merge-Ins
This is equivalent to a diff from 18e7e965e2 to f4a40c5778
2015-09-27
| ||
06:05 | Added s:hd check-in: f0e4b568c0 user: matt tags: selfcontained | |
2015-04-14
| ||
04:45 | Merged selfcontained back to trunk check-in: d3fdfad50d user: matt tags: trunk | |
2015-01-27
| ||
05:02 | Tweaked config file locating. Added thead and tbody. check-in: f4a40c5778 user: matt tags: selfcontained | |
2015-01-25
| ||
21:20 | Little bit done on documentation check-in: 36a29ccc0a user: matt tags: selfcontained | |
2013-05-17
| ||
07:08 | refactor for selfcontained executables (incomplete) check-in: 55a8152be6 user: matt tags: selfcontained | |
2013-02-03
| ||
05:25 | Added additional verbage for debug and setup easing check-in: 18e7e965e2 user: matt tags: trunk | |
2013-01-09
| ||
06:20 | Fixed output of error in error page check-in: 60f784c4db user: matt tags: trunk | |
Modified Makefile from [90d147b144] to [6f36870ae1].
1 2 3 4 5 6 7 8 | # Copyright 2007-2008, Matthew Welland. # # This program is made available under the GNU GPL version 2.0 or # greater. See the accompanying file COPYING for details. # # This program is distributed WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR # PURPOSE. | | > > > > | > | > | > > > > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | # Copyright 2007-2008, Matthew Welland. # # This program is made available under the GNU GPL version 2.0 or # greater. See the accompanying file COPYING for details. # # This program is distributed WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR # PURPOSE. # # Following needed on bluehost # # CSC_OPTIONS='-C "-fPIC"' make # include install.cfg SRCFILES = stml.scm misc-stml.scm session.scm sqltbl.scm formdat.scm setup.scm keystore.scm html-filter.scm cookie.scm MODULEFILES = $(wildcard modules/*/*-mod.scm) SOFILES = $(MODULEFILES:%.scm=%.so) CFILES = $(MODULEFILES:%.scm=%.c) OFILES = $(SRCFILES:%.scm=%.o) TARGFILES = $(notdir $(SOFILES)) MODULES = $(addprefix $(TARGDIR)/modules/,$(TARGFILES)) install : $(TARGDIR)/stmlrun $(LOGDIR) $(MODULES) chicken-install all : $(SOFILES) # stmlrun : stmlrun.scm formdat.scm misc-stml.scm session.scm stml.scm \ # setup.scm html-filter.scm requirements.scm keystore.scm \ # cookie.scm sqltbl.scm # csc stmlrun.scm $(TARGDIR)/stmlrun : stmlrun stml.so echo "NOTE: CSC_OPTIONS='-C \"-fPIC\"' make" install stmlrun $(TARGDIR) chmod a+rx $(TARGDIR)/stmlrun $(TARGDIR)/modules : mkdir -p $(TARGDIR)/modules $(MODULES) : $(SOFILES) $(TARGDIR)/modules cp $< $@ stmlrun : $(OFILES) stmlrun.scm requirements.scm stmlcommon.scm csc $(OFILES) stmlrun.scm -o stmlrun stml.so : stmlmodule.so cp stmlmodule.so stml.so stmlmodule.so : $(OFILES) stmlmodule.scm requirements.scm stmlcommon.scm csc $(OFILES) -s stmlmodule.scm # logging currently relies on this # $(LOGDIR) : mkdir -p $(LOGDIR) chmod a+rwx $(LOGDIR) |
︙ | ︙ |
Modified doc/howto.txt from [f196be1330] to [9db6996c14].
1 2 3 | Gotchas! ======= | | > > | > > | > > > > | > | > | > | | > | | > | | > | | > | | > | > > > > > > > > > > > > > | > | | > < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | Gotchas! ======= All items for a page *must* be part of a list! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ OK: (list (function1 param1)(function2 param2)) NOT OK: (begin (function1 param1)(function2 param2)) Various components ~~~~~~~~~~~~~~~~~~ The URL: http://the.domain.com/pagename/p1/p2/p3?param1=value1 (s:get-page-params) => '("p1" "p2") (s:get-param 'param1) => "value1" Create a link. ~~~~~~~~~~~~~~ (s:null "[" (s:a name 'href (s:link-to (string-append "location/" (string-intersperse p "/") ""))) "] "))) Call current page with new param ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In view.scm: (s:center "[" (s:a 'href (s:link-to "polls" 'id (begin (poll:poll 'fill-polls) (poll:poll 'get-next-poll))) "Go to the next poll") "]") In control.scm: (let ((poll-id (s:get-param 'id))) ;; do stuff based on poll-id Call an action on a specific page ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ (s:a 'href (s:link-to "polls" 'id (poll:poll 'get 'id) 'action "poll.edit") "Suggest changes to this poll") NOT TRUE! This calls fuction poll.edit (should be in control.scm). Parameter set is 'id to a poll num. A complex link example ~~~~~~~~~~~~~~~~~~~~~~ (s:a "Reply" 'href (s:link-to (s:current-page) 'action "discussion.reply" ;; <page>.<action> 'reply_to (number->string (hash-table-ref row 'posts.id)) 'id (s:get "discussion.parent_object_id")) "reply") ;; use (s:get-param to get the 'id, or 'reply_to values Get and set a session var ~~~~~~~~~~~~~~~~~~~~~~~~~ (s:session-var-get "keyname") (s:session-var-set! "keyname" "value") 5.1 Page local vars (s:set! key val) (s:get key) make a selection drop down ~~~~~~~~~~~~~~~~~~~~~~~~~~ In view.scm: (s:select '(("World" 0)("Country" 1)("State" 2)("Town/City" 3)) 'name 'scope) In control.scm: (let ((scope (s:get-input 'scope))) .... Simple error reporting ~~~~~~~~~~~~~~~~~~~~~~ In control.scm: (s:set-err "You must provide an email address") In view.scm: (s:get-err s:err-font) Or: (s:get-err (lambda (x)(s:err-font x (s:br)))) Sharing data between pages ~~~~~~~~~~~~~~~~~~~~~~~~~~ NOTE: This data is *not* preserved between cgi calls. ;; In first page called (s:shared-set! "somekey" somevalue) ;; In a page called later (let ((dat (s:shared-get "somekey"))) ( .... )) Misc useful stuff ~~~~~~~~~~~~~~~~~ i. Lazy/safe string->number (s:any->number val) ii. Random string (session:make-rand-string len) iii. string to number for pgint (s:any->pgint val) Forms and input ~~~~~~~~~~~~~~~ (s:form 'action "login.login" 'method "post" (s:input-preserve 'type "text" 'name "email-address" 'size "16" 'maxlength "30") (s:input 'type "submit" 'name "form-name" 'value "login")) (s:get-input 'email-address) To preserve the input simply do a set of the value on the 'name field: (s:set! "email-address" "matt@kiatoa.com") |
Modified doc/manual.txt from [a5e8c49fa9] to [ae796565bb].
1 2 3 4 5 | STML User Manual ================ Matt Welland <matt@kiatoa.com> v1.0, 2012-6 | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 | STML User Manual ================ Matt Welland <matt@kiatoa.com> v1.0, 2012-6 NOT DONE YET! :( sorry. :numbered!: [abstract] Example Abstract ---------------- Yada about stml |
︙ | ︙ |
Deleted doc/stml-manual.odt version [55a66e4646].
cannot compute difference between binary files
Modified formdat.scm from [24de706a4e] to [5b06a4d3e0].
︙ | ︙ | |||
31 32 33 34 35 36 37 | (define-inline (formdat:formdat-get-data vec) (vector-ref vec 0)) (define-inline (formdat:formdat-set-data! vec val)(vector-set! vec 0 val)) (define (formdat:initialize self) (formdat:formdat-set-data! self (make-hash-table))) (define (formdat:get self key) | | > > > > > > | 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | (define-inline (formdat:formdat-get-data vec) (vector-ref vec 0)) (define-inline (formdat:formdat-set-data! vec val)(vector-set! vec 0 val)) (define (formdat:initialize self) (formdat:formdat-set-data! self (make-hash-table))) (define (formdat:get self key) (hash-table-ref/default (formdat:formdat-get-data self) (cond ((symbol? key) key) ((string? key) (string->symbol key)) (else key)) #f)) ;; change to convert data to list and append val if already exists ;; or is a list (define (formdat:set! self key val) (let ((prev-val (formdat:get self key)) (ht (formdat:formdat-get-data self))) (if prev-val |
︙ | ︙ |
Modified misc-stml.scm from [9d5a337236] to [9494e07667].
︙ | ︙ | |||
129 130 131 132 133 134 135 | ;; openssl passwd -crypt -salt xx password ;; (define (s:crypt-passwd pw s) (let* ((salt (if s s (session:make-rand-string 2))) (inp (open-input-pipe ;;(string-append "echo " pw " | mkpasswd -S " salt " -s"))) | | > > > > > | | 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 | ;; openssl passwd -crypt -salt xx password ;; (define (s:crypt-passwd pw s) (let* ((salt (if s s (session:make-rand-string 2))) (inp (open-input-pipe ;;(string-append "echo " pw " | mkpasswd -S " salt " -s"))) ;; (conc "mkpasswd " pw " " salt) (conc "openssl passwd -crypt -salt " salt " " pw) )) (res (read-line inp))) (close-input-port inp) res)) (define (s:password-match? password crypted) (let* ((salt (substring crypted 0 2)) (pcrypted (s:crypt-passwd password salt))) (s:log "INFO: pcrypted=" pcrypted " crypted=" crypted) (and (string? password) (string? pcrypted) (string=? pcrypted crypted)))) ;; (read-line (open-input-pipe "echo foo | mkpasswd -S ab -s")) (define (s:error-page . err) (s:cgi-out (cons "Content-type: text/html; charset=iso-8859-1\n\n" (s:html (s:head (s:title err) |
︙ | ︙ | |||
168 169 170 171 172 173 174 | (res '())) (if (eof-object? l) (s:log res) (loop (read-line p)(cons (list l "<BR>") res))))) #t)))) (define (s:validate-inputs) | > | | | | | | 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 | (res '())) (if (eof-object? l) (s:log res) (loop (read-line p)(cons (list l "<BR>") res))))) #t)))) (define (s:validate-inputs) (if (not (s:validate-uri)) (begin (s:error-page "Bad URI" (let ((ref (get-environment-variable "HTTP_REFERER"))) (if ref (list "referred from" ref) ""))) (exit)))) ;; anything except a list is converted to a string!!! (define (s:any->string val) (cond ((string? val) val) ((number? val) (number->string val)) ((symbol? val) (symbol->string val)) |
︙ | ︙ |
Modified requirements.scm.template from [e48452c17e] to [b71aaa144e].
1 2 3 4 | ;; choose your db interface as appropriate (require-extension sqlite3) (import (prefix sqlite3 sqlite3:)) | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 | ;; choose your db interface as appropriate (require-extension sqlite3) (import (prefix sqlite3 sqlite3:)) ;; (require-extension postgresql) ;; (import (prefix postgresql pg:)) ;; (require-extension cgi-util) ;; (require-extension cookie) (use posix) ;; (require-extension proplist) (use regex) (use srfi-1) |
︙ | ︙ |
Added rollup-pages.scm version [b24bc2e231].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | (use regex posix srfi-69 srfi-1) (define extract-rx (regexp "pages\\/(.*)_(view|ctrl).scm")) (define (print-page-wrapper lookup page) (print "(define (pages:" page " session db shared)") (if (hash-table-ref/default lookup (conc page "_ctrl") #f) (print "(include \"pages/" page "_ctrl.scm\")")) (if (hash-table-ref/default lookup (conc page "_view") #f) (print "(include \"pages/" page "_view.scm\")")) (print ")\n")) (let* ((views (glob "pages/*_view.scm")) (ctrls (glob "pages/*_ctrl.scm")) (all (append views ctrls)) (lookup (make-hash-table)) (pages (delete-duplicates (map (lambda (x) (let* ((res (string-match extract-rx x)) (page (cadr res)) (type (caddr res))) (hash-table-set! lookup (conc page "_" type) #t) (cadr res))) all)))) (if (null? all)(begin (print "No page files matching pages/*_(view|ctrl).scm")(exit))) (print "Pages: " pages) ;; first the individual rollup wrappers (used by the dynamic load) (for-each (lambda (page) (let ((pagefile (conc "pages/" page ".scm"))) (print "page " page " ") (if (not (file-exists? pagefile)) (begin (with-output-to-file pagefile (lambda () (print-page-wrapper lookup page))) (print " created")) (print " already created")))) pages) ;; then the monolithic rollup wrapper (used in compiling the single-executable) (with-output-to-file "all_pages.scm" (lambda () (for-each (lambda (page) (print-page-wrapper lookup page)) pages)))) |
Modified session.scm from [c4e9fdabd2] to [b28c169b67].
︙ | ︙ | |||
22 23 24 25 26 27 28 | ;; TODO ;; Concept of order num incremented with each page access ;; if a branch is taken then a new session would need to be created ;; ;; make-vector-record session session dbtype dbinit conn params path-params session-key session-id domain toppage page curr-page content-type page-type sroot twikidir pagedat alt-page-dat pagevars pagevars-before sessionvars sessionvars-before globalvars globalvars-before logpt formdat request-method session-cookie curr-err log-port logfile seen-pages page-dir-style debugmode | | | 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | ;; TODO ;; Concept of order num incremented with each page access ;; if a branch is taken then a new session would need to be created ;; ;; make-vector-record session session dbtype dbinit conn params path-params session-key session-id domain toppage page curr-page content-type page-type sroot twikidir pagedat alt-page-dat pagevars pagevars-before sessionvars sessionvars-before globalvars globalvars-before logpt formdat request-method session-cookie curr-err log-port logfile seen-pages page-dir-style debugmode (define (make-sdat)(make-vector 34)) (define (sdat-get-dbtype vec) (vector-ref vec 0)) (define (sdat-get-dbinit vec) (vector-ref vec 1)) (define (sdat-get-conn vec) (vector-ref vec 2)) (define (sdat-get-pgconn vec) (vector-ref (vector-ref vec 2) 1)) (define (sdat-get-params vec) (vector-ref vec 3)) (define (sdat-get-path-params vec) (vector-ref vec 4)) (define (sdat-get-session-key vec) (vector-ref vec 5)) |
︙ | ︙ | |||
57 58 59 60 61 62 63 64 65 66 67 68 69 70 | (define (sdat-get-session-cookie vec) (vector-ref vec 26)) (define (sdat-get-curr-err vec) (vector-ref vec 27)) (define (sdat-get-log-port vec) (vector-ref vec 28)) (define (sdat-get-logfile vec) (vector-ref vec 29)) (define (sdat-get-seen-pages vec) (vector-ref vec 30)) (define (sdat-get-page-dir-style vec) (vector-ref vec 31)) (define (sdat-get-debugmode vec) (vector-ref vec 32)) (define (sdat-set-dbtype! vec val)(vector-set! vec 0 val)) (define (sdat-set-dbinit! vec val)(vector-set! vec 1 val)) (define (sdat-set-conn! vec val)(vector-set! vec 2 val)) (define (sdat-set-params! vec val)(vector-set! vec 3 val)) (define (sdat-set-path-params! vec val)(vector-set! vec 4 val)) (define (sdat-set-session-key! vec val)(vector-set! vec 5 val)) (define (sdat-set-session-id! vec val)(vector-set! vec 6 val)) | > > > > > | 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | (define (sdat-get-session-cookie vec) (vector-ref vec 26)) (define (sdat-get-curr-err vec) (vector-ref vec 27)) (define (sdat-get-log-port vec) (vector-ref vec 28)) (define (sdat-get-logfile vec) (vector-ref vec 29)) (define (sdat-get-seen-pages vec) (vector-ref vec 30)) (define (sdat-get-page-dir-style vec) (vector-ref vec 31)) (define (sdat-get-debugmode vec) (vector-ref vec 32)) (define (sdat-get-shared-hash vec) (vector-ref vec 33)) (define (session:get-shared vec varname) (hash-table-ref/default (vector-ref vec 33) varname #f)) (define (sdat-set-dbtype! vec val)(vector-set! vec 0 val)) (define (sdat-set-dbinit! vec val)(vector-set! vec 1 val)) (define (sdat-set-conn! vec val)(vector-set! vec 2 val)) (define (sdat-set-params! vec val)(vector-set! vec 3 val)) (define (sdat-set-path-params! vec val)(vector-set! vec 4 val)) (define (sdat-set-session-key! vec val)(vector-set! vec 5 val)) (define (sdat-set-session-id! vec val)(vector-set! vec 6 val)) |
︙ | ︙ | |||
90 91 92 93 94 95 96 97 | (define (sdat-set-session-cookie! vec val)(vector-set! vec 26 val)) (define (sdat-set-curr-err! vec val)(vector-set! vec 27 val)) (define (sdat-set-log-port! vec val)(vector-set! vec 28 val)) (define (sdat-set-logfile! vec val)(vector-set! vec 29 val)) (define (sdat-set-seen-pages! vec val)(vector-set! vec 30 val)) (define (sdat-set-page-dir-style! vec val)(vector-set! vec 31 val)) (define (sdat-set-debugmode! vec val)(vector-set! vec 32 val)) | > < < < < < < < | < < | | < < < < < < < < < | < < < | < < < < < < < < | 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | (define (sdat-set-session-cookie! vec val)(vector-set! vec 26 val)) (define (sdat-set-curr-err! vec val)(vector-set! vec 27 val)) (define (sdat-set-log-port! vec val)(vector-set! vec 28 val)) (define (sdat-set-logfile! vec val)(vector-set! vec 29 val)) (define (sdat-set-seen-pages! vec val)(vector-set! vec 30 val)) (define (sdat-set-page-dir-style! vec val)(vector-set! vec 31 val)) (define (sdat-set-debugmode! vec val)(vector-set! vec 32 val)) (define (sdat-set-shared-hash! vec val)(vector-set! vec 33 val)) (define (session:set-shared! vec varname val) (hash-table-set! (vector-ref vec 33) varname val)) ;; The global session (define s:session (make-sdat)) ;; SPLIT INTO STRAIGHT FORWARD INIT AND COMPLEX INIT (define (session:initialize self) (sdat-set-dbtype! self 'pg) (sdat-set-page! self "home") ;; these are defaults (sdat-set-curr-page! self "home") (sdat-set-content-type! self "Content-type: text/html; charset=iso-8859-1\n\n") |
︙ | ︙ | |||
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 | (if debugmode (sdat-set-debugmode! self debugmode)) (sdat-set-page-dir-style! self page-dir) ;; (print "configdat: ")(pp configdat) (if debugmode (session:log self "sroot: " sroot " logfile: " logfile " dbtype: " dbtype " dbinit: " dbinit " domain: " domain " page-dir-style: " page-dir)) ) ) ;; (let ((dbtype (sdat-get-dbtype self))) ;; (print "dbtype: " dbtype) ;; (sdat-set-dbtype! self (eval dbtype)))) (define (session:setup self) (let ((dbtype (sdat-get-dbtype self)) (debugmode (sdat-get-debugmode self)) (dbinit (eval (sdat-get-dbinit self))) (dbexists #f)) (let ((dbfname (alist-ref 'dbname dbinit))) (if debugmode (session:log self "session:setup dbfname=" dbfname ", dbtype=" dbtype ", dbinit=" dbinit)) (if (eq? dbtype 'sqlite3) (let ((dbpath (pathname-directory dbfname))) ;; do a couple sanity checks here to make setting up easier (if debugmode (session:log self "INFO: setting up for sqlite3 db access to " dbfname)) (if (not (file-write-access? dbpath)) (session:log self "WARNING: Cannot write to " dbpath) (if debugmode (session:log self "INFO: " dbpath " is writeable"))) (if (file-exists? dbfname) (begin ;; (session:log self "setting dbexists to #t") (set! dbexists #t)))) (if debugmode (session:log self "INFO: setting up for pg db access to account info " dbinit))) (if debugmode (session:log self "dbtype: " dbtype " dbfname: " dbfname " dbexists: " dbexists))) (sdat-set-conn! self (dbi:open dbtype dbinit)) (if (and (not dbexists)(eq? dbtype 'sqlite3)) (begin (print "WARNING: Setting up session db with sqlite3") (session:setup-db self))) (session:process-url-path self) (session:setup-session-key self) ;; capture stdin if this is a POST | > > > > > > > > | 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 | (if debugmode (sdat-set-debugmode! self debugmode)) (sdat-set-page-dir-style! self page-dir) ;; (print "configdat: ")(pp configdat) (if debugmode (session:log self "sroot: " sroot " logfile: " logfile " dbtype: " dbtype " dbinit: " dbinit " domain: " domain " page-dir-style: " page-dir)) ) (sdat-set-shared-hash! self (make-hash-table)) ) ;; Used for the strangely inconsistent handling of the config file. A better way is needed. ;; ;; (let ((dbtype (sdat-get-dbtype self))) ;; (print "dbtype: " dbtype) ;; (sdat-set-dbtype! self (eval dbtype)))) (define (session:setup self) (let ((dbtype (sdat-get-dbtype self)) (debugmode (sdat-get-debugmode self)) (dbinit (eval (sdat-get-dbinit self))) (dbexists #f)) (let ((dbfname (alist-ref 'dbname dbinit))) (if debugmode (session:log self "session:setup dbfname=" dbfname ", dbtype=" dbtype ", dbinit=" dbinit)) (if (eq? dbtype 'sqlite3) ;; The 'auto method will distribute dbs across the disk using hash ;; of user host and user. TODO ;; (if (eq? dbfname 'auto) ;; This is the auto assignment of a db based on hash of IP (let ((dbpath (pathname-directory dbfname))) ;; do a couple sanity checks here to make setting up easier (if debugmode (session:log self "INFO: setting up for sqlite3 db access to " dbfname)) (if (not (file-write-access? dbpath)) (session:log self "WARNING: Cannot write to " dbpath) (if debugmode (session:log self "INFO: " dbpath " is writeable"))) (if (file-exists? dbfname) (begin ;; (session:log self "setting dbexists to #t") (set! dbexists #t)))) (if debugmode (session:log self "INFO: setting up for pg db access to account info " dbinit))) (if debugmode (session:log self "dbtype: " dbtype " dbfname: " dbfname " dbexists: " dbexists))) (sdat-set-conn! self (dbi:open dbtype dbinit)) (set! *db* (sdat-get-conn self)) (if (and (not dbexists)(eq? dbtype 'sqlite3)) (begin (print "WARNING: Setting up session db with sqlite3") (session:setup-db self))) (session:process-url-path self) (session:setup-session-key self) ;; capture stdin if this is a POST |
︙ | ︙ | |||
448 449 450 451 452 453 454 | (define (session:page-get self key) (hash-table-ref/default (sdat-get-pagevars self) key #f)) ;; get session vars for a specified page ;; (define (session:get self page key) (let ((ht (session:get-page-hash self page))) | | | | 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 | (define (session:page-get self key) (hash-table-ref/default (sdat-get-pagevars self) key #f)) ;; get session vars for a specified page ;; (define (session:get self page key) (let ((ht (session:get-page-hash self page))) (hash-table-ref/default ht (s:any->string key) #f))) ;; delete a session var for a specified page ;; (define (session:del! self page key) (let ((ht (session:get-page-hash self page))) (hash-table-delete! ht (s:any->string key)))) ;; get ALL keys for this page and store in the session pagevars hash ;; (define (session:get-vars self) (let ((session-id (sdat-get-session-id self))) (if (not session-id) (err:log "ERROR: No session id in session object! session:get-vars") |
︙ | ︙ | |||
561 562 563 564 565 566 567 | (s:sqlparam ins-query session-id page key master-value))) (else (err:log "Shouldn't get here"))))) all-keys))) ;; process all keys (list "*sessionvars*" "*globalvars*" page-name)))))) ;; (pg:sql-null-object? element) (define (session:read-config self) | > | | 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 | (s:sqlparam ins-query session-id page key master-value))) (else (err:log "Shouldn't get here"))))) all-keys))) ;; process all keys (list "*sessionvars*" "*globalvars*" page-name)))))) ;; (pg:sql-null-object? element) (define (session:read-config self) (let* ((cgi-path (pathname-directory (car (argv)))) (name (string-append (if cgi-path (conc cgi-path "/") "") "." (pathname-file (car (argv))) ".config"))) (if (not (file-exists? name)) (print name " not found at " (current-directory)) (let* ((fp (open-input-file name)) (initargs (read fp))) (close-input-port fp) initargs)))) |
︙ | ︙ | |||
602 603 604 605 606 607 608 609 610 611 612 | (cond ((list? x) x) ((string? x) x) (else '()))) (port-map (lambda (s) (eval s e)) (lambda ()(read p)))))) ;; May 2011, putting all pages into one directory for the following reasons: ;; 1. want filename to reflect page name (emacs limitation) ;; 2. that's it! no other reason. could make it configurable ... | > > > > > > > > > > > > > > | < | < | | | | | < | > | > > > > > | | | < | < < < < < | | | < < < < < < < | | > > | > > > > | | | | | | | < < < < < < | < < < < < < < < < < | | | < > | | | | | | | | | | | 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 | (cond ((list? x) x) ((string? x) x) (else '()))) (port-map (lambda (s) (eval s e)) (lambda ()(read p)))))) (define (session:process-file f) (let* ((p (open-input-file f)) (dat (process-port p))) (close-input-port p) dat)) ;; May 2011, putting all pages into one directory for the following reasons: ;; 1. want filename to reflect page name (emacs limitation) ;; 2. that's it! no other reason. could make it configurable ... ;; page-dir-style is: ;; 'stored => stored in executable ;; 'flat => pages flat directory ;; 'dir => directory tree pages/<pagename>/{view,control}.scm ;; parts: ;; 'both => load control and view (anything other than view or control ;; 'view => load view only ;; 'control => load control only (define (session:call-parts self page #!key (parts 'both)) (sdat-set-curr-page! self page) (let* ((dir-style (sdat-get-page-dir-style self));; (equal? (sdat-get-page-dir-style self) "onedir")) ;; flag #t for onedir, #f for old style (dir (string-append (sdat-get-sroot self) (if dir-style (conc "/pages/") (conc "/pages/" page))))) (case dir-style ;; NB// Stored always loads both control and view ((stored) ((eval (string->symbol (conc "pages:" page))) self ;; the session (sdat-get-conn self) ;; the db connection (sdat-get-shared-hash self) ;; a shared hash table for passing data to/from page calls )) ((flat) (let* ((so-file (conc dir page ".so")) (scm-file (conc dir page ".scm")) (src-file (or (file-exists? so-file) (file-exists? scm-file)))) (if src-file (begin (load src-file) ((eval (string->symbol (conc "pages:" page))) self ;; the session (sdat-get-conn self) ;; the db connection (sdat-get-shared-hash self) ;; a shared hash table for passing data to/from page calls )) (list "<p>Page not found " page " </p>")))) ;; first the control ;; (let ((control-file (conc "pages/" page "_ctrl.scm")) ;; (view-file (conc "pages/" page "_view.scm"))) ;; (if (and (file-exists? control-file) ;; (not (eq? parts 'view))) ;; (begin ;; (session:set-called! self page) ;; (load control-file))) ;; (if (file-exists? view-file) ;; (if (not (eq? parts 'control)) ;; (session:process-file view-file)) ;; (list "<p>Page not found " page " </p>"))) ((dir) "ERROR: dir style not yet re-implemented") (else (list "ERROR: page-dir-style must be stored, dir or flat, got " dir-style))))) (define (session:call self page parts) (session:call-parts self page 'both)) ;; (define (session:load-model self model) ;; (let ((model.scm (string-append (sdat-get-sroot self) "/models/" model ".scm")) ;; (model.so (string-append (sdat-get-sroot self) "/models/" model ".so"))) ;; (if (file-exists? model.so) ;; (load model.so) ;; (if (file-exists? model.scm) ;; (load model.scm) ;; (s:log "ERROR: model " model.scm " not found"))))) ;; (define (session:model-path self model) ;; (string-append (sdat-get-sroot self) "/models/" model ".scm")) (define (session:pp-formdat self) (let ((dat (formdat:all->strings (sdat-get-formdat self)))) (string-intersperse dat "<br> "))) (define (session:param->string params) ;; (err:log "params=" params) |
︙ | ︙ | |||
749 750 751 752 753 754 755 756 757 758 759 760 761 762 | (if (or (string? key)(number? key)(symbol? key)) (if (and (vector? formdat)(eq? (vector-length formdat) 1)(hash-table? (vector-ref formdat 0))) (formdat:get formdat key) (begin (session:log self "ERROR: formdat: " formdat " is not of class <formdat>") #f)) (session:log self "ERROR: bad key " key))))) (define (session:run-actions self) (let* ((action (session:get-param self 'action)) (page (sdat-get-page self))) ;; (print "action=" action " page=" page) (if action (let ((action-lst (string-split action "."))) | > > > > > > > > > > | 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 | (if (or (string? key)(number? key)(symbol? key)) (if (and (vector? formdat)(eq? (vector-length formdat) 1)(hash-table? (vector-ref formdat 0))) (formdat:get formdat key) (begin (session:log self "ERROR: formdat: " formdat " is not of class <formdat>") #f)) (session:log self "ERROR: bad key " key))))) ;; This one will get the first value found regardless of form (define (session:get-input-keys self) (let* ((formdat (sdat-get-formdat self))) (if (not formdat) #f (if (and (vector? formdat)(eq? (vector-length formdat) 1)(hash-table? (vector-ref formdat 0))) (formdat:keys formdat) (begin (session:log self "ERROR: formdat: " formdat " is not of class <formdat>") #f))))) (define (session:run-actions self) (let* ((action (session:get-param self 'action)) (page (sdat-get-page self))) ;; (print "action=" action " page=" page) (if action (let ((action-lst (string-split action "."))) |
︙ | ︙ |
Modified setup.scm from [f3ad64511f] to [e52dd0f926].
︙ | ︙ | |||
8 9 10 11 12 13 14 | ;; PURPOSE. (declare (unit setup)) (declare (uses session)) (require-extension srfi-69) (require-extension regex) | < < < < < < < < | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | ;; PURPOSE. (declare (unit setup)) (declare (uses session)) (require-extension srfi-69) (require-extension regex) ;; use this for getting data from page to page when scope and evals ;; get in the way (define s:local-vars (make-hash-table)) (define (s:local-set! k v) (hash-table-set! s:local-vars k v)) (define (s:local-get k) (hash-table-ref/default s:local-vars k #f)) (define (s:log . msg) (apply session:log s:session msg)) (define (s:set-err . args) (sdat-set-curr-err! s:session args)) ;; Usage: (s:get-err s:big) (define (s:get-err wrapperfunc) (let ((errmsg (sdat-get-curr-err s:session))) (if errmsg ((if wrapperfunc |
︙ | ︙ | |||
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | (session:del! s:session "*sessionvars*" key)) ;; utility to get all vars as hash table (define (s:session-get-sessionvars) (sdat-get-sessionvars s:session)) ;; inputs (define (s:get-input key) (session:get-input s:session key)) (define (s:load-model model) (session:load-model s:session model)) (define (s:model-path model) (session:model-path s:session model)) (define (s:db) (sdat-get-conn s:session)) (define (s:never-called-page? page) (session:never-called-page? s:session page)) ;; find out if we are in debugmode (define (s:debug-mode?) (sdat-get-debugmode s:session)) | > > > > > > > > > > > > > > > > > > > > > > > | 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | (session:del! s:session "*sessionvars*" key)) ;; utility to get all vars as hash table (define (s:session-get-sessionvars) (sdat-get-sessionvars s:session)) ;; inputs ;; (define (s:get-input key) (session:get-input s:session key)) (define (s:get-input-keys) (session:get-input-keys s:session)) (define (s:load-model model) (session:load-model s:session model)) (define (s:model-path model) (session:model-path s:session model)) ;; share data between pages calls. NOTE: This is not persistent ;; between cgi calls. Use sessionvars for that. ;; (define (s:shared-hash) (sdat-get-shared-hash s:session)) (define (s:shared-set! key val) (hash-table-set! (sdat-get-shared-hash s:session) key val)) ;; What to return when no value for key? ;; (define (s:shared-get key) (hash-table-ref/default (sdat-get-shared-hash s:session) key #f)) ;; http://foo.bar.com/pagename/p1/p2 => '("p1" "p2") ;; (define (s:get-page-params) (sdat-get-page-params s:session)) (define (s:db) (sdat-get-conn s:session)) (define (s:never-called-page? page) (session:never-called-page? s:session page)) ;; find out if we are in debugmode (define (s:debug-mode?) (sdat-get-debugmode s:session)) |
Added stml.meta version [e8cabdbc79].
> > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | ( ; Your egg's license: (license "LGPL") ; Pick one from the list of categories (see below) for your egg and enter it ; here. (category misc) ; A list of eggs mpeg3 depends on. If none, you can omit this declaration ; altogether. If you are making an egg for chicken 3 and you need to use ; procedures from the `files' unit, be sure to include the `files' egg in the ; `needs' section (chicken versions < 3.4.0 don't provide the `files' unit). ; `depends' is an alias to `needs'. (needs srfi-69) ; A list of eggs required for TESTING ONLY. See the `Tests' section. (test-depends test) (author "Matt Welland") (synopsis "Primitive argument processor.")) |
Modified stml.scm from [20cb989f12] to [8f12de3e15].
︙ | ︙ | |||
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | (define (s:body . args) (s:common-tag "BODY" args)) (define (s:center . args) (s:common-tag "CENTER" args)) (define (s:code . args) (s:common-tag "CODE" args)) (define (s:div . args) (s:common-tag "DIV" args)) (define (s:h1 . args) (s:common-tag "H1" args)) (define (s:h2 . args) (s:common-tag "H2" args)) (define (s:h3 . args) (s:common-tag "H3" args)) (define (s:head . args) (s:common-tag "HEAD" args)) (define (s:html . args) (s:common-tag "HTML" args)) (define (s:i . args) (s:common-tag "I" args)) (define (s:img . args) (s:common-tag "IMG" args)) (define (s:input . args) (s:common-tag "INPUT" args)) (define (s:link . args) (s:common-tag "LINK" args)) (define (s:p . args) (s:common-tag "P" args)) (define (s:strong . args) (s:common-tag "STRONG" args)) (define (s:table . args) (s:common-tag "TABLE" args)) (define (s:td . args) (s:common-tag "TD" args)) (define (s:title . args) (s:common-tag "TITLE" args)) (define (s:tr . args) (s:common-tag "TR" args)) (define (s:small . args) (s:common-tag "SMALL" args)) (define (s:quote . args) (s:common-tag "QUOTE" args)) (define (s:hr . args) (s:common-tag "HR" args)) (define (s:li . args) (s:common-tag "LI" args)) (define (s:ul . args) (s:common-tag "UL" args)) (define (s:ol . args) (s:common-tag "OL" args)) (define (s:dl . args) (s:common-tag "DL" args)) (define (s:dt . args) (s:common-tag "DT" args)) (define (s:dd . args) (s:common-tag "DD" args)) (define (s:pre . args) (s:common-tag "PRE" args)) (define (s:span . args) (s:common-tag "SPAN" args)) (define (s:dblquote . args) (let* ((inputs (s:extract args)) (data (caar inputs)) (params (s:process-params (cadr inputs)))) (conc """ data """))) | > > > > > | 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | (define (s:body . args) (s:common-tag "BODY" args)) (define (s:center . args) (s:common-tag "CENTER" args)) (define (s:code . args) (s:common-tag "CODE" args)) (define (s:div . args) (s:common-tag "DIV" args)) (define (s:h1 . args) (s:common-tag "H1" args)) (define (s:h2 . args) (s:common-tag "H2" args)) (define (s:h3 . args) (s:common-tag "H3" args)) (define (s:h4 . args) (s:common-tag "H4" args)) (define (s:h5 . args) (s:common-tag "H5" args)) (define (s:head . args) (s:common-tag "HEAD" args)) (define (s:html . args) (s:common-tag "HTML" args)) (define (s:i . args) (s:common-tag "I" args)) (define (s:img . args) (s:common-tag "IMG" args)) (define (s:input . args) (s:common-tag "INPUT" args)) (define (s:link . args) (s:common-tag "LINK" args)) (define (s:p . args) (s:common-tag "P" args)) (define (s:strong . args) (s:common-tag "STRONG" args)) (define (s:table . args) (s:common-tag "TABLE" args)) (define (s:tbody . args) (s:common-tag "TBODY" args)) (define (s:thead . args) (s:common-tag "THEAD" args)) (define (s:td . args) (s:common-tag "TD" args)) (define (s:title . args) (s:common-tag "TITLE" args)) (define (s:tr . args) (s:common-tag "TR" args)) (define (s:small . args) (s:common-tag "SMALL" args)) (define (s:quote . args) (s:common-tag "QUOTE" args)) (define (s:hr . args) (s:common-tag "HR" args)) (define (s:li . args) (s:common-tag "LI" args)) (define (s:ul . args) (s:common-tag "UL" args)) (define (s:ol . args) (s:common-tag "OL" args)) (define (s:dl . args) (s:common-tag "DL" args)) (define (s:dt . args) (s:common-tag "DT" args)) (define (s:dd . args) (s:common-tag "DD" args)) (define (s:pre . args) (s:common-tag "PRE" args)) (define (s:span . args) (s:common-tag "SPAN" args)) (define (s:label . args) (s:common-tag "LABEL" args)) (define (s:dblquote . args) (let* ((inputs (s:extract args)) (data (caar inputs)) (params (s:process-params (cadr inputs)))) (conc """ data """))) |
︙ | ︙ |
Added stml.setup version [b663e1c0bf].
> > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | ;; Copyright 2007-2010, Matthew Welland. ;; ;; This program is made available under the GNU GPL version 2.0 or ;; greater. See the accompanying file COPYING for details. ;; ;; This program is distributed WITHOUT ANY WARRANTY; without even the ;; implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ;; PURPOSE. ;;;; margs.setup ;; compile the code into a dynamically loadable shared object ;; (will generate margs.so) ;; (compile -s margs.scm) ;; Install as extension library (install-extension 'stml "stml.so") |
Added stmlcommon.scm version [722378235d].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | ;; Copyright 2007-2011, Matthew Welland. ;; ;; This program is made available under the GNU GPL version 2.0 or ;; greater. See the accompanying file COPYING for details. ;; ;; This program is distributed WITHOUT ANY WARRANTY; without even the ;; implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ;; PURPOSE. ;; (require-extension syntax-case) ;; (declare (run-time-macros)) (include "requirements.scm") (declare (uses cookie)) (declare (uses html-filter)) (declare (uses misc-stml)) (declare (uses formdat)) (declare (uses stml)) (declare (uses session)) (declare (uses setup)) ;; s:session gets created here (declare (uses sqltbl)) (declare (uses keystore)) (define (stml:cgi-session session) (session:initialize session) (session:setup session) (session:get-vars session) (sdat-set-log-port! session ;; (current-error-port)) (open-output-file (sdat-get-logfile session) #:append)) (s:validate-inputs) (session:run-actions session) (sdat-set-pagedat! session (append (sdat-get-pagedat session) (s:call (sdat-get-toppage session)))) (if (eq? (sdat-get-page-type session) 'html) ;; default is html. (session:cgi-out session) (session:alt-out session)) (session:save-vars session) (session:close session)) (define (stml:main proc) (handle-exceptions exn (begin (print "Content-type: text/html") (print "") (print "<html> <head> <title>EXCEPTION</title> </head> <body>") (print " QUERY_STRING is: <b> " (get-environment-variable "QUERY_STRING") " </b> <br>") (print "<pre>") ;; (print " EXCEPTION: " ((condition-property-accessor 'exn 'message) exn)) (print-error-message exn) (print-call-chain) (print "</pre>") (print "<table>") (for-each (lambda (var) (print "<tr><td>" (car var) "</td><td>" (cdr var) "</td></tr>")) (get-environment-variables)) (print "</table>") (print "</body></html>")) (if proc (proc s:session) (stml:cgi-session s:session)) ;; (raise-error) ;; (exit) )) |
Added stmlmodule.scm version [296e0e34a7].
> > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | ;; Copyright 2007-2011, Matthew Welland. ;; ;; This program is made available under the GNU GPL version 2.0 or ;; greater. See the accompanying file COPYING for details. ;; ;; This program is distributed WITHOUT ANY WARRANTY; without even the ;; implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ;; PURPOSE. ;; (require-extension syntax-case) ;; (declare (run-time-macros)) (include "stmlcommon.scm") |
Modified stmlrun.scm from [ced526ca73] to [ab2a64d7c8].
︙ | ︙ | |||
8 9 10 11 12 13 14 | ;; This program is distributed WITHOUT ANY WARRANTY; without even the ;; implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ;; PURPOSE. ;; (require-extension syntax-case) ;; (declare (run-time-macros)) | < < < < < < < < < < < < < < < < < < | < < < < | < < < < | < < < < < < < < < < < < | < < | 8 9 10 11 12 13 14 15 16 17 18 | ;; This program is distributed WITHOUT ANY WARRANTY; without even the ;; implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ;; PURPOSE. ;; (require-extension syntax-case) ;; (declare (run-time-macros)) ;; (include "stmlcommon.scm") (require-library stml) (stml:main #f) |
Modified sugar.scm from [08f3dbeadf] to [8c9838f5ec].
︙ | ︙ | |||
20 21 22 23 24 25 26 27 | ;; [(_ s x y) (if (s:get s) x y)])) ;; ;; ;; (define-syntax s:if-test ;; (syntax-rules () ;; [(_ s x) (if (string=? "yep" s) x (list "s:if not"))] ;; [(_ s x y) (if (string=? "yep" s) x y)])) | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | | | | | | | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | ;; [(_ s x y) (if (s:get s) x y)])) ;; ;; ;; (define-syntax s:if-test ;; (syntax-rules () ;; [(_ s x) (if (string=? "yep" s) x (list "s:if not"))] ;; [(_ s x y) (if (string=? "yep" s) x y)])) ;; Some of these routines use: ;; ;; http://www.cs.toronto.edu/~gfb/scheme/simple-macros.html ;; ;; Syntax for defining macros in a simple style similar to function definiton, ;; when there is a single pattern for the argument list and there are no keywords. ;; ;; (define-simple-syntax (name arg ...) body ...) ;; (define-syntax define-simple-syntax (syntax-rules () ((_ (name arg ...) body ...) (define-syntax name (syntax-rules () ((name arg ...) (begin body ...))))))) ;;====================================================================== ;; syntatic sugar items ;;====================================================================== ;; We often seem to want to include stuff if a conditional is met ;; otherwise not include it. This routine makes that slightly cleaner ;; since using a pure if results in #<undefined> objects. (admittedly they ;; should be ignored but this is slightly cleaner I think). ;; ;; NOTE: This has to be a macro or the true clause will be evaluated ;; whether "a" is true or false ;; If a is true return b, else return '() (define-simple-syntax (s:if a b) (if a b '())) ;; Using the Simple-Syntax System ;; ;; The syntax for defining macros in this system is similar to that for defining functions. In fact if the macro has a fixed number of arguments the syntax is identical. For example: ;; ;; ; Define a simple macro to add a value to a variable. ;; ; ;; (define-simple-syntax (+= variable value) ;; (set! variable (+ variable value))) ;; ;; ; Use it. ;; ; ;; (define v 2) ;; (+= v 7) ;; v ; => 9 ;; ;; For a fixed number of arguments followed by an unknown number of arguments we use ... after a single argument to represent the unknown number (possibly zero) of arguments. For example, let's revise our definition of += to allow zero or more values to be added: ;; ;; ; Define a simple macro to add a zero or more values to a variable ;; ; ;; (define-simple-syntax (+= variable value ...) ;; (set! variable (+ variable value ...))) ;; ;; ; Use it ;; ; ;; (define v 2) ;; (+= v 7) ;; v ; => 9 ;; (+= v 3 4) ;; v ; => 16 ;; (+= v) ;; v ; => 16 ;; ;; (define-macro (s:if-param varname . dat) ;; (match dat ;; (() '()) ;; ((a) `(if (s:get ,varname) ,a '())) ;; ((a b) `(if (s:get ,varname) ,a ,b)))) ;; ;; (define-macro (s:if-sessionvar varname . dat) ;; (match dat ;; (() '()) ;; ((a) `(if (s:session-var-get ,varname) ,a '())) ;; ((a b) `(if (s:session-var-get ,varname) ,a ,b)))) ;; |