; shell.ss - Shell programing utilities ; ; Copyright (c) 2009 Higepon(Taro Minowa) ; ; Redistribution and use in source and binary forms, with or without ; modification, are permitted provided that the following conditions ; are met: ; ; 1. Redistributions of source code must retain the above copyright ; notice, this list of conditions and the following disclaimer. ; ; 2. Redistributions in binary form must reproduce the above copyright ; notice, this list of conditions and the following disclaimer in the ; documentation and/or other materials provided with the distribution. ; ; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED ; TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR ; PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ; LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ; ; $Id: shell.ss 621 2008-11-09 06:22:47Z higepon $ (library (mosh shell) (export def-command $def-command cd -> $-> def-alias) (import (only (rnrs) define define-syntax syntax-case ... syntax lambda let-values list display current-error-port syntax->datum quote with-syntax datum->syntax string->symbol close-port syntax-rules let transcoded-port make-transcoder utf-8-codec if eof-object? list->string reverse cons read-char map pair? car cdr begin do = length +) (only (srfi :98) get-environment-variable) (only (system) %waitpid %pipe) (only (mosh process) spawn) (only (mosh) format string-split set-current-directory! current-directory)) (define-syntax def-alias (lambda (y) (syntax-case y() [(_ name body ...) #'(define-syntax name (lambda (x) (syntax-case x () [_ (begin body ...)])))]))) (define-syntax def-command (lambda (y) (syntax-case y () [(_ command) #'(define-syntax command (lambda (x) (syntax-case x () [(_ args (... ...)) #'(spawn (any->string (syntax->datum #'command)) (map any->string (syntax->datum #'(args (... ...)))))] [_ #'(spawn (any->string (syntax->datum #'command)) '())] )))]))) ;; spawn and get result as list of string (define-syntax $def-command (lambda (y) (syntax-case y () [(k command) (with-syntax ([$command (datum->syntax #'k (string->symbol (format "$~a" (syntax->datum #'command))))]) #'(define-syntax $command (lambda (x) (syntax-case x () [(_ args (... ...)) #'(string-split (spawn->string (any->string (syntax->datum #'command)) (map any->string (syntax->datum #'(args (... ...))))) #\newline)] [_ #'(string-split (spawn->string (any->string (syntax->datum #'command)) '()) #\newline)] ))))]))) (define-syntax cd (lambda (x) (syntax-case x () [(_ arg) #'(set-current-directory! (format "~a" (syntax->datum #'arg)))] [_ #'(set-current-directory! (get-environment-variable "HOME"))]))) ;; pipe ;; usage: (-> ls (grep hoge)) (define-syntax -> (lambda (x) (syntax-case x () [(_ x y z ...) #'(pipe ((any->string (if (pair? (syntax->datum #'x)) (car (syntax->datum #'x)) (syntax->datum #'x))) (map any->string (if (pair? (syntax->datum #'x)) (cdr (syntax->datum #'x)) '()))) ((any->string (if (pair? (syntax->datum #'y)) (car (syntax->datum #'y)) (syntax->datum #'y))) (map any->string (if (pair? (syntax->datum #'y)) (cdr (syntax->datum #'y)) '()))) ((any->string (if (pair? (syntax->datum #'z)) (car (syntax->datum #'z)) (syntax->datum #'z))) (map any->string (if (pair? (syntax->datum #'z)) (cdr (syntax->datum #'z)) '()))) ...)]))) ;; pipe ;; get result of pipe as string (define-syntax $-> (lambda (x) (syntax-case x () [(_ x y z ...) #'(let-values ([(in out) (%pipe)]) ($pipe out ((any->string (if (pair? (syntax->datum #'x)) (car (syntax->datum #'x)) (syntax->datum #'x))) (map any->string (if (pair? (syntax->datum #'x)) (cdr (syntax->datum #'x)) '()))) ((any->string (if (pair? (syntax->datum #'y)) (car (syntax->datum #'y)) (syntax->datum #'y))) (map any->string (if (pair? (syntax->datum #'y)) (cdr (syntax->datum #'y)) '()))) ((any->string (if (pair? (syntax->datum #'z)) (car (syntax->datum #'z)) (syntax->datum #'z))) (map any->string (if (pair? (syntax->datum #'z)) (cdr (syntax->datum #'z)) '()))) ...) (port->string (transcoded-port in (make-transcoder (utf-8-codec)))))] ))) (define-syntax begin0 (syntax-rules () ((_ e es ...) (let ((v e)) es ... v)))) ;(define (spawn command args) ; (let-values ([(pid cin cout cerr) (%spawn command args (list #f #f #f))]) ; (%waitpid pid) ; #f)) (define (spawn->string command args) (let-values ([(in out) (%pipe)]) (let-values ([(pid cin cout cerr) (spawn command args (list #f out #f))]) (close-port out) (begin0 (port->string (transcoded-port in (make-transcoder (utf-8-codec)))) (close-port in) (%waitpid pid))))) (define (port->string p) (let loop ([ret '()][c (read-char p)]) (if (eof-object? c) (list->string (reverse ret)) (loop (cons c ret) (read-char p))))) (define (any->string x) (format "~a" x)) ;; backend of ->. (define-syntax pipe (lambda (x) (syntax-case x () [(_ (cmd1 args1) (cmd2 args2) ...) #'(let-values ([(in1 out1) (%pipe)]) (spawn cmd1 args1 (list #f out1 #f)) (close-port out1) (pipe "internal" in1 (cmd2 args2) ...) (do ([i 0 (+ i 1)]) ((= i (length '((cmd2 args2) ...)))) (%waitpid -1)))] [(_ "internal" in (cmd args)) #'(begin (spawn cmd args (list in #f #f)) (close-port in))] [(_ "internal" in (cmd1 args1) (cmd2 args2) (cmd3 args3) ...) #'(let-values ([(in1 out1) (%pipe)]) (spawn cmd1 args1 (list in out1 #f)) (close-port out1) (pipe "internal" in1 (cmd2 args2) (cmd3 args3) ...))] ))) (define-syntax $pipe (lambda (x) (syntax-case x () [(_ out (cmd1 args1) (cmd2 args2) ...) #'(let-values ([(in1 out1) (%pipe)]) (spawn cmd1 args1 (list #f out1 #f)) (close-port out1) ($pipe "internal" out in1 (cmd2 args2) ...) (do ([i 0 (+ i 1)]) ((= i (length '((cmd2 args2) ...)))) (%waitpid -1)))] [(_ "internal" out in (cmd args)) #'(begin (spawn cmd args (list in out #f)) (close-port out) (close-port in))] [(_ "internal" out in (cmd1 args1) (cmd2 args2) (cmd3 args3) ...) #'(let-values ([(in1 out1) (%pipe)]) (spawn cmd1 args1 (list in out1 #f)) (close-port out1) ($pipe "internal" out in1 (cmd2 args2) (cmd3 args3) ...))] ))) (display "(mosh shell) library is deprecated.\n" (current-error-port)) )