ラベル perl の投稿を表示しています。 すべての投稿を表示
ラベル perl の投稿を表示しています。 すべての投稿を表示

2013-03-04

perl-5.005_04 が make できなくて困る

- 追記 make できました。-

perl-5.005 のテスト環境が欲しかったので、
WinXP に VMware Player と Ubuntu 12.04 をインストール。
perlbrew で perl-5.005_04 をインストールしてみたところ、見事にこける。

Linux とコンパイルに関して、ほとんどわからないので非常に困る。
インストールログのエラー部分はこんな感じ。

makedepend でエラーが出てるので makedepend.SH を修正。
$ diff -u makedepend.SH.orig makedepend.SH
--- makedepend.SH.orig 2004-01-14 05:16:31.000000000 +0900
+++ makedepend.SH 2013-03-03 00:00:00.000000000 +0900
@@ -51,6 +51,10 @@
  ;;
 esac
 
+# Avoid localized gcc/cc messages
+LC_ALL=C
+export LC_ALL
+
 # We need .. when we are in the x2p directory if we are using the
 # cppstdin wrapper script.
 # Put .. and . first so that we pick up the present cppstdin, not
@@ -113,7 +117,7 @@
     *.y) filebase=`basename $file .y` ;;
     esac
     case "$file" in
-    */*) finc="-I`echo $file | sed 's#/[^/]*$##`" ;;
+    */*) finc="-I`echo $file | sed 's#/[^/]*$##'`" ;;
     *)   finc= ;;
     esac
     $echo "Finding dependencies for $filebase$_o."
@@ -132,6 +136,7 @@
  -e '/^#.*<builtin>/d' \
  -e '/^#.*<built-in>/d' \
  -e '/^#.*<command line>/d' \
+ -e '/^#.*<command-line>/d' \
  -e '/^#.*"-"/d' \
  -e 's#\.[0-9][0-9]*\.c#'"$file.c#" \
  -e 's/^[  ]*#[  ]*line/#/' \


問題は次の miniperlmain.o のエラー。
'bool'型が定義されてないというのは何となくわかるが
ソースコードを修正するのか、
環境設定やコンパイルオプションを修正するのか判断がつかない。

エラーメッセージが日本語だとググれないので "$ LANG=C make" するとこんな感じ。

$ cd /home/user01/perl5/perlbrew/build/perl5.005_04
$ LANG=C make
`sh  cflags libperl.a miniperlmain.o`  miniperlmain.c
   CCCMD =  cc -DPERL_CORE -c -I/usr/local/include -O2   
In file included from perl.h:1276:0,
                 from miniperlmain.c:11:
cop.h:218:5: error: unknown type name 'bool'
cop.h:219:5: error: unknown type name 'bool'
....
"unknown type name bool" でググると perlbrew で fix された形跡を発見。
Fixes Configure options for ancient perls by friedo ・ Pull Request #249 ・ gugod/App-perlbrew ・ GitHub
perlbrew は 0.59 なので fix済みのようだけど、やっぱり make できない。

コンパイル環境がおかしいのかと、perl-5.8.9 を試してみたが、あっさりインストール完了。

考えられる状況としては
 ・コンパイルの設定が間違ってる
 ・コンパイラが非対応になった
 ・Ubuntu の環境が特殊
といったところか。

もうちょっと make 周りを理解しないと解決しなさそう。
とりあえず他のディストロでも試さないとダメかな。

- 追記 make できた! -

ついに解決!
何と15年前の ML に答えがありました。

[debian-users:05717] perl_5.004.04 & inn_1.7.2
[debian-users:05722] Re: perl_5.004.04 & inn_1.7.2
[debian-users:05745] Re: perl_5.004.04 & inn_1.7.2
ccflags='-Dbool=char -DHAS_BOOL'
このオプションを指定すればいいらしい。

Configure でうまく設定できなかったので config.sh を直接編集。
#config.sh
-    ccflags='-I/usr/local/include'
+    ccflags='-Dbool=char -DHAS_BOOL -I/usr/local/include'
make できたーーーーーーーーーーー!!!!

make test は2つほどこけます。
pragma/constant....FAILED at test 35
lib/db-btree.......Can't locate DB_File.pm in @INC (@INC contains: ../lib) at lib/db-btree.t line 21.
BEGIN failed--compilation aborted at lib/db-btree.t line 21.
FAILED at test 0
Failed 2 test scripts out of 190, 95.79% okay.
"で" な日々(2002年7月上旬)

perl 5.6.1 の compile で、make test の pragma/constant のところで
failed になってしまうのは、LANG を C にすると回避できた。
"$ LANG=C make test" で無事通過。
残りの DB_File.pm は BerkeleyDB 関連で、使わなければ無視してもいいみたい。

ということで "$ make install"。
$ perlbrew use 5.005_04
$ perl -v

This is perl, version 5.005_04 built for i686-linux

Copyright 1987-1999, Larry Wall

Perl may be copied only under the terms of either the Artistic License or the
GNU General Public License, which may be found in the Perl 5.0 source kit.

Complete documentation for Perl, including FAQ lists, should be found on
this system using `man perl' or `perldoc perl'.  If you have access to the
Internet, point your browser at http://www.perl.com/, the Perl Home Page.

感動した(T T)
ここまでたどり着けたのも、ひとえに先人のお陰です。
ありがとう。


参考リンク

perlbrew - search.cpan.org

[Perl] Debian (lenny) Perl 5.005・5.6.2 インストール失敗 Kawanet Blog II/ウェブリブログ
Mac OS X 10.6(Snow Leopard)にPerl 5.005をインストールする:Kawanet Blog II
Ubuntu8.10にPerl5.005_04をインストール - なんとなく目記
LinuxにPerl5.005_04をインストールする方法(makeで失敗した場合の対処法) - DQNEO起業日記
Perl の make 時に miniperl でエラーになる場合の対処方法 :: drk7jp

[debian-users:05717] perl_5.004.04 & inn_1.7.2
[debian-users:05722] Re: perl_5.004.04 & inn_1.7.2
[debian-users:05745] Re: perl_5.004.04 & inn_1.7.2

2012-09-23

perl - windows の電源コントロール

コマンドプロンプトのみでサスペンド(スリープ)は、できないみたいなので perl で挑戦。

PowrProf.dll と shutdown.exe を呼んで
サスペンド、ハイバネート、シャットダウン、リブート、ログオフを
n 秒後に実行できるようにしてみました。

サスペンド後にタスクスケジューラでの復帰もできます。(後述)
テスト環境は winXP SP3、Activeperl 5.14。

#使用例

#t オプションのデフォルト値は 30秒
#カウントダウン中、CTRL+C で中止します

#60秒後にサスペンド
> pwrctrl.pl -s -t 60
> pwrctrl.pl --suspend --timeout 60

#即シャットダウン
> pwrctrl.pl -d -t 0
> pwrctrl.pl --shutdown --timeout 0

#ヘルプ
> pwrctrl.pl -?
> pwrctrl.pl --help

# pwrctrl.pl
# windows power control script

use strict;
use warnings;
use Getopt::Long;
use Win32::API;

our $VERSION = "0.02";

$| = 1;                 #no buffering
$Win32::API::DEBUG = 0; #Win32::API debug flag


my $cmd = init();

count_down($cmd);

my $return_code = $cmd->{'run'}->();

print "return code : $return_code\n";

exit;

#--------------------

sub init{
    usage() unless @ARGV;

    ###get options
    my $opts = {'timeout' => 30}; #default

    GetOptions($opts,
        'help|?',
        'hibernate|h',
        'suspend|s',
        'shutdown|d',
        'reboot',
        'logoff',
        'timeout=i',
        ) || usage();

    usage() if $opts->{'help'};


    ###set command
    my $api = Win32::API->new('Powrprof', 'SetSuspendState', 'NNN', 'N')
                || die "Can't load API : $!\n";

    my $cmd_table = {
        'hibernate'=> sub{ $api->Call(1,0,0)  },
        'suspend'  => sub{ $api->Call(0,0,0)  },
        'shutdown' => sub{ `shutdown -s -t 0` },
        'reboot'   => sub{ `shutdown -r -t 0` },
        'logoff'   => sub{ `shutdown -l -t 0` },
        };
    my $cmd = {'timeout' => $opts->{'timeout'}};

    for my $key (keys %$opts) {
        next if $key =~ /help|timeout/;
        $cmd->{'name'} = $key;
        $cmd->{'run'}  = $cmd_table->{$key};
        last;
    }

    usage(qq/option requires "-h -s -r -d -l -? [-t]"/)
        unless $cmd->{'name'};

    return $cmd;
}


sub count_down{
    my $cmd = shift;
    my $command = uc $cmd->{'name'};
    my $timeout = $cmd->{'timeout'};
    
    local $SIG{'INT'} = 'abort';

    print<<"EOM";

$command after $timeout seconds.
Press [CTRL+C] to abort.

EOM

    return if $timeout == 0;

    for my $sec (reverse (0..$timeout)) {
        printf "\r%3d sec", $sec;
        sleep 1;
        printf "\r%10s\r", "";
    }
}


sub abort {
    print "\n\n", "abort!\n";
    exit;
}


sub usage {
    my $msg = shift;
    print "$msg\n" if $msg;
    
    print<<"EOM";

- windows power control script v$VERSION -

Usage   : pwrctrl.pl option [timeout]
          pwrctrl.pl -d -t 60   # shutdown after 60sec

Options :
    -? --help         this document

    -h --hibernate    hibernate
    -s --suspend      suspend
    -r --reboot       reboot
    -d --shutdown     shutdown
    -l --logoff       logoff

    [-t] [--timeout]  run after n seconds
                      default is 30
EOM

    exit;
}

__END__


rundll32.exe だと自動復帰できない

> rundll32.exe PowrProf.dll,SetSuspendState 0,1,0

> rundll32.exe PowrProf.dll,SetSuspendState Sleep

コマンドプロンプトからサスペンドするのに上記のコードがWEB上で見つかります。
サスペンドするだけなら問題ないみたいですが、 タスクスケジューラでの自動復帰ができません。
※Windows7 だと問題なく自動復帰できるようです。


Rundll32.exe は正しい使用法なのか?

まず、Rundll32.exe の仕様を確認します。
Windows の Rundll と Rundll32 インターフェイス

これによると、Rundll32.exe は以下のように dll の関数呼び出しをする仕様です。
void CALLBACK
EntryPoint(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow);

hwnd        - DLL で作成する任意のウィンドウのオーナー ウィンドウとして
              使用するウィンドウ ハンドル
hinst       - DLL のインスタンス ハンドル
lpszCmdLine - DLL で解析する ASCIIZ コマンド ライン
nCmdShow    - DLL のウィンドウを表示する方法を指定

Rundll32.exe は dll の関数への引数を 文字列 として渡します。
引数は dll がパースしてねという仕様です。


次に、SetSuspendState の仕様を確認します。
SetSuspendState function - MSDN
C++
BOOLEAN WINAPI SetSuspendState(
    _In_  BOOLEAN Hibernate,
    _In_  BOOLEAN ForceCritical,
    _In_  BOOLEAN DisableWakeEvent
);
SetSuspendState の正しい引数は bool値 3つ。

1つ目は、 0 = サスペンド、 1 = ハイバネート
2つ目は、 0 = アプリケーションの終了を待って中断、 1 = 強制的に中断
3つ目は、 0 = wake イベント有効、 1 = wake イベント無効


これらを踏まえると、先の Rundll32.exe 経由の SetSuspendState 呼び出しはこうなります。
> rundll32.exe PowrProf.dll,SetSuspendState 0,1,0

SetSuspendState( hwnd, hinst, "0,1,0", nCmdShow );

引数を渡すと DisableWakeEvent の値が TRUE になるので
wake イベントで復帰できないというわけです。


つまり、Rundll32.exe 経由での SetSuspendState 呼び出しは間違ってます。


perl 以外の方法

1. SetSuspendState というソフトを使う。
SetSuspendState - Vector
Sleep/Standby
> SetSuspendState
  or
> SetSuspendState 0

Hibernate
> SetSuspendState 1

非常に簡易なソフト。
サスペンドか、ハイバネートするだけ。
秒数の指定とかもできないけど、そのへんはバッチなりなんなりで対応。

ソースを見ると下のように ForceCritical の値が TRUE なので注意が必要かも。

SetSuspendState( 0, 1, 0 );  // Sleep
SetSuspendState( 1, 1, 0 );  // Hibernate


2. Ruby で SetSuspendState を実行。
コマンドラインからWindows PCを停止(スリープなど)する方法 | TipsZone


3. お好きな言語でAPIを叩く。


-------------------------
なんで shutdown.exe にサスペンド、ハイバネートのオプションないんでしょうね?


参考リンク

Windows の Rundll と Rundll32 インターフェイス
SetSuspendState function
SetSuspendState function (Windows)
Application.SetSuspendState メソッド (System.Windows.Forms)

プログラミングTips : SetSystemPowerState() の罠
コマンドラインからWindows PCを停止(スリープなど)する方法 | TipsZone
SetSuspendState - Vector

2012-08-04

いまさら perl v5.5

もっぱら perl はローカルで使ってるので、バージョンやモジュールで困ることはないのですが、
久しぶりにプロバイダの提供スペースで CGI 使って遊ぼうと思い環境調査してみました。

#!/usr/local/bin/perl

use strict;
use warnings;

print "Content-type: text/html;\n\n";

print "perl : $]<br>\n";
print "$_ : $ENV{$_}<br>\n" for sort keys %ENV;

なぜか500エラー。
shebang は合ってるしなんで?
試しに use を外してみたら動きました。

古いといっても v5.8 だろうと思っていたところ
驚愕の v5.5.3 !!!!!

ちょっと手元の corelist さんに聞いてみましょう。
corelist は v5.8.9 以降なら標準で入ってるみたいです。

C:\>corelist Module::CoreList
Module::CoreList was first released with perl v5.8.9

C:\>corelist strict
strict was first released with perl 5

C:\>corelist warnings
warnings was first released with perl v5.6.0

C:\>corelist utf8
utf8 was first released with perl v5.6.0

C:\>corelist Encode
Encode was first released with perl v5.7.3

・・・。
strict しか使えないじゃないですか!!
いまさら EUC でコーディングとかしたくないなー。
正直、サーバーのエラーログをエラーまみれにしそうな予感しかしない。


perl v5.5.3 で使えないもの

・warnings.pm
・utf8.pm
・Encode.pm

# 3引数 open は perl v5.6 以降
open( INFO, ">", $datafile ) or die $!;

# 間接ファイルハンドルも perl v5.6 以降
open( my $in, "> $infile" )  or die $!;

# our も perl v5.6 以降
our $var;
# 代わりに use vars
use vars qw($var);
# perl v5.14 から一部の関数がリファレンスを受け取れるようになったので
# この書き方で楽してるとデリファレンスでエラーが出てハマルかも。

http://perldoc.perl.org/perl5140delta.html#Syntactical-Enhancements

|----------------------------+---------------------------|
| Traditional syntax         | Terse syntax              |
|----------------------------+---------------------------|
| push    @$arrayref, @stuff | push    $arrayref, @stuff |
| unshift @$arrayref, @stuff | unshift $arrayref, @stuff |
| pop     @$arrayref         | pop     $arrayref         |
| shift   @$arrayref         | shift   $arrayref         |
| splice  @$arrayref, 0, 2   | splice  $arrayref, 0, 2   |
| keys    %$hashref          | keys    $hashref          |
| keys    @$arrayref         | keys    $arrayref         |
| values  %$hashref          | values  $hashref          |
| values  @$arrayref         | values  $arrayref         |
| ($k,$v) = each %$hashref   | ($k,$v) = each $hashref   |
| ($k,$v) = each @$arrayref  | ($k,$v) = each $arrayref  |
|----------------------------+---------------------------|

まだまだハマリどころがありそう。
文字コード周りは Jcode.pm を使うのかな。


500 Internal Server Error の対応

500エラーが出たときにサーバーのエラーログが見れない場合どうするか。
CGI::Carp を使う。

C:\>corelist CGI::Carp
CGI::Carp was first released with perl 5.004
perl v5.4 からコアモジュールで安心。
# エラーをブラウザに表示
use CGI::Carp qw(fatalsToBrowser);

# エラーをログファイルに書き出す
BEGIN {
  use CGI::Carp qw(carpout);
  # perl v5.5.3 なので 3引数open は使えない
  open(LOG, ">> ./err.log") or die $!;
  carpout(LOG);
}

fatalsToBrowser はメジャーだけど
carpout は今回調べるまで知らなかった。

他にも KCatch.pm というモジュールもあります。


perl v5.5.3 環境を作る?

perl のバージョンを切り替える perlbrew というものがありますが、Windows だと使えないっぽい。

Strawberry Perl も ActivePerl も v5.5.3 のバイナリなんて置いてないしなー。
などとググってるうちに発見した Vector の Perl for Win32(perl5) は v5.5.7 らしい。
置いてあるディレクトリが win95 !!
これを入れる勇気はちょっとないなと。

いっそのこと、サーバー借りちゃった方が楽かもね。


参考リンク

History / Changes - perldoc.perl.org
コアドキュメント - perldoc.jp
Perl Hackers Hub:第14回 最新Perl使いこなし術―リファレンスの引き方,5.10以降の新機能(2)
Perl Hackers Hub:第14回 最新Perl使いこなし術―リファレンスの引き方,5.10以降の新機能(3)
perl5.10から5.16の新機能まとめ

CGI::Carp - search.cpan.org
[Perl] KCatch.pm/CGI エラーメッセージをブラウザに表示
Jcode - search.cpan.org

perlbrew - search.cpan.org

Windows で複数の perl を使い分けよう! - JPerl Advent Calendar 2010 Win32 Track
Strawberry Perl for Windows
ActivePerl

2012-05-04

perl - Markdown変換スクリプト

ネタを整理するのに Markdown で書くと便利なのかなと調べていると
CPAN に Text::Markdown というモジュールがあったので
思いつきで変換スクリプト書いてみました。

スクリプトにファイル名を渡すか、__END__ 以下に Markdown を書いて使います。
出力を保存する場合はリダイレクトして下さい。

# markdown2html.pl

use strict;
use warnings;

use Text::Markdown 'markdown';

my $file = shift;
my $text = "";

if ($file) {
 open(my $fh, '<', $file) or die($!);
  local $/;
  $text = <$fh>;
 close $fh;
} else {
 local $/;
 $text = <DATA>;
}
my $html = markdown($text);

#print $text;
print $html;


__END__
#markdown sample
##h2
###h3

paragraph  
hoge
moge

[リンク文字列](http://example.com/)
[リンク文字列](http://example.com/ "タイトル")
<http://example.com>

![画像の説明](/path/to/image.jpg "タイトル")

- listA
- listB
- listC

---

1. listA
2. listB
3. listC

>blockquote
blockquote

    ...code...
`...code...`
ドラッグアンドドロップ用にバッチファイルも付けておきますね。
スクリプトと保存先のパスは適宜修正して下さい。
::markdown2html.bat

set markdown2html="C:\markdown2html.pl"
set output="C:\%~n1%.htm"

perl %markdown2html% %1 > %output%

pause

Markdown用のエディタとかもあるので、わざわざこんなの使うことないですよね。
個人的には秀丸から perl に渡して処理とかよくやるので、使うかなと思いまして。

参考リンク

Tomas Doran / Text-Markdown - search.cpan.org
Daring Fireball: Markdown
blog::2310 » Markdown文法の全訳
Markdown - Wikipedia

2012-05-02

Perl - リンク集

Perl

The Perl Programming Language
本家
The Comprehensive Perl Archive Network
CPAN
The CPAN Search Site - search.cpan.org
ActivePerl
Windows(32|64bit), MacOS, Linux(32|64bit)
Strawberry Perl
Windows(32|64bit)

Document

Perl programming documentation
perldoc
perldoc.jp
perldoc邦訳
Argrath's lair
pod日本語訳仮置き場
ちょいマシなCPAN機械翻訳

Framework | Library

Perlbrew
ユーザー環境下で複数バージョンの perl を管理
App-perlbrew - search.cpan.org
Catalyst
The Elegant MVC Web Application Framework
Catalyst - search.cpan.org
Moose
A postmodern object system for Perl 5
Moose - search.cpan.org
Moose 邦訳ドキュメント - perldoc.jp
PSGI/Plack
Perl Superglue for Web frameworks and Web Servers (PSGI toolkit)
Plack - search.cpan.org
Mojolicious
Real-time web framework
Mojolicious - search.cpan.org
Mojolicious リファレンス - サンプルコードによるPerl入門
ImageMagick
画像処理ライブラリ
PerlMagick, Perl API for ImageMagick
Image::Magick - search.cpan.org
ChartDirector for Perl
チャート描画ライブラリ
EPIC
Eclipse用 Perl IDE

News

Perl.com
O'Reillyのperlニュースサイト

Community

Perl Mongers
YAPC - Yet Another Perl Conference
Perl-users.jp - 日本のPerlユーザのためのハブサイト
PerlMonks

Learn

--- 基礎 ---
サンプルコードによるPerl入門
Perl基礎文法最速マスター - サンプルコードによるPerl入門
Perlオブジェクト基礎文法最速マスター - 燈明日記
Perl5編 - Programing Place
--- 基礎以上 ---
Perl-users.jp
JPerl Advent Calendar
JPerl Advent Calendar 2008
JPerl Advent Calendar 2009
JPerl Advent Calendar 2010
JPerl Advent Calendar 2011
JPerl Advent Calendar 2012
連載:モダンPerlの世界へようこそ|gihyo.jp
連載:Perl Hackers Hub|gihyo.jp
特集:Happy Testing Perl|gihyo.jp
--- 日本語処理 ---
Encode.pm - search.cpan.org
404 Blog Not Found:perl - Encode 入門
404 Blog Not Found:perl - Encode 中級
404 Blog Not Found:perl - use encoding; #は黒歴史
404 Blog Not Found:perl - EncodeでXSSを防ぐ
404 Blog Not Found:perl - use CGI; use Encode; # 非英語Webプログラミング3原則
404 Blog Not Found:perl - 最速のUTF-8処理法
Encodeでラクラク日本語処理 - JPerl Advent Calendar 2009
続・Encodeでラクラク日本語処理 - JPerl Advent Calendar 2010 Casual Track
モダンPerlの世界へようこそ:第32回 Encode:日本語だけ扱えればよいのではなく|gihyo.jp
--- その他 ---
Perl道場
PerlエンジニアがつくるPerlエンジニアのための検定試験

Books

--- O'Reilly's CD bookshelf ---
[eng]Perl in a Nutshell 第2版 - 2002
[eng]Learning Perl 第3版 - 2001
[eng]Learning Perl Objects, References and Modules - 2003
[eng]Programming Perl 第3版 - 2000
[eng]Advanced Perl Programming - 1997
[eng]Perl Cookbook - 1998
日本語インデックス
[eng]Perl Cookbook 第2版 - 2003
[eng]Mastering Regular Expressions 第2版 - 2002
[eng]Perl & LWP - 2002
[eng]CGI Programming with Perl 第2版 - 2000
[eng]Perl & XML - 2002
[eng]Mastering Perl/Tk - 2002
[eng]Learning Perl on Win32 Systems - 1997
[eng]Perl for System Administration - 2000
--- Google Books ---
Google Books Downloader for Windows and Mac OS X
 
[eng]Learning Perl 第6版 - 2011
初めてのPerl 第3版 - 2003
[eng]Intermediate Perl 第2版 - 2012
続初めてのPerl 改訂版 - 2006
[eng]Mastering Perl - 2007
[eng]Learning Perl Objects, References, and Modules - 2003
[eng]Programming Perl 第4版 - 2012
プログラミングPerl VOLUME 1 第3版 - 2002
プログラミングPerl VOLUME 2 第3版 - 2002
Perlクックブック VOLUME 1 第2版 - 2004
Perlクックブック VOLUME 2 第2版 - 2004
実用Perlプログラミング 第2版 - 2006
ミニマルPerl: Unix/LinuxユーザのためのPerl習得法 - 2008
Perlベストプラクティス - 2006
詳説正規表現 第2版 - 2003
正規表現デスクトップリファレンス - 2004
[eng]Regular Expressions Cookbook - 2009
[eng]Perl Debugger Pocket Reference - 2004
[eng]Perl & Lwp - 2002
[eng]Spidering Hacks: 100 Industrial-Strength Tips & Tools - 2003
CGIプログラミング 第2版 - 2001
入門Perl DBI - 2001
初めてのPerl Win32システム -1998
Perl & XML -2002
[eng]Perl Graphics Programming - 2002
Perl/GNUソフトウェアによるWebグラフィックスプログラミング - 2000
[eng]Web Security Testing Cookbook - 2008
[eng]Perl Hacks: Tips & Tools for Programming, Debugging, and Surviving - 2006
モダンPerl入門: 実務で使う実用的なPerlの"すべて" - 2009
PerlフレームワークCatalyst完全入門 - 2010

2012-04-04

Perl - WindowsでPerl

ワンライナー

ネットで見つけたワンライナーをコマンドプロンプトで使おうとすると
perl -e 'print "Hello, World!"'
Can't find string terminator "'" anywhere before EOF at -e line 1.
こんな感じでエラーが出て使えません。

引数はダブルクォートで囲わないとダメなので少し変更しないといけません。
# 内側のダブルクォートをエスケープする
perl -e "print \"Hello, World!\""

# qq 演算子を使う
perl -e "print qq{Hello, World!}"

# 内側のダブルクォートをシングルクォートに置き換える
perl -e "print 'Hello, World!'"

# q 演算子を使う
perl -e "print q{Hello, World!}"


perlへのショートカット

こんな感じでショートカットを作っておくと
ファイルをドラッグアンドドロップで実行できます。



バッチファイルでもできるのでお好きな方をどうぞ。
@echo off
cd /d "%~dp0"
cmd /k perl %1


UTF8を出力

現在では UTF8 でコードを書くのが主流ですが、
コマンドプロンプトの文字コードは CP932 なので
UTF8 で出力すると当然、文字化けします。

これは binmode で文字コードを CP932 にすれば大丈夫。
use strict;
use warnings;
use utf8;
binmode STDOUT => ':encoding(cp932)';

print "寿限無寿限無";
出力を UTF8 のまま得たい場合はテキストファイルに出力します。
use strict;
use warnings;
use utf8;
binmode STDOUT => ':utf8';

print "寿限無寿限無";
perl "C:\utf8.pl" > "C:\utf8.txt"
コマンドプロンプトの文字コードを UTF8 にする方法は
うまくいかない場合があるので、テキストファイルに出力した方が確実です。


秀丸でperl

秀丸マクロを覚えるのが面倒というあなたへ。
ちょこっと整形、置換、抽出したいときは 「その他 > プログラム実行」から perl が使えます。



ただ、これだと UTF8 でコードを書いた場合、shift-jis に変換されるのでうまくいきません。
この場合、下のように設定してください。
「Unicodeで標準入出力」は UTF-16 なのでチェックしません。



これは perl にファイル名を渡して cp932 で出力を受け取ります。
なのでファイルとして保存してから実行してください。
# サンプル
use strict;
use warnings;
use utf8;

binmode STDOUT => ':encoding(cp932)';
binmode STDERR => ':encoding(cp932)';

for my $line (<DATA>){
    chomp $line;
    print "僕と契約してよ、$line。\n";
}

__END__
うろぶち
きょうこ
まみ
まどか
さやか
ほむら
__END__ 以下は <DATA> で読み出せるので処理したいデータを貼り付けて
for なり while で回してゴニョゴニョします。

ちょろっとテキストを処理したいときなんか便利じゃないでしょうか。

2012-04-03

Perl - PACKAGEはブロックスコープじゃない

あまり使わないかもしれませんが、1つのファイルに複数の PACKAGE を書く場合注意が必要かなと。
use strict;
use warnings;

package FOO;
my $hoge = "madoka";

package BAR;
my $moge = "homura";

package BAZ;
print "\$FOO::hoge : $FOO::hoge \n";
print "\$hoge      : $hoge \n";
print "\$BAR::moge : $BAR::moge \n";
print "\$moge      : $moge \n";

------------------
実行結果
$FOO::hoge :        # エラー
$hoge      : madoka # 期待と違ってエラーじゃない
$BAR::moge :        # エラー
$moge      : homura # 期待と違ってエラーじゃない

Name "BAR::moge" used only once: possible typo at - line 12.
Name "FOO::hoge" used only once: possible typo at - line 10.
この場合 $hoge も $moge もレキシカル変数なので
外から見えないことを期待しましたが、なぜか見えます。

では、次の場合はどうでしょう?
use strict;
use warnings;

package FOO;
my $hoge = "madoka";

package BAR;
my $moge = "homura";

package BAZ;
my $hoge = "mami";
my $moge = "sayaka";

------------------
実行結果
"my" variable $hoge masks earlier declaration in same scope at - line 11.
"my" variable $moge masks earlier declaration in same scope at - line 12.
「$hoge も $moge も同じスコープで既に使われてるよ」と怒られます。
PACKAGE が違ってもレキシカル変数は同じスコープみたいです。

これはこれで不便なので期待通りに動かすには次のようにします。
package FOO;
{
    my $hoge = "madoka";
}
もしくは
{
    package FOO;
    my $hoge = "madoka";
}
このように明示的にブロックで囲みます。
これを踏まえて書き直すと
use strict;
use warnings;

package FOO;
{
    my $hoge = "madoka";
    print "\$hoge : $hoge \n\n";
}
package BAR;
{
    my $moge = "homura";
    print "\$moge : $moge \n\n";
}
package BAZ;
{
    my $hoge = "mami";
    my $moge = "sayaka";

    print "\$hoge : $hoge \n";
    print "\$moge : $moge \n";
}

------------------
実行結果
$hoge : madoka 

$moge : homura 

$hoge : mami 
$moge : sayaka 
めでたし、めでたし。


- 追記 -
perlのドキュメントに書いてありました。
perlmod - Perl のモジュール (パッケージとシンボルテーブル) 【perldoc.jp】

パッケージ文は(local() を使った)動的変数にのみ効果を持ちますが、
my() によって生成されたレキシカル変数には影響しません。

2010-03-31

SleipnirでPerlを使う。

下準備

ActivePerl をインストール。

厳密には Perl じゃなくて PerlScript を使います。
ドキュメントは %perl%/html/Windows/WindowsScriptHost.html


Sleipnirスクリプト(WSH) で PerlScript を使う

%Sleipnir%/scripts/ に入れて使う方法。

標準では .pls に関連付けられているので
作ったものを hoge.pls など適当に名前をつけて保存。

%Sleipnir%/scripts/ に入れる。
メニューバー → スクリプト から実行。


.pls がプレイリストとバッティングしてる場合は
どう関連付けを変更すればいいのかわかりませんが

のような書き方で hoge.wsf として保存すれば実行できます。


UserActionスクリプト で PerlScript を使う

%Sleipnir%/plugins/scripts/ に入れて使う方法。

%Sleipnir%/resources/languages/default/english/ScriptEngine.ini
に追記することで対応言語を増やせるので
[StringTable]
js=JScript
vbs=VBScript
となっているのを
[StringTable]
js=JScript
vbs=VBScript
pl=PerlScript
と変更。

あとは作ったものを hoge.pl など適当に名前をつけて保存。
%Sleipnir%/plugins/scripts/
に入れればActionとして使えます。

もちろん Perl のモジュールも使い放題。
公式?の Sleipnir.pm というのもありますよ。

- 参考記事 -
UserAction Extension でオレオレスクリプトのススメ (1) (フェンリル | デベロッパーズブログ)
UserAction Extension でオレオレスクリプトのススメ (2) (フェンリル | デベロッパーズブログ)
UserAction Extension でオレオレスクリプトのススメ (3) (フェンリル | デベロッパーズブログ)
UserAction Extension でオレオレスクリプトのススメ (4) - そして伝説へ - (フェンリル | デベロッパーズブログ)
その後の「UserAction Extension でオレオレスクリプト」 (フェンリル | デベロッパーズブログ)

日本語使うとエラー出たりする

PerlScript で日本語が含まれると読み込まれるbyte数が短くなる。

PerlScript - miau's blog?
ActivePerlのPerlScriptで日本語
Bug 40776 – 2-byte character problem with PerlScript

これはうちの環境、winXP SP3、Sleipnir2.9.3、ActivePerl v5.10.1でも発生。
use strict;
use warnings;
use Win32::OLE;

my $pnir     = Win32::OLE->CreateObject("Sleipnir.API");
my $id       = $pnir->GetDocumentID($pnir->ActiveIndex);
my $window   = $pnir->GetWindowObject($id);
my $document = $pnir->GetDocumentObject($id);

if(!$document) {
 $pnir->Beep();
 $pnir->MessageBox("エラー:Documentオブジェクトが作成できませんでした");
} else {
 $pnir->Beep();
 $pnir->MessageBox("寿限無寿限無五劫の擦り切れ海砂利水魚の水行末雲来末風来末食う寝る処に住む処やぶら小路の藪柑子パイポパイポパイポのシューリンガンシューリンガンのグーリンダイグーリンダイのポンポコピーのポンポコナーの長久命の長助");
}

__END__ 
原因は内部処理で文字数とbyte数がごっちゃになってるせいらしい。
UTF8で書いても回避できません。

ずいぶんとほったらかしのバグですが、いまだに "Status: UNCONFIRMED" ってなんで?


解決するには
 1. 日本語を使わない。
 2. ファイル全体の文字数 > スクリプト部分のバイト数 になるようにスペース等を入れて調節する。
 3. require や use で動的・静的コンパイルする。
のどれかのようです。


では、動的・静的コンパイルを試してみましょう。
Sleipnir のインストール先は C:/sleipnir293/ とします。

Sleipnirスクリプト(WSH)
C:/sleipnir293/
 └ scripts/
  ├ JugemuPLS.pls
  ├ JugemuPM.pm
  ├ call_JugemuPLS.pls
  └ call_JugemuPM.pls

# JugemuPL.pl, JugemuPLS.pls, JugemuPM.pm
use strict;
use warnings;
use Win32::OLE;

my $pnir     = Win32::OLE->CreateObject("Sleipnir.API");
my $id       = $pnir->GetDocumentID($pnir->ActiveIndex);
my $window   = $pnir->GetWindowObject($id);
my $document = $pnir->GetDocumentObject($id);

if(!$document) {
 $pnir->Beep();
 $pnir->MessageBox("エラー:Documentオブジェクトが作成できませんでした");
} else {
 $pnir->Beep();
 $pnir->MessageBox('寿限無寿限無五劫の擦り切れ海砂利水魚の水行末雲来末風来末食う寝る処に住む処やぶら小路の藪柑子パイポパイポパイポのシューリンガンシューリンガンのグーリンダイグーリンダイのポンポコピーのポンポコナーの長久命の長助');
}

1;
__END__
# call_JugemuPLS.pls
use lib qw(C:/sleipnir293/scripts);
require 'JugemuPLS.pls';
# call_JugemuPM.pls
use lib qw(C:/sleipnir293/scripts);
use JugemuPM;

call_JugemuPLS.pls, call_JugemuPM.pm をそれぞれ実行。
Shift-JIS以外だと文字化けしますが、エラーは出ません。


UserActionスクリプト
C:/sleipnir293/
 └ plugins/
  └ scripts/
   ├ JugemuPL.pl
   ├ JugemuPM.pm
   ├ call_JugemuPL.pl
   └ call_JugemuPM.pl

# call_JugemuPL.pl
use lib qw(C:/sleipnir293/plugins/scripts);
require 'JugemuPL.pl';
# call_JugemuPM.pl
use lib qw(C:/sleipnir293/plugins/scripts);
use JugemuPM;

call_JugemuPL.pl, call_JugemuPM.pl をそれぞれ実行。
これもエラーは出ません。


もう少し何とかする
実行ファイル と 呼び出すファイル の2つが必要とはいえ
日本語がエラーなしで使えるのはありがたい。

そこでもう少し環境を詰めてみる。

.pm はモジュールなのでモジュール以外には使わない。

呼び出すファイルが
 Sleipnirスクリプト(WSH) は .pls
 UserActionスクリプト は .pl
というのは管理が煩雑になるので .pls に統一する。

Sleipnir.pm もあることだし %perl%/site/lib/Sleipnir/ 以下にスクリプトを放り込んでおけば
Sleipnirスクリプト(WSH) でも UserActionスクリプト でも
use lib しなくていいので便利かなと。

C:/perl/
 └ site/
  └ lib/
   ├ Sleipnir/
   │ ├ UAS_hoge.pls
   │ └ WSH_hoge.pls
   └ Sleipnir.pm
実行環境の違いも考慮するならこうした方がいいのかな。
C:/perl/
 └ site/
  └ lib/
   ├ Sleipnir/
   │ ├ UAS/
   │ │ └ UAS_hoge.pls
   │ └ WSH/
   │  └ WSH_hoge.pls
   └ Sleipnir.pm
C:/sleipnir293/
 ├ scripts/
 │ └ call_WSH_hoge.pls
 └ plugins/
  └ scripts/
   └ call_UAS_hoge.pls
ディレクトリで分けるかどうかはお好みで。


ということで変更点は3つ。

1. ScriptEngine.ini を編集。
C:/sleipnir293/resources/languages/default/english/ScriptEngine.ini

[StringTable]
js=JScript
vbs=VBScript
pl=PerlScript
pls=PerlScript
に変更して UserActionスクリプト で *.pls を実行できるように。


2. 実行ファイルと Sleipnir.pm を設置。
C:/perl/
 └ site/
  └ lib/
   ├ Sleipnir/
   │ ├ UAS_hoge.pls
   │ └ WSH_hoge.pls
   └ Sleipnir.pm
# 実行ファイルのテンプレはこんな感じで。
# 日本語が使えます。

# 一応 package 使った方がいいかも。
package Sleipnir::hoge;

use strict;
use warnings;
use Sleipnir;

my $pnir     = Sleipnir->new;
my $id       = $pnir->id;
my $window   = $pnir->window($id);
my $document = $pnir->document($id);

if(!$document) {
 $pnir->Beep();
 $pnir->MessageBox("エラー:Documentオブジェクトが作成できませんでした");
} else {
 # code
}

# この 1 は必須です。
1;
__END__

3. 呼び出すファイル(*.pls)を設置して実行。
C:/sleipnir293/
 ├ scripts/
 │ └ call_WSH_hoge.pls
 └ plugins/
  └ scripts/
   └ call_UAS_hoge.pls
require 'Sleipnir/WSH_hoge.pls';
require 'Sleipnir/UAS_hoge.pls';

__END__
# 呼び出すファイルのテンプレはこんな感じで。
# 日本語でコメントを書く場合は __END__ 以下に書けます。


実際に動かしてみる
C:/perl/
 └ site/
  └ lib/
   ├ Sleipnir/
   │ └ Jugemu.pls
   └ Sleipnir.pm
C:/sleipnir293/
 ├ scripts/
 │ └ call_Jugemu.pls
 └ plugins/
  └ scripts/
   └ call_Jugemu.pls
# Jugemu.pls
package Sleipnir::Jugemu;

use strict;
use warnings;
use Sleipnir;

my $pnir     = Sleipnir->new;
my $id       = $pnir->id;
my $window   = $pnir->window($id);
my $document = $pnir->document($id);

if(!$document) {
 $pnir->Beep();
 $pnir->MessageBox("エラー:Documentオブジェクトが作成できませんでした");
} else {
 $pnir->Beep();
 $pnir->MessageBox('寿限無寿限無五劫の擦り切れ海砂利水魚の水行末雲来末風来末食う寝る処に住む処やぶら小路の藪柑子パイポパイポパイポのシューリンガンシューリンガンのグーリンダイグーリンダイのポンポコピーのポンポコナーの長久命の長助');
}

1;
__END__
# call_Jugemu.pls
require 'Sleipnir/Jugemu.pls';

__END__
これでもShift-JIS以外は文字化けするので
文字コードが問題になるのなら
UTF8で書いてShift-JISで出力すればOK。
# JugemuUTF8.pls
package Sleipnir::JugemuUTF8;

use utf8;
use strict;
use warnings;
use Encode qw/encode/;

use Sleipnir;

my $pnir     = Sleipnir->new;
my $id       = $pnir->id;
my $window   = $pnir->window($id);
my $document = $pnir->document($id);

if(!$document) {
 my $txt = 'エラー:Documentオブジェクトが作成できませんでした';
 $txt = encode('Shift_JIS', $txt);

 $pnir->Beep();
 $pnir->MessageBox($txt);
} else {
 my $txt = '寿限無寿限無五劫の擦り切れ海砂利水魚の水行末雲来末風来末食う寝る処に住む処やぶら小路の藪柑子パイポパイポパイポのシューリンガンシューリンガンのグーリンダイグーリンダイのポンポコピーのポンポコナーの長久命の長助';

 $txt = encode('Shift_JIS', $txt);

 main::MsgBox($txt);

 $window->alert($txt);

 $pnir->Beep();
 $pnir->MessageBox($txt);
}

1;
__END__

こんな感じでいかがでしょうか?
早くバグ修正してくれないかなー。


- 関連記事 -
Aragger: Sleipnirのスクリプトがわかりにくいので整理してみる。