Compare commits
26 commits
9b165490e5
...
85af3fcff3
Author | SHA1 | Date | |
---|---|---|---|
85af3fcff3 | |||
8b6e1955ef | |||
2a7fb0d735 | |||
e1bb1885b2 | |||
0a762ccb1d | |||
6915cc0e21 | |||
6947dd37b3 | |||
d24b7c4136 | |||
fabb387ba1 | |||
708268d91d | |||
a9f5fc74e4 | |||
c458dc3900 | |||
dcf6d8937f | |||
15888b7e3e | |||
dc3044026c | |||
ed55660c80 | |||
d0771e130a | |||
6282a934c6 | |||
707bb1d61e | |||
ba2c753109 | |||
2674f08674 | |||
3629844743 | |||
65c7155ba3 | |||
939af54e87 | |||
a64ab232c6 | |||
2baffe570b |
14 changed files with 237 additions and 104 deletions
35
CHANGELOG.md
35
CHANGELOG.md
|
@ -1,14 +1,41 @@
|
|||
ChangeLog
|
||||
=========
|
||||
|
||||
1.15
|
||||
----
|
||||
1.16.2 - released 2024-05-07
|
||||
----------------------------
|
||||
|
||||
* fix rada-ml-pred? in -mlsync
|
||||
|
||||
1.16.1 - released 2024-04-02
|
||||
----------------------------
|
||||
|
||||
* add EUR account for paying membership fees to member's page
|
||||
|
||||
1.16 - released 2024-02-09
|
||||
--------------------------
|
||||
|
||||
* handle # character at weird positions in DokuWiki users.auth.php
|
||||
* unify -mlsync and -mlcheck handling of member predicates
|
||||
* handle unicode characters with 3-byte UTF-8 representation correctly
|
||||
* calculate expected income with respect to discounts granted
|
||||
* report soon-expiring members in the summary emails
|
||||
* report mailing lists check status in summary emails
|
||||
|
||||
1.15.1 - released 2024-01-02
|
||||
----------------------------
|
||||
|
||||
* fix calculating historical membership fee (was erroneously based on
|
||||
current date)
|
||||
* fix showing basic information without MLs loaded
|
||||
|
||||
1.15 - released 2024-12-24
|
||||
--------------------------
|
||||
|
||||
* increase membership fees starting 2024-01 (specification.rkt)
|
||||
* add support for explicit fee amounts for specified period
|
||||
|
||||
1.14
|
||||
----
|
||||
1.14 - released 2024-12-06
|
||||
--------------------------
|
||||
|
||||
* add support for dynamic terminal size
|
||||
* use table cell formatting instead of paragraph formatting everywhere
|
||||
|
|
17
src/Makefile
17
src/Makefile
|
@ -42,7 +42,7 @@ HACKERBASE-DEPS=hackerbase.scm cal-month.import.scm \
|
|||
tests.import.scm notifications.import.scm logging.import.scm \
|
||||
progress.import.scm cal-period.import.scm \
|
||||
util-stdout.import.scm export-web-static.import.scm \
|
||||
dokuwiki.import.scm
|
||||
dokuwiki.import.scm mailinglist.import.scm
|
||||
|
||||
HACKERBASE-OBJS=hackerbase.o testing.o listing.o cal-month.o \
|
||||
cal-period.o ansi.o util-bst-ldict.o command-line.o mbase.o \
|
||||
|
@ -59,7 +59,8 @@ HACKERBASE-OBJS=hackerbase.o testing.o listing.o cal-month.o \
|
|||
template-list-expander.o box-drawing.o export-web-static.o \
|
||||
util-dir.o dokuwiki.o racket-kwargs.o duck.o util-bst.o \
|
||||
util-bst-bdict.o util-bst-ldict.o util-bst-lset.o mailman2.o \
|
||||
mailman-common.o mailman3.o mailman3-sql.o tiocgwinsz.o
|
||||
mailman-common.o mailman3.o mailman3-sql.o tiocgwinsz.o \
|
||||
mailinglist.o
|
||||
|
||||
GENDOC-SOURCES=gendoc.scm duck-extract.import.scm \
|
||||
util-time.import.scm util-csv.import.scm util-git.import.scm \
|
||||
|
@ -291,7 +292,7 @@ util-io.o: util-io.import.scm
|
|||
util-io.import.scm: $(UTIL-IO-SOURCES)
|
||||
|
||||
UTIL-PARSER-SOURCES=util-parser.scm testing.import.scm \
|
||||
duck.import.scm
|
||||
duck.import.scm racket-kwargs.import.scm
|
||||
|
||||
util-parser.o: util-parser.import.scm
|
||||
util-parser.import.scm: $(UTIL-PARSER-SOURCES)
|
||||
|
@ -332,7 +333,8 @@ NOTIFICATIONS-SOURCES=notifications.scm brmember.import.scm \
|
|||
brmember-format.import.scm configuration.import.scm \
|
||||
util-time.import.scm members-fees.import.scm mbase.import.scm \
|
||||
members-print.import.scm table.import.scm \
|
||||
bank-account.import.scm logging.import.scm
|
||||
bank-account.import.scm logging.import.scm \
|
||||
mailinglist.import.scm
|
||||
|
||||
notifications.o: notifications.import.scm
|
||||
notifications.import.scm: $(NOTIFICATIONS-SOURCES)
|
||||
|
@ -550,3 +552,10 @@ TIOCGWINSZ-SOURCES=tiocgwinsz.scm duck.import.scm
|
|||
|
||||
tiocgwinsz.o: tiocgwinsz.import.scm
|
||||
tiocgwinsz.import.scm: $(TIOCGWINSZ-SOURCES)
|
||||
|
||||
MAILINGLIST-SOURCES=mailinglist.scm racket-kwargs.import.scm \
|
||||
mailman.import.scm mbase.import.scm util-string.import.scm \
|
||||
brmember.import.scm
|
||||
|
||||
mailinglist.o: mailinglist.import.scm
|
||||
mailinglist.import.scm: $(MAILINGLIST-SOURCES)
|
||||
|
|
|
@ -499,8 +499,8 @@
|
|||
(ldict-equal?
|
||||
(make-brmember '|1234| "members/1234" '(|member|))
|
||||
(make-ldict
|
||||
`((file-name . |1234|)
|
||||
(TAG . ,TAG-BRMEMBER)
|
||||
`((TAG . ,TAG-BRMEMBER)
|
||||
(file-name . |1234|)
|
||||
(file-path . "members/1234")
|
||||
(symlinks |member|)
|
||||
(id . 1234)))))
|
||||
|
|
|
@ -54,7 +54,7 @@
|
|||
(users '()))
|
||||
(if (null? lines)
|
||||
users
|
||||
(let ((line (parser-preprocess-line (car lines))))
|
||||
(let ((line (parser-preprocess-line (car lines) #:strip-comments? #f)))
|
||||
(if (equal? line "")
|
||||
(loop (cdr lines)
|
||||
users)
|
||||
|
@ -74,8 +74,8 @@
|
|||
(handle-exceptions
|
||||
exn
|
||||
(let ()
|
||||
(log-warning "DokuWiki: cannot open ~A" fname)
|
||||
(stdout-printf "DokuWiki: cannot open ~A" fname)
|
||||
(log-warning "DokuWiki (~A) exception ~A" fname (condition->list exn))
|
||||
(stdout-printf "DokuWiki (~A) exception ~A" fname (condition->list exn))
|
||||
'())
|
||||
(with-input-from-file fname
|
||||
parse-dokuwiki-users-auth)))
|
||||
|
|
|
@ -101,7 +101,7 @@
|
|||
(print "<dt>Member ID, Variable Symbol for Payments<br>(Členské číslo, variabilní symbol plateb)</dt><dd>"
|
||||
(brmember-id mr) "</dd>")
|
||||
(print "<dt>Balance in CZK<br>(Zůstatek v Kč)</dt><dd>" (caar (reverse bhs)) "</dd>")
|
||||
(print "<dt>Account for Payments<br>(Účet pro platbu příspěvků)</dt><dd>2500079551/2010</dd>")
|
||||
(print "<dt>Account for Payments<br>(Účet pro platbu příspěvků)</dt><dd>CZK: 2500079551/2010<br>EUR: CZ93 2010 0000 0021 0007 9552</dd>")
|
||||
(print "</dl>")
|
||||
(print "</div>")
|
||||
(print "<div class=\"bi\">")
|
||||
|
|
|
@ -50,7 +50,8 @@
|
|||
export-web-static
|
||||
dokuwiki
|
||||
racket-kwargs
|
||||
util-string)
|
||||
util-string
|
||||
mailinglist)
|
||||
|
||||
;; Command-line options and configurable parameters
|
||||
(define -needs-bank- (make-parameter #f))
|
||||
|
@ -286,32 +287,6 @@
|
|||
(print " " (car keys) ": " (length (ldict-ref status (car keys)))))
|
||||
(loop (cdr keys)))))))
|
||||
|
||||
(define* (check-mailing-list mls name #:pred? (pred? #f))
|
||||
(define ml (find-mailman-list mls name))
|
||||
(when ml
|
||||
(let-values (((missing surplus)
|
||||
(mailman-compare-members ml
|
||||
(mbase-active-emails MB
|
||||
#:suspended #t
|
||||
#:pred? pred?
|
||||
))))
|
||||
(if (null? (cdr ml))
|
||||
(print "Skipping ML check - not loaded")
|
||||
(if (and (null? missing)
|
||||
(null? surplus))
|
||||
(print (format "~a mailing list membership in sync." (string-capitalize name)))
|
||||
(let ()
|
||||
(print (format "~a mailing list:" (string-capitalize name)))
|
||||
(when (not (null? missing))
|
||||
(print " Missing: " missing))
|
||||
(when (not (null? surplus))
|
||||
(print " Outsiders: " surplus))))))))
|
||||
|
||||
(define (rada-ml-pred? mr)
|
||||
(or (brmember-council? mr)
|
||||
(brmember-chair? mr)
|
||||
(brmember-revision? mr)))
|
||||
|
||||
;; Perform requested action
|
||||
(case (-action-)
|
||||
((print-info)
|
||||
|
@ -323,10 +298,7 @@
|
|||
(let ()
|
||||
(print-members-base-table MB)
|
||||
(newline)
|
||||
(check-mailing-list MLS "internal")
|
||||
(check-mailing-list MLS "rada"
|
||||
#:pred? rada-ml-pred?)
|
||||
(check-mailing-list MLS "rk" #:pred? brmember-revision?)
|
||||
(print-mailing-list-checks MB MLS)
|
||||
(print-git-status)))
|
||||
(newline))
|
||||
((print-stats)
|
||||
|
@ -424,8 +396,8 @@
|
|||
(print-git-status))
|
||||
((summary)
|
||||
(if (-send-emails-)
|
||||
(make+send-summary-email MB)
|
||||
(make+print-summary-email MB)))
|
||||
(make+send-summary-email MB MLS)
|
||||
(make+print-summary-email MB MLS)))
|
||||
((list)
|
||||
(for-each (lambda (mr)
|
||||
(print (brmember-nick mr)))
|
||||
|
|
78
src/mailinglist.scm
Normal file
78
src/mailinglist.scm
Normal file
|
@ -0,0 +1,78 @@
|
|||
;;
|
||||
;; mailinglist.scm
|
||||
;;
|
||||
;; Common high-level mailinglist management procedures.
|
||||
;;
|
||||
;; ISC License
|
||||
;;
|
||||
;; Copyright 2023 Brmlab, z.s.
|
||||
;; Dominik Pantůček <dominik.pantucek@trustica.cz>
|
||||
;;
|
||||
;; Permission to use, copy, modify, and/or distribute this software
|
||||
;; for any purpose with or without fee is hereby granted, provided
|
||||
;; that the above copyright notice and this permission notice appear
|
||||
;; in all copies.
|
||||
;;
|
||||
;; THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
;; WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
;; WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||
;; AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
|
||||
;; CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
;; OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
;; NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
;; CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
;;
|
||||
|
||||
(declare (unit mailinglist))
|
||||
|
||||
(module
|
||||
mailinglist
|
||||
(
|
||||
check-mailing-list
|
||||
print-mailing-list-checks
|
||||
|
||||
rada-ml-pred?
|
||||
)
|
||||
|
||||
(import scheme
|
||||
(chicken base)
|
||||
(chicken format)
|
||||
racket-kwargs
|
||||
mailman
|
||||
mbase
|
||||
util-string
|
||||
brmember)
|
||||
|
||||
(define* (check-mailing-list MB mls name #:pred? (pred? #f) #:suspended (suspended #f))
|
||||
(define ml (find-mailman-list mls name))
|
||||
(when ml
|
||||
(let-values (((missing surplus)
|
||||
(mailman-compare-members ml
|
||||
(mbase-active-emails MB
|
||||
#:suspended suspended
|
||||
#:pred? pred?
|
||||
))))
|
||||
(if (null? (cdr ml))
|
||||
(print "Skipping ML check - not loaded")
|
||||
(if (and (null? missing)
|
||||
(null? surplus))
|
||||
(print (format "~a mailing list membership in sync." (string-capitalize name)))
|
||||
(let ()
|
||||
(print (format "~a mailing list:" (string-capitalize name)))
|
||||
(when (not (null? missing))
|
||||
(print " Missing: " missing))
|
||||
(when (not (null? surplus))
|
||||
(print " Outsiders: " surplus))))))))
|
||||
|
||||
(define (print-mailing-list-checks MB MLS)
|
||||
(check-mailing-list MB MLS "internal" #:suspended #t)
|
||||
(check-mailing-list MB MLS "rada"
|
||||
#:pred? rada-ml-pred?)
|
||||
(check-mailing-list MB MLS "rk" #:pred? brmember-revision?))
|
||||
|
||||
(define (rada-ml-pred? mr)
|
||||
(or (brmember-council? mr)
|
||||
(brmember-chair? mr)
|
||||
(brmember-revision? mr)))
|
||||
|
||||
)
|
|
@ -30,6 +30,7 @@
|
|||
(
|
||||
lookup-member-fee
|
||||
member-calendar
|
||||
make-member-calendar-entry
|
||||
member-calendar-first-month
|
||||
member-calendar-last-month
|
||||
member-calendar-query
|
||||
|
@ -40,12 +41,14 @@
|
|||
member-calendar->table
|
||||
members-summary
|
||||
member-calendar-entry->fee
|
||||
get-expected-income-string
|
||||
)
|
||||
|
||||
(import scheme
|
||||
(chicken base)
|
||||
(chicken format)
|
||||
(chicken sort)
|
||||
(chicken string)
|
||||
srfi-1
|
||||
configuration
|
||||
brmember
|
||||
|
@ -82,15 +85,17 @@
|
|||
(if (cal-month>? cm last-month)
|
||||
(reverse cal)
|
||||
(loop (cal-month-add cm)
|
||||
(cons (list cm
|
||||
(with-current-month
|
||||
cm
|
||||
(brmember-flags mr))
|
||||
(with-current-month
|
||||
cm
|
||||
(brmember-spec-fee mr)))
|
||||
(cons (with-current-month
|
||||
cm
|
||||
(make-member-calendar-entry mr))
|
||||
cal))))))
|
||||
|
||||
;; Assumes current-month is specified correctly
|
||||
(define (make-member-calendar-entry mr)
|
||||
(list (*current-month*)
|
||||
(brmember-flags mr)
|
||||
(brmember-spec-fee mr)))
|
||||
|
||||
;; Returns the first month of the calendar
|
||||
(define (member-calendar-first-month mc)
|
||||
(caar mc))
|
||||
|
@ -203,4 +208,25 @@
|
|||
(cons 0 0)
|
||||
members)))
|
||||
|
||||
(define (get-expected-income-string mb)
|
||||
(let* ((flst
|
||||
(map (compose member-calendar-entry->fee make-member-calendar-entry)
|
||||
(find-members-by-predicate mb brmember-active?)))
|
||||
(amts (sort (delete-duplicates flst) <))
|
||||
(sums
|
||||
(map
|
||||
(lambda (amt)
|
||||
(cons amt
|
||||
(length (filter (lambda (v) (= v amt)) flst))))
|
||||
amts)))
|
||||
(string-append
|
||||
"Expected income: "
|
||||
(string-intersperse (map
|
||||
(lambda (p)
|
||||
(format "~A*~A" (cdr p) (car p)))
|
||||
sums)
|
||||
" + ")
|
||||
" = "
|
||||
(number->string (foldl + 0 (map (lambda (p) (* (car p) (cdr p))) sums))))))
|
||||
|
||||
)
|
||||
|
|
|
@ -500,7 +500,17 @@
|
|||
(null? (cdr dsa)))
|
||||
#f
|
||||
(cadr dsa))))
|
||||
(let* ((members ;; Pass 1
|
||||
(let* ((raw-members
|
||||
(sort
|
||||
(if destroyed?
|
||||
(find-members-by-predicate MB (lambda x #t))
|
||||
(if only-active?
|
||||
(find-members-by-predicate MB (lambda (mr)
|
||||
(brmember-active? mr)))
|
||||
(find-members-by-predicate MB (lambda (mr)
|
||||
(not (brmember-destroyed? mr))))))
|
||||
brmember<?))
|
||||
(members ;; Pass 1
|
||||
(map
|
||||
(lambda (mr)
|
||||
(let* ((balance (member-balance mr))
|
||||
|
@ -522,15 +532,7 @@
|
|||
total
|
||||
balance
|
||||
)))
|
||||
(sort
|
||||
(if destroyed?
|
||||
(find-members-by-predicate MB (lambda x #t))
|
||||
(if only-active?
|
||||
(find-members-by-predicate MB (lambda (mr)
|
||||
(brmember-active? mr)))
|
||||
(find-members-by-predicate MB (lambda (mr)
|
||||
(not (brmember-destroyed? mr))))))
|
||||
brmember<?)))
|
||||
raw-members))
|
||||
(balances (map (lambda (m)
|
||||
(list-ref m 6))
|
||||
members)))
|
||||
|
@ -598,19 +600,7 @@
|
|||
(map (lambda (member)
|
||||
(min 0 (list-ref member 5)))
|
||||
members)))
|
||||
(let* ((ns (foldl (lambda (acc member)
|
||||
(cons (+ (car acc) (if (eq? 'student (cadr member)) 1 0))
|
||||
(+ (cdr acc) (if (eq? 'active (cadr member)) 1 0))))
|
||||
(cons 0 0)
|
||||
members))
|
||||
(students (car ns))
|
||||
(full (cdr ns)))
|
||||
(print "Expected income: "
|
||||
(+ (* (lookup-member-fee 'normal) full)
|
||||
(* (lookup-member-fee 'student) students))
|
||||
" (" full " full members + " students " students)"))
|
||||
)
|
||||
))
|
||||
(print (get-expected-income-string MB)))))
|
||||
|
||||
(define (unpaired-table mb . args)
|
||||
(apply
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
(chicken format)
|
||||
(chicken string)
|
||||
(chicken sort)
|
||||
(chicken port)
|
||||
brmember
|
||||
util-mail
|
||||
util-bst-ldict
|
||||
|
@ -54,7 +55,8 @@
|
|||
table
|
||||
bank-account
|
||||
logging
|
||||
srfi-1)
|
||||
srfi-1
|
||||
mailinglist)
|
||||
|
||||
;; Prints email to the console
|
||||
(define (print-notification-email em)
|
||||
|
@ -142,16 +144,14 @@
|
|||
(send-notification-email em)))
|
||||
|
||||
;; Summary email of membership fees payments
|
||||
(define (summary-email-body mb)
|
||||
(define (summary-email-body mb mls)
|
||||
(let* ((mbs (members-summary mb))
|
||||
(students (car mbs))
|
||||
(full (cdr mbs))
|
||||
(income (+ (* (lookup-member-fee 'normal) full)
|
||||
(* (lookup-member-fee 'student) students)))
|
||||
(income-lst
|
||||
(list (format "Expected income: ~A CZK" income)
|
||||
(format " ~A full members" full)
|
||||
(format " ~A students" students)))
|
||||
(list (get-expected-income-string mb)))
|
||||
(unpaired (mbase-unpaired mb))
|
||||
(unpaired-lst
|
||||
(if (null? unpaired)
|
||||
|
@ -160,6 +160,30 @@
|
|||
(list ""
|
||||
"Unpaired transactions:")
|
||||
(unpaired-table mb #:border-style 'ascii))))
|
||||
(soonexps (sort
|
||||
(find-members-by-predicate
|
||||
mb
|
||||
(brmember-suspended-for 21 24))
|
||||
brmember<?))
|
||||
(soonexps-lst
|
||||
(if (null? soonexps)
|
||||
#f
|
||||
(list ""
|
||||
(format "Expiring members (~A): ~A"
|
||||
(length soonexps)
|
||||
(string-intersperse
|
||||
(map
|
||||
(lambda (mr)
|
||||
(brmember-format "~N (~S)" mr))
|
||||
soonexps)
|
||||
",")))))
|
||||
(mlcheck-lst
|
||||
(cons ""
|
||||
(string-split
|
||||
(with-output-to-string
|
||||
(lambda ()
|
||||
(print-mailing-list-checks mb mls)))
|
||||
"\n")))
|
||||
(debtors (sort
|
||||
(members-to-notify mb 1)
|
||||
brmember<?))
|
||||
|
@ -256,6 +280,8 @@
|
|||
", "))))))
|
||||
(append income-lst
|
||||
unpaired-lst
|
||||
soonexps-lst
|
||||
mlcheck-lst
|
||||
debtors-lst
|
||||
boring-lst
|
||||
dw-lst
|
||||
|
@ -266,21 +292,21 @@
|
|||
))))
|
||||
|
||||
;; Creates the summary email structure
|
||||
(define (make-summary-email mb)
|
||||
(define (make-summary-email mb mls)
|
||||
(make-ldict
|
||||
`((to . ,(*summary-mailto*))
|
||||
(subject . ,(format "Členské příspěvky ~A"
|
||||
(today/iso)))
|
||||
(body . ,(summary-email-body mb)))))
|
||||
(body . ,(summary-email-body mb mls)))))
|
||||
|
||||
;; Just print to standard output
|
||||
(define (make+print-summary-email mb)
|
||||
(let ((em (make-summary-email mb)))
|
||||
(define (make+print-summary-email mb mls)
|
||||
(let ((em (make-summary-email mb mls)))
|
||||
(print-notification-email em)))
|
||||
|
||||
;; Actually send emails
|
||||
(define (make+send-summary-email mr)
|
||||
(let ((em (make-summary-email mr)))
|
||||
(define (make+send-summary-email mr mls)
|
||||
(let ((em (make-summary-email mr mls)))
|
||||
(send-notification-email em)))
|
||||
|
||||
)
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
(chicken format))
|
||||
|
||||
;; Short banner
|
||||
(define banner-line "HackerBase 1.15.1 (c) 2023 Brmlab, z.s.")
|
||||
(define banner-line "HackerBase 1.16.2 (c) 2023-2024 Brmlab, z.s.")
|
||||
|
||||
;; Banner source with numbers for ANSI CSI SGR
|
||||
(define banner-source "
|
||||
|
|
|
@ -286,10 +286,12 @@
|
|||
(call/cc
|
||||
(lambda (cc)
|
||||
(set! break cc)
|
||||
(if resume
|
||||
(resume '())
|
||||
(bst-iter-kv bst yield))
|
||||
#f)))))
|
||||
(cond (resume
|
||||
(resume '())
|
||||
(break #f))
|
||||
(else
|
||||
(bst-iter-kv bst yield)
|
||||
(break #f))))))))
|
||||
|
||||
(define/doc (bst-keys bst)
|
||||
("Returns all the keys contained in given dictionary.")
|
||||
|
|
|
@ -39,11 +39,12 @@ member file parsers. All functions are UTF-8 aware.")
|
|||
|
||||
(import scheme
|
||||
(chicken base)
|
||||
racket-kwargs
|
||||
testing)
|
||||
|
||||
;; Pass 0: Removes any comments and removes any leading and trailing
|
||||
;; whitespace.
|
||||
(define/doc (parser-preprocess-line line)
|
||||
(define*/doc (parser-preprocess-line line #:strip-comments? (strip-comments? #t))
|
||||
("* ```line``` - a string with contents of one source line
|
||||
|
||||
If the input ```line``` contains the ```#``` character, the rest of
|
||||
|
@ -62,7 +63,9 @@ Returns a string representing the preprocessed line.")
|
|||
(ploop (add1 pidx)))))
|
||||
(hpos (let hloop ((hidx ppos))
|
||||
(if (or (= hidx llen)
|
||||
(eq? (string-ref line hidx) #\#))
|
||||
(and (or strip-comments?
|
||||
(= hidx 0))
|
||||
(eq? (string-ref line hidx) #\#)))
|
||||
hidx
|
||||
(hloop (add1 hidx)))))
|
||||
(spos (let sloop ((sidx (sub1 hpos)))
|
||||
|
|
|
@ -120,13 +120,13 @@ of the string and a list of remaining bytes (as integers).")
|
|||
(define/doc (utf8-bytes->lists chars)
|
||||
("The same as above but accepts a list of bytes (as integers).")
|
||||
(let loop ((bytes chars)
|
||||
(rpending '())
|
||||
(rpending chars)
|
||||
(pending 0)
|
||||
(expected #f)
|
||||
(res '()))
|
||||
(if (null? bytes)
|
||||
(values (reverse res)
|
||||
(reverse rpending))
|
||||
rpending)
|
||||
(let ((byte (car bytes)))
|
||||
(cond (expected
|
||||
;; Decode UTF-8 sequence
|
||||
|
@ -135,14 +135,14 @@ of the string and a list of remaining bytes (as integers).")
|
|||
(let ((char (integer->char (bitwise-ior pending
|
||||
(bitwise-and byte #b111111)))))
|
||||
(loop (cdr bytes)
|
||||
'()
|
||||
(cdr bytes)
|
||||
0
|
||||
#f
|
||||
(cons char res))))
|
||||
(else
|
||||
;; Intermediate bytes
|
||||
(loop (cdr bytes)
|
||||
(cons byte rpending)
|
||||
rpending
|
||||
(arithmetic-shift (bitwise-ior pending
|
||||
(bitwise-and byte #b111111)) 6)
|
||||
(sub1 expected)
|
||||
|
@ -152,7 +152,7 @@ of the string and a list of remaining bytes (as integers).")
|
|||
(cond ((= (bitwise-and byte #b10000000) 0)
|
||||
;; ASCII
|
||||
(loop (cdr bytes)
|
||||
'()
|
||||
(cdr bytes)
|
||||
0
|
||||
#f
|
||||
(cons (integer->char byte) res)))
|
||||
|
@ -160,20 +160,20 @@ of the string and a list of remaining bytes (as integers).")
|
|||
;; First byte of UTF-8 sequence
|
||||
(let-values
|
||||
(((first-byte char-bytes)
|
||||
(cond ((= (bitwise-and byte #b11000000) #b11000000)
|
||||
(cond ((= (bitwise-and byte #b11100000) #b11000000)
|
||||
(values (bitwise-and byte #b11111)
|
||||
2))
|
||||
((= (bitwise-and byte #b11100000) #b11100000)
|
||||
((= (bitwise-and byte #b11110000) #b11100000)
|
||||
(values (bitwise-and byte #b1111)
|
||||
3))
|
||||
((= (bitwise-and byte #b11110000) #b11110000)
|
||||
((= (bitwise-and byte #b11111000) #b11110000)
|
||||
(values (bitwise-and byte #b111)
|
||||
4))
|
||||
(else
|
||||
;; Should not happen
|
||||
(values 0 0)))))
|
||||
(loop (cdr bytes)
|
||||
(list byte)
|
||||
bytes
|
||||
(arithmetic-shift first-byte 6)
|
||||
(sub1 char-bytes)
|
||||
res))))))))))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue