Compare commits

...

26 commits

Author SHA1 Message Date
85af3fcff3 Release 1.16.2 with -mlsync fix. 2024-05-07 20:27:07 +02:00
8b6e1955ef Export rada-ml-pred? for backwards compatibility. 2024-05-07 20:24:00 +02:00
2a7fb0d735 Release 1.16.1 2024-04-02 19:45:57 +02:00
e1bb1885b2 Add EUR account. 2024-04-02 19:43:27 +02:00
0a762ccb1d Improve changelog for 1.16. 2024-02-09 15:18:24 +01:00
6915cc0e21 Fix spacing and bump version. 2024-02-09 15:14:46 +01:00
6947dd37b3 Report ML check status in summary emails. 2024-02-09 15:13:09 +01:00
d24b7c4136 Move more to the new mailinglist module. 2024-02-09 15:05:49 +01:00
fabb387ba1 Split out mailinglist check base. 2024-02-09 15:01:21 +01:00
708268d91d Update the changelog. 2024-02-09 14:53:34 +01:00
a9f5fc74e4 Add members expiring soon to the summary email. 2024-02-09 14:51:26 +01:00
c458dc3900 Use the same algorithm for expected income in summary emails. 2024-02-09 14:44:24 +01:00
dcf6d8937f Update changelog. 2024-02-09 14:30:06 +01:00
15888b7e3e Fix computing expected income based on actual fees and discounts. 2024-02-09 14:28:17 +01:00
dc3044026c Fix utf-8 3-byte handling. 2024-02-08 21:05:08 +01:00
ed55660c80 Add finished issues to changelog for next version. 2024-01-16 22:26:18 +01:00
d0771e130a Remove debug output, bump version to -dev. 2024-01-16 22:16:51 +01:00
6282a934c6 Always handle lines starting with # as comment. 2024-01-16 22:14:41 +01:00
707bb1d61e More debugging. 2024-01-16 22:13:17 +01:00
ba2c753109 Allow parsing config lines without comments. 2024-01-16 22:10:56 +01:00
2674f08674 Print line-by-line for debugging. 2024-01-16 22:03:32 +01:00
3629844743 Convert condition to list. 2024-01-16 22:01:27 +01:00
65c7155ba3 Log exception details. 2024-01-16 21:58:30 +01:00
939af54e87 Sync mlcheck with mlsync. 2024-01-16 21:54:10 +01:00
a64ab232c6 Fix tests. 2024-01-16 21:50:13 +01:00
2baffe570b Update changelog for 1.15.1 2024-01-02 13:12:50 +01:00
14 changed files with 237 additions and 104 deletions

View file

@ -1,14 +1,41 @@
ChangeLog 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) * increase membership fees starting 2024-01 (specification.rkt)
* add support for explicit fee amounts for specified period * add support for explicit fee amounts for specified period
1.14 1.14 - released 2024-12-06
---- --------------------------
* add support for dynamic terminal size * add support for dynamic terminal size
* use table cell formatting instead of paragraph formatting everywhere * use table cell formatting instead of paragraph formatting everywhere

View file

@ -42,7 +42,7 @@ HACKERBASE-DEPS=hackerbase.scm cal-month.import.scm \
tests.import.scm notifications.import.scm logging.import.scm \ tests.import.scm notifications.import.scm logging.import.scm \
progress.import.scm cal-period.import.scm \ progress.import.scm cal-period.import.scm \
util-stdout.import.scm export-web-static.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 \ 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 \ 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 \ 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-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 \ 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 \ GENDOC-SOURCES=gendoc.scm duck-extract.import.scm \
util-time.import.scm util-csv.import.scm util-git.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-io.import.scm: $(UTIL-IO-SOURCES)
UTIL-PARSER-SOURCES=util-parser.scm testing.import.scm \ 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.o: util-parser.import.scm
util-parser.import.scm: $(UTIL-PARSER-SOURCES) 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 \ brmember-format.import.scm configuration.import.scm \
util-time.import.scm members-fees.import.scm mbase.import.scm \ util-time.import.scm members-fees.import.scm mbase.import.scm \
members-print.import.scm table.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.o: notifications.import.scm
notifications.import.scm: $(NOTIFICATIONS-SOURCES) notifications.import.scm: $(NOTIFICATIONS-SOURCES)
@ -550,3 +552,10 @@ TIOCGWINSZ-SOURCES=tiocgwinsz.scm duck.import.scm
tiocgwinsz.o: tiocgwinsz.import.scm tiocgwinsz.o: tiocgwinsz.import.scm
tiocgwinsz.import.scm: $(TIOCGWINSZ-SOURCES) 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)

View file

@ -499,8 +499,8 @@
(ldict-equal? (ldict-equal?
(make-brmember '|1234| "members/1234" '(|member|)) (make-brmember '|1234| "members/1234" '(|member|))
(make-ldict (make-ldict
`((file-name . |1234|) `((TAG . ,TAG-BRMEMBER)
(TAG . ,TAG-BRMEMBER) (file-name . |1234|)
(file-path . "members/1234") (file-path . "members/1234")
(symlinks |member|) (symlinks |member|)
(id . 1234))))) (id . 1234)))))

View file

@ -54,7 +54,7 @@
(users '())) (users '()))
(if (null? lines) (if (null? lines)
users users
(let ((line (parser-preprocess-line (car lines)))) (let ((line (parser-preprocess-line (car lines) #:strip-comments? #f)))
(if (equal? line "") (if (equal? line "")
(loop (cdr lines) (loop (cdr lines)
users) users)
@ -74,8 +74,8 @@
(handle-exceptions (handle-exceptions
exn exn
(let () (let ()
(log-warning "DokuWiki: cannot open ~A" fname) (log-warning "DokuWiki (~A) exception ~A" fname (condition->list exn))
(stdout-printf "DokuWiki: cannot open ~A" fname) (stdout-printf "DokuWiki (~A) exception ~A" fname (condition->list exn))
'()) '())
(with-input-from-file fname (with-input-from-file fname
parse-dokuwiki-users-auth))) parse-dokuwiki-users-auth)))

View file

@ -101,7 +101,7 @@
(print "<dt>Member ID, Variable Symbol for Payments<br>(Členské číslo, variabilní symbol plateb)</dt><dd>" (print "<dt>Member ID, Variable Symbol for Payments<br>(Členské číslo, variabilní symbol plateb)</dt><dd>"
(brmember-id mr) "</dd>") (brmember-id mr) "</dd>")
(print "<dt>Balance in CZK<br>(Zůstatek v Kč)</dt><dd>" (caar (reverse bhs)) "</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 "</dl>")
(print "</div>") (print "</div>")
(print "<div class=\"bi\">") (print "<div class=\"bi\">")

View file

@ -50,7 +50,8 @@
export-web-static export-web-static
dokuwiki dokuwiki
racket-kwargs racket-kwargs
util-string) util-string
mailinglist)
;; Command-line options and configurable parameters ;; Command-line options and configurable parameters
(define -needs-bank- (make-parameter #f)) (define -needs-bank- (make-parameter #f))
@ -286,32 +287,6 @@
(print " " (car keys) ": " (length (ldict-ref status (car keys))))) (print " " (car keys) ": " (length (ldict-ref status (car keys)))))
(loop (cdr 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 ;; Perform requested action
(case (-action-) (case (-action-)
((print-info) ((print-info)
@ -323,10 +298,7 @@
(let () (let ()
(print-members-base-table MB) (print-members-base-table MB)
(newline) (newline)
(check-mailing-list MLS "internal") (print-mailing-list-checks MB MLS)
(check-mailing-list MLS "rada"
#:pred? rada-ml-pred?)
(check-mailing-list MLS "rk" #:pred? brmember-revision?)
(print-git-status))) (print-git-status)))
(newline)) (newline))
((print-stats) ((print-stats)
@ -424,8 +396,8 @@
(print-git-status)) (print-git-status))
((summary) ((summary)
(if (-send-emails-) (if (-send-emails-)
(make+send-summary-email MB) (make+send-summary-email MB MLS)
(make+print-summary-email MB))) (make+print-summary-email MB MLS)))
((list) ((list)
(for-each (lambda (mr) (for-each (lambda (mr)
(print (brmember-nick mr))) (print (brmember-nick mr)))

78
src/mailinglist.scm Normal file
View 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)))
)

View file

@ -30,6 +30,7 @@
( (
lookup-member-fee lookup-member-fee
member-calendar member-calendar
make-member-calendar-entry
member-calendar-first-month member-calendar-first-month
member-calendar-last-month member-calendar-last-month
member-calendar-query member-calendar-query
@ -40,12 +41,14 @@
member-calendar->table member-calendar->table
members-summary members-summary
member-calendar-entry->fee member-calendar-entry->fee
get-expected-income-string
) )
(import scheme (import scheme
(chicken base) (chicken base)
(chicken format) (chicken format)
(chicken sort) (chicken sort)
(chicken string)
srfi-1 srfi-1
configuration configuration
brmember brmember
@ -82,15 +85,17 @@
(if (cal-month>? cm last-month) (if (cal-month>? cm last-month)
(reverse cal) (reverse cal)
(loop (cal-month-add cm) (loop (cal-month-add cm)
(cons (list cm (cons (with-current-month
(with-current-month
cm cm
(brmember-flags mr)) (make-member-calendar-entry mr))
(with-current-month
cm
(brmember-spec-fee mr)))
cal)))))) 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 ;; Returns the first month of the calendar
(define (member-calendar-first-month mc) (define (member-calendar-first-month mc)
(caar mc)) (caar mc))
@ -203,4 +208,25 @@
(cons 0 0) (cons 0 0)
members))) 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))))))
) )

View file

@ -500,7 +500,17 @@
(null? (cdr dsa))) (null? (cdr dsa)))
#f #f
(cadr dsa)))) (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 (map
(lambda (mr) (lambda (mr)
(let* ((balance (member-balance mr)) (let* ((balance (member-balance mr))
@ -522,15 +532,7 @@
total total
balance balance
))) )))
(sort raw-members))
(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<?)))
(balances (map (lambda (m) (balances (map (lambda (m)
(list-ref m 6)) (list-ref m 6))
members))) members)))
@ -598,19 +600,7 @@
(map (lambda (member) (map (lambda (member)
(min 0 (list-ref member 5))) (min 0 (list-ref member 5)))
members))) members)))
(let* ((ns (foldl (lambda (acc member) (print (get-expected-income-string MB)))))
(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)"))
)
))
(define (unpaired-table mb . args) (define (unpaired-table mb . args)
(apply (apply

View file

@ -40,6 +40,7 @@
(chicken format) (chicken format)
(chicken string) (chicken string)
(chicken sort) (chicken sort)
(chicken port)
brmember brmember
util-mail util-mail
util-bst-ldict util-bst-ldict
@ -54,7 +55,8 @@
table table
bank-account bank-account
logging logging
srfi-1) srfi-1
mailinglist)
;; Prints email to the console ;; Prints email to the console
(define (print-notification-email em) (define (print-notification-email em)
@ -142,16 +144,14 @@
(send-notification-email em))) (send-notification-email em)))
;; Summary email of membership fees payments ;; Summary email of membership fees payments
(define (summary-email-body mb) (define (summary-email-body mb mls)
(let* ((mbs (members-summary mb)) (let* ((mbs (members-summary mb))
(students (car mbs)) (students (car mbs))
(full (cdr mbs)) (full (cdr mbs))
(income (+ (* (lookup-member-fee 'normal) full) (income (+ (* (lookup-member-fee 'normal) full)
(* (lookup-member-fee 'student) students))) (* (lookup-member-fee 'student) students)))
(income-lst (income-lst
(list (format "Expected income: ~A CZK" income) (list (get-expected-income-string mb)))
(format " ~A full members" full)
(format " ~A students" students)))
(unpaired (mbase-unpaired mb)) (unpaired (mbase-unpaired mb))
(unpaired-lst (unpaired-lst
(if (null? unpaired) (if (null? unpaired)
@ -160,6 +160,30 @@
(list "" (list ""
"Unpaired transactions:") "Unpaired transactions:")
(unpaired-table mb #:border-style 'ascii)))) (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 (debtors (sort
(members-to-notify mb 1) (members-to-notify mb 1)
brmember<?)) brmember<?))
@ -256,6 +280,8 @@
", ")))))) ", "))))))
(append income-lst (append income-lst
unpaired-lst unpaired-lst
soonexps-lst
mlcheck-lst
debtors-lst debtors-lst
boring-lst boring-lst
dw-lst dw-lst
@ -266,21 +292,21 @@
)))) ))))
;; Creates the summary email structure ;; Creates the summary email structure
(define (make-summary-email mb) (define (make-summary-email mb mls)
(make-ldict (make-ldict
`((to . ,(*summary-mailto*)) `((to . ,(*summary-mailto*))
(subject . ,(format "Členské příspěvky ~A" (subject . ,(format "Členské příspěvky ~A"
(today/iso))) (today/iso)))
(body . ,(summary-email-body mb))))) (body . ,(summary-email-body mb mls)))))
;; Just print to standard output ;; Just print to standard output
(define (make+print-summary-email mb) (define (make+print-summary-email mb mls)
(let ((em (make-summary-email mb))) (let ((em (make-summary-email mb mls)))
(print-notification-email em))) (print-notification-email em)))
;; Actually send emails ;; Actually send emails
(define (make+send-summary-email mr) (define (make+send-summary-email mr mls)
(let ((em (make-summary-email mr))) (let ((em (make-summary-email mr mls)))
(send-notification-email em))) (send-notification-email em)))
) )

View file

@ -39,7 +39,7 @@
(chicken format)) (chicken format))
;; Short banner ;; 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 ;; Banner source with numbers for ANSI CSI SGR
(define banner-source " (define banner-source "

View file

@ -286,10 +286,12 @@
(call/cc (call/cc
(lambda (cc) (lambda (cc)
(set! break cc) (set! break cc)
(if resume (cond (resume
(resume '()) (resume '())
(bst-iter-kv bst yield)) (break #f))
#f))))) (else
(bst-iter-kv bst yield)
(break #f))))))))
(define/doc (bst-keys bst) (define/doc (bst-keys bst)
("Returns all the keys contained in given dictionary.") ("Returns all the keys contained in given dictionary.")

View file

@ -39,11 +39,12 @@ member file parsers. All functions are UTF-8 aware.")
(import scheme (import scheme
(chicken base) (chicken base)
racket-kwargs
testing) testing)
;; Pass 0: Removes any comments and removes any leading and trailing ;; Pass 0: Removes any comments and removes any leading and trailing
;; whitespace. ;; 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 ("* ```line``` - a string with contents of one source line
If the input ```line``` contains the ```#``` character, the rest of If the input ```line``` contains the ```#``` character, the rest of
@ -62,7 +63,9 @@ Returns a string representing the preprocessed line.")
(ploop (add1 pidx))))) (ploop (add1 pidx)))))
(hpos (let hloop ((hidx ppos)) (hpos (let hloop ((hidx ppos))
(if (or (= hidx llen) (if (or (= hidx llen)
(eq? (string-ref line hidx) #\#)) (and (or strip-comments?
(= hidx 0))
(eq? (string-ref line hidx) #\#)))
hidx hidx
(hloop (add1 hidx))))) (hloop (add1 hidx)))))
(spos (let sloop ((sidx (sub1 hpos))) (spos (let sloop ((sidx (sub1 hpos)))

View file

@ -120,13 +120,13 @@ of the string and a list of remaining bytes (as integers).")
(define/doc (utf8-bytes->lists chars) (define/doc (utf8-bytes->lists chars)
("The same as above but accepts a list of bytes (as integers).") ("The same as above but accepts a list of bytes (as integers).")
(let loop ((bytes chars) (let loop ((bytes chars)
(rpending '()) (rpending chars)
(pending 0) (pending 0)
(expected #f) (expected #f)
(res '())) (res '()))
(if (null? bytes) (if (null? bytes)
(values (reverse res) (values (reverse res)
(reverse rpending)) rpending)
(let ((byte (car bytes))) (let ((byte (car bytes)))
(cond (expected (cond (expected
;; Decode UTF-8 sequence ;; 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 (let ((char (integer->char (bitwise-ior pending
(bitwise-and byte #b111111))))) (bitwise-and byte #b111111)))))
(loop (cdr bytes) (loop (cdr bytes)
'() (cdr bytes)
0 0
#f #f
(cons char res)))) (cons char res))))
(else (else
;; Intermediate bytes ;; Intermediate bytes
(loop (cdr bytes) (loop (cdr bytes)
(cons byte rpending) rpending
(arithmetic-shift (bitwise-ior pending (arithmetic-shift (bitwise-ior pending
(bitwise-and byte #b111111)) 6) (bitwise-and byte #b111111)) 6)
(sub1 expected) (sub1 expected)
@ -152,7 +152,7 @@ of the string and a list of remaining bytes (as integers).")
(cond ((= (bitwise-and byte #b10000000) 0) (cond ((= (bitwise-and byte #b10000000) 0)
;; ASCII ;; ASCII
(loop (cdr bytes) (loop (cdr bytes)
'() (cdr bytes)
0 0
#f #f
(cons (integer->char byte) res))) (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 ;; First byte of UTF-8 sequence
(let-values (let-values
(((first-byte char-bytes) (((first-byte char-bytes)
(cond ((= (bitwise-and byte #b11000000) #b11000000) (cond ((= (bitwise-and byte #b11100000) #b11000000)
(values (bitwise-and byte #b11111) (values (bitwise-and byte #b11111)
2)) 2))
((= (bitwise-and byte #b11100000) #b11100000) ((= (bitwise-and byte #b11110000) #b11100000)
(values (bitwise-and byte #b1111) (values (bitwise-and byte #b1111)
3)) 3))
((= (bitwise-and byte #b11110000) #b11110000) ((= (bitwise-and byte #b11111000) #b11110000)
(values (bitwise-and byte #b111) (values (bitwise-and byte #b111)
4)) 4))
(else (else
;; Should not happen ;; Should not happen
(values 0 0))))) (values 0 0)))))
(loop (cdr bytes) (loop (cdr bytes)
(list byte) bytes
(arithmetic-shift first-byte 6) (arithmetic-shift first-byte 6)
(sub1 char-bytes) (sub1 char-bytes)
res)))))))))) res))))))))))