(define first car) (define second cadr) (define third caddr) (define fourth cadddr) (define rest cdr) (define wc (lambda args (call-with-values (lambda () (let loop ([args args] [options '()]) (cond [(null? args) (values options args)] [(string? (first args)) ;; the options have been processed (values options args)] [else (loop (rest args) (cons (first args) options))]))) (lambda (options all-files) (if (null? all-files) ;; then process the (current-input-port) (call-with-values (lambda () (process-input (current-input-port))) (lambda (chars words lines) `( (chars ,chars) (words ,words) (lines ,lines)))) ;; else process the list of the input files ;; keeping track of a running total (let loop ([files all-files] [total_chars 0] [total_words 0] [total_lines 0]) (if (null? files) (if (null? (cdr all-files)) ;; there was only 1 file '() ;; else return a summary (list `(Total (chars ,total_chars) (words ,total_words) (lines ,total_lines)))) (call-with-input-file (first files) (lambda (port) (call-with-values (lambda () (process-input port)) (lambda (chars words lines) (cons `(,(first files) (chars ,chars) (words ,words) (lines ,lines)) (loop (rest files) (+ total_chars chars) (+ total_words words) (+ total_lines lines)))))))))))))) (define process-input (lambda (port) (let loop ([chars 0] [words 0] [lines 0] [state 's0] [in (read-char port)]) (if (eof-object? in) (values chars words lines) (case state [(s0) (case in [(#\newline) (loop (add1 chars) words (add1 lines) 's0 (read-char port))] [(#\space #\tab) (loop (add1 chars) words lines 's0 (read-char port))] [else (loop (add1 chars) words lines 's1 (read-char port))])] [(s1) (case in [(#\newline) (loop (add1 chars) (add1 words) (add1 lines) 's0 (read-char port))] [(#\space #\tab) (loop (add1 chars) (add1 words) lines 's0 (read-char port))] [else (loop (add1 chars) words lines 's1 (read-char port))])])))))