#!/usr/bin/perl -w
# genrpbindings -- generate ratpoison bindings for various languages
#
# Copyright (C) 2003, 2004 Ryan Yeske, Doug Kearns, Shawn Betts
#
# currently generates bindings for:
# * Perl (Ratpoison.pm) Ryan Yeske <rcyeske@sfu.ca>
# * Emacs Lisp (ratpoison-cmd.el) Ryan Yeske <rcyeske@sfu.ca>
# * Ruby (ratpoison.rb) Doug Kearns <djkea2@mugc.its.monash.edu.au>
# * Common Lisp (ratpoison.lisp) Shawn Betts <sabetts@vcn.bc.ca>
# * Python (ratpoison.py) Mike O'Connor <stew@vireo.org>
# add more languages!
#
# Bindings are just very thin wrappers, no argument checking is done.
# All of the functions return a string.
#
# Example: ratpoison --command='echo hello world'
#
# #!perl
# use Ratpoison;
# Ratpoison::echo ("hello world")
#
# ;;; elisp
# (require 'ratpoison-cmd)
# (ratpoison-echo "hello world")
#
# #!ruby
# require "ratpoison"
# Ratpoison.echo ("hello world")
#
# ;;; Common Lisp
# (load "ratpoison.lisp")
# (ratpoison:rp-echo "hello world")
#
# #!python
# import ratpoison
# ratpoison.echo( "hello world" )
$\="\n";
# set this to your rp binary
$RATPOISON=$ENV{RATPOISON} || "ratpoison";
# open source file
$ACTIONS_C="../src/actions.c";
open ACTIONS_C or die "Can't open $ACTIONS_C";
# open target files
$PERL_FILE="./Ratpoison.pm";
$ELISP_FILE="./ratpoison-cmd.el";
$RUBY_FILE="./ratpoison.rb";
$COMMONLISP_FILE="./ratpoison.lisp";
$PYTHON_FILE="./ratpoison.py";
open PERL, ">$PERL_FILE" or die "Can't create $PERL_FILE";
open ELISP, ">$ELISP_FILE" or die "Can't create $ELISP_FILE";
open RUBY, ">$RUBY_FILE" or die "Can't create $RUBY_FILE";
open COMMONLISP, ">$COMMONLISP_FILE" or die "Can't create $COMMONLISP_FILE";
open PYTHON, ">$PYTHON_FILE" or die "Can't create $PYTHON_FILE";
# PERL preamble
print PERL 'package Ratpoison;';
print PERL '$RATPOISON="',$RATPOISON,'";';
print PERL 'sub command { return `$RATPOISON -c "@_"`; }';
# ELISP preamble
print ELISP '(defvar ratpoison-program "',$RATPOISON,'")';
print ELISP <<PREAMBLE;
(defmacro defun-ratpoison (cmd)
`(progn (defun ,(intern (concat "ratpoison-" (symbol-name cmd))) (&rest args)
(apply 'ratpoison-cmd ,(symbol-name cmd) args))))
(defun ratpoison-cmd (cmd &rest args)
(with-temp-buffer
(call-process ratpoison-program nil (current-buffer) t
"-c" (format "%s %s"
cmd
(mapconcat (lambda (x)
(if (stringp x)
x
(prin1-to-string x)))
args " ")))
(buffer-substring (point-min) (if (> (point-max) 1)
(- (point-max) 1)
(point-max)))))
PREAMBLE
# RUBY preamble
print RUBY <<PREAMBLE;
module Ratpoison
RATPOISON="$RATPOISON"
def command (command, *args)
return `#{RATPOISON} -c "#{command} #{args.join(' ')}"`
end
module_function :command
PREAMBLE
# Scheme preamble
print COMMONLISP <<PREAMBLE;
(defpackage :ratpoison
(:use :cl))
;; Needs the CLOCC PORT package
(asdf:operate 'asdf:load-op :port)
(in-package :ratpoison)
(defvar ratpoison-program "$RATPOISON")
(defmacro defun-ratpoison (cmd)
(let ((sym (intern (concatenate 'string "RP-" (symbol-name cmd)))))
`(progn (defun ,sym (&rest args)
(apply 'ratpoison-cmd ,(string-downcase (symbol-name cmd)) args))
(export ',sym))))
(defun ratpoison-cmd (cmd &rest args)
(labels ((mapconcat (fn list sep)
(apply 'concatenate 'string
(loop for x on list
collect (if (cdr x)
(concatenate 'string (funcall fn (car x)) sep)
(funcall fn (car x))))))
(build-cmd (cmd args)
(mapconcat (lambda (x)
(if (stringp x)
x
(prin1-to-string x)))
(nconc (list cmd) args) " ")))
(let ((stream (port:pipe-input ratpoison-program
"-c" (build-cmd cmd args))))
(do ((line (read-line stream nil nil)
(read-line stream nil nil))
(accum nil (cons line accum)))
((null line) accum)))))
PREAMBLE
# python preamble
print PYTHON <<PREAMBLE;
import os
ratpoison="ratpoison -c "
def rp_command( *args ):
p = os.popen( ratpoison + '"' + (' '.join( args ) ) + '"', 'r' )
r = p.readlines();
p.close();
return r
PREAMBLE
# bindings
while (<ACTIONS_C>) {
if (m!/\*\@begin !) {
while (<ACTIONS_C>)
{
last if (m!/\*\@end !);
if (/\s*add_command\s*\(\"([^\"]+)\",\s*[^\"]+,\s*([0-9]+),\s*[0-9]+,\s*([0-9]+)/) {
my $name = $1;
my $numargs = $2;
my $optargs = $3;
# Skip the arguments
for (my $i=0; $i<$numargs; $i++) {
<ACTIONS_C>;
}
$nbindings++;
print PERL "sub $name { return command (\"$name\", \@_); }";
print ELISP "(defun-ratpoison $name)";
print COMMONLISP "(defun-ratpoison $name)";
print RUBY " def $name (*args)";
print RUBY " return command (\"$name\", args)";
print RUBY " end";
print RUBY " module_function :$name\n";
print PYTHON "def rp_$name( *args ): return rp_command ( '$name ' + ' '.join( args ) )";
}
}
}
}
print "$nbindings bindings.";
# PERL postamble
# nothing
# ELISP postamble
print ELISP '(provide \'ratpoison-cmd)';
# RUBY postamble
print RUBY "end";
# PYTHON postamble
# nothing
close PERL;
print "Created $PERL_FILE";
close ELISP;
print "Created $ELISP_FILE";
close RUBY;
print "Created $RUBY_FILE";
close COMMONLISP;
print "Created $COMMONLISP_FILE";
close PYTHON;
print "Created $PYTHON_FILE";
syntax highlighted by Code2HTML, v. 0.9.1