Here are some suggestions (and sample implementations) of some
features that I missed when re-writing a bunch of /bin/sh and perl
scripts in scsh. Feel free to use the code if you wish.
* argc
I found that I used (length command-line-arguments) at least once in
most of my scripts. It would be useful to have a function that
corresponded to `arg' and `argv' that is used for finding the number
of arguments to a script.
(argc [command-line]) => integer
When no arguments are supplied, `argc' returns the number of
command line arguments or (length command-line-arguments). When
a list of arguments is provided, it returns the length of that
list.
A magic variable `argument-count' could be provided instead.
* split
There should be a set of functions for splitting strings into a list
of strings. I propose:
(split string) => list of strings
Splits a string into a list of whitespace delimited string fields.
(split-fields character string) => list of strings
Splits a string into a list of strings based on a delimiter character.
(regexp-split regexp string) => list of strings
Splits a string into a list of strings based on a delmiting regexp.
* file->list et al
I found myself doing things like (port->string-list (open-input-file "foo"))
an awful lot. It would be nice to have
(file->string filename)
(file->sexp-list filename)
(file->string-list filename)
(file->list reader filename)
---sample implementations---
; With no arguments, return the number of command line arguments.
; If passed an argument list, return the length of the list.
;
(define (argc . maybe-list)
(let ((command-line #f))
(cond
((null? maybe-list)
(set! command-line command-line-arguments))
((null? (cdr maybe-list))
(set! command-line (car maybe-list)))
(else (error "bad argument to ARGC")))
(if (not (list? command-line))
(error "bad command line to ARGC"))
(length command-line)))
; Split a string into a list of strings by stripping whitespace
; from the beginning and end of the original string, pulling
; out whitespace delimited fields.
;
(define (split string)
(let ((len (string-length string)))
(define (skip index)
(cond
((= index len) '())
((char-whitespace? (string-ref string index))
(skip (+ index 1)))
(else (collect index index))))
(define (collect start end)
(cond
((= end len)
(list (substring string start end)))
((char-whitespace? (string-ref string end))
(cons (substring string start end)
(skip (+ end 1))))
(else (collect start (+ end 1)))))
(skip 0)))
; Split a string into a list of strings based on
; a single delimiter character. Multiple occurences of
; the delimiter character are significant.
;
(define (split-fields delimiter string)
(let ((len (string-length string)))
(define (collect start end)
(cond
((= end len)
(list (substring string start end)))
((char=? (string-ref string end) delimiter)
(cons (substring string start end)
(collect (+ end 1) (+ end 1))))
(else (collect start (+ end 1)))))
(collect 0 0)))
; Split a string into a list of strings based on a delimiting
; regular expression.
;
(define (regexp-split regexp string)
(let ((regexp (if (regexp? regexp) regexp (make-regexp regexp)))
(len (string-length string)))
(let loop ((i 0))
(if (= i len)
'()
(let ((match (regexp-exec regexp string i)))
(if match
(cons (substring string i (match:start match))
(loop (match:end match)))
(list (substring string i len))))))))
; These routines correspond to port->list, file->string,
; file->sexp-list, and file->string-list, but obviate the
; need for opening the file.
;
(define (file->list reader filename)
(call-with-input-file filename
(lambda (port) (port->list reader port))))
(define (file->string filename)
(call-with-input-file filename
(lambda (port) (port->string port))))
(define (file->sexp-list filename)
(file->list read filename))
(define (file->string-list filename)
(file->list read-line filename))
|