2011/12/05

Visual C# 2010 Express Edition で「要求されたレジストリアクセスは許可されていません。」が出る



VC# 2010 Express Edition で新しいプロジェクトを作ろうとすると「要求されたレジストリアクセスは許可されていません。」が出る*1


ぐぐったら、やれ Windows Resource Kit を入れるだの、レジストリをいじるだの出てきたけど、効果なし。


仕方ないので、VC# 2008 Express Edition を入れてみると、こちらではOK。


念のため、もう一度 2010 でやってみると、なぜかうまくいった。2008 がなんかしてくれたようだ。


ま、2008 を使うつもりはないけど、入れたままでいいや。




*1:事例も少なそうだし、ひょっとして AVR Studio 5 の影響だろうか。





2011/12/03

MPC で iso を直接再生する wsh スクリプトを書いてみた



動画を見るときは Media Player Classic(MPC) を使ってる。でも MPC は ISOは直接再生できないので、ISO を見るときだけは仕方なく VLC を使っていたのだった。

でも VLC ってちょっと使いにくい。なので、MPC で iso を再生する wsh スクリプトを書いてみた*1



やってることは単純で WinCDEmu で DVD の ISO をマウントして MPC で再生するだけ。MPCを閉じたらアンマウント。


これを使って、ISO ファイルをダブルクリックして再生するための手順を書いておく。


なお、.vbs をファイルの関連付けすることはできないと思うので、MakeExe で .vbs → .exe に変換したものを .iso に関連付けするようにした。




  1. mpcをダウンロードしてインストール

  2. WinCDEmuをダウンロードしてインストール

  3. MakeExe をダウンロードして展開

  4. 上述の dvd_iso_play.vbs をどこかに保存

  5. dvd_iso_play.vbs の MOUNTER と PLAYER を書き換える

  6. MakeExe を展開したディレクトリに makewin.exe があるので、そこに dvd_iso_play.vbs をドラッグアンドドロップ

  7. dvd_iso_play.vbs と同じ場所に exe ができるので、これを iso ファイルに関連付ける
    Windows 7では スタート / 規定のプログラム / ファイルの種類またはプロトコルのプログラムへの関連付け


これで、.iso をダブルクリックすると mpc で再生できるはず。


にしても MakeExe 素晴らしい。作者に感謝。




*1:ハゲしく既出な気もするんだけど





2011/11/10

AVR Studio 5 で ATmega88P のプロジェクトがビルドできなくなる件。



こないだから AVR Studio 5 を使っている。ふとATMELのサイトに行くとアップデートがあったので、何の気なしに入れてみた。


AVR Studio 5 - AVR Software Framework Update(222 MB, revision 2.8.1, updated 10/11)


アップデートしたあと、いつものように作りかけのプロジェクトを開いてビルドしようとすると、




"device is not supported."



とか出てコンパイルできなくなった。あれ、さっきまで出来てたのに??


なんか、PORTB とか DDRB とかの名前が undefined だとか言われている。


注意してみると、どうやら選択中のデバイス mega88p が io.h の #if - #endif のデバイス個別ヘッダの選択肢にないのが原因のようだ。mega88 はあるんだけど、mega88p がない。デバイス設定を mega88 にするとコンパイルできるけど、書き込みやフューズとか考えたら気持ち悪いから mega88p で続けたいぞ。


しょうがないので、さっき入れたアップデートをアンインストールした。


でも相変わらずコンパイルできない。まいった。


まいったので、AVR Studio 5 や jungo ドライバの一式を全部アンインストールし、もう一度入れなおした。


これでやっと元通り、mega88p でコンパイルできるようになった。


内容も見ずにアップデートを入れるのはよろしくないなと思った。リリースノートによれば、今回のアップデートは XMEGA 対応だからスルーするべきだった。


mega48p、mega168p とかでも同じようになりそう。


それにしてもね。もうちょっと、ちゃんとやろうよ ATMEL…。





evernote クライアントアプリで同期が失敗した時の解決方法



何回ボタンを押しても同期に失敗する。


ぐぐってみると、書いてくれている人がいた。


http://saiut.posterous.com/evernote-0


キャッシュ?をクリアすればいいようだ。





2011/10/19

avr studio 5 のヘルプ



以前から欲しかった avr dragon を買ったので、avr studio 5*1を入れてみた。


avr studio 自体10年ぶりくらいなんだけど、今回のは visual studio をベースにしているだけあってスゴい事になってる。


でさっそく困ったことがひとつ。ヘルプを見ようとしても、



avrstudio The topic you requested could not be found in local help.



と表示されて見れない。ググってみるとすでに外人さんが解決されていた。さすがは avrfreaks の外人さん。


http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=880538


ヘルプは別途ダウンロードするそうな。


さらに visual studio のライセンス期限の関係でまずかった模様。


なので、一時的にwindows の日付を期限前に設定した後でヘルプファイルをダウンロードする。


要約すると、




  1. スタートメニュー / コントロールパネル / 日付と時刻

  2. 2011/10/10 より前の日付に設定(10/8とか)

  3. avr studio 5 / help / manage help settings とたどる

  4. install content from disk をクリック

  5. i want to use local help をチェック

  6. 下記を入れてNextをクリック


    • windows 64ビット C:\Program Files (x86)\Atmel\AVR Studio 5.0\help\helpcontentsetup.msha

    • windows 32ビット C:\Program Files\Atmel\AVR Studio 5.0\help\helpcontentsetup.msha



  7. avr studio help の add をクリック

  8. update ボタンをクリック

  9. セキュリティを聞いてくるので、許可する

  10. 日付を戻す*2


これでOKなはず。


ちなみに avr dragon の取説もローカルにインストールされ、下記で見れる。


http://127.0.0.1:47873/help/1-4388/ms.help?method=page&id=AVR_DRAGONUSERGUIDE&topicversion=0&topiclocale=EN-US&SQM=1&product=AVRStudio&productVersion=5&locale=EN-US




*1:ver. 5.0.1163


*2:ntpで自動時計合わせしている場合は 日付と時刻 / インターネット時刻 / 設定の変更 / 今すぐ更新 をやるだけでいい





2011/07/18

ふつうの電卓の税込キーを「×π」キーにしてみる



以前買った普通の電卓なんだけど、しょうもないことを思いついたのでやってみる。


この電卓には「税込」「税抜」キーが付いてるんだけど、まあ、個人的には一生押さないボタンだと思う。


これをなんとか活用したい。


たとえば、「×π」「÷π」キーにしてみてはどうか。これなら理工系な人でも結構有用なんじゃないだろうか。


税込キーは何をしているかというと、税率が 5% の場合



結果 = 今の値 × 1.05


という、実に単純な演算だ。


ポイントとしては、ここで税率はパーセントで設定してやる必要があるってことかな。


つまり税率に注目すると、上の式は



結果 = 今の値 × (1 + (税率/100) )


となる。

「税込」キーを「×π」キーにするには、上式の (1 + (税率/100) ) を 3.14 にすればいいので、税率として 214 を設定してやればいい*1

これで「税込」キーに「×π」機能をキーバインドすることができた*2


でもやっぱり関数電卓の、ただの「π」キーがあった方がいいな。




*1:当たり前だけど、これは税率が変えられるタイプの電卓でしかできない


*2:同時に、「税抜」キーには「÷π」機能が割りついている





2011/07/10

なにこれ?



google で検索結果の右に出た広告。


f:id:gnrr:20110711011749p:image


スペースキーの価格比較って(w


実にいい加減だ。





2011/06/25

光プロバイダ選びの真実



ADSL が不調なので*1、今更ながら光の導入をちょっとまじめに考えてみた。


いろいろ考えた結果、今回は nifty に決めた。何をどう考えたか、以下にメモを残す。


注意:以下はあくまで現在の僕の状況での考え方。もし参考にする場合はご自分のおかれた状況と見比べて自分の頭で考える必要あり。価格.com のキャンペーンが他より本当に安いのかも要検討。




まずは、現在の僕の状況を確認しておく。金額は概算。




  • 住んでるところ:賃貸アパート, 10戸/棟, 築10年くらい?

  • 固定電話の加入権:すでにあり

  • 今の月額通信費:5500円/月 = 3800円(YBB ADSL 12M) + 1700円(NTT 電話の基本料金)
    (加入してから1年以上経過)

これをなんとか今より安く、光にしたい。具体的には「コミコミ*2で 3000円/月 以下」を目指す。


まず、住んでいる場所で光収容の状態を確認する。アパートの管理会社にメールしたり、NTTやeo光のサイトで住所や電話番号を入れて確認する。僕の場合はNTTとeo光の2つが対応していた。その他の対応はなし。




  • 光収容状態(NTT):フレッツ 光ネクスト マンションミニ・ハイスピードタイプ

  • 光収容状態(eo光):eo光ネット メゾンタイプ

なんとかタイプ*3とか、よくわからん長い名前が並んでて、いろいろ選択肢がありそうだ。しかし、光収容状態(つまりは住んでる場所)によって、すでに月額料金はあらかた決まってしまっている。NTTとeo光のサイトで確認すると、下のような料金が書かれていた。




  • NTT:「フレッツ 光ネクスト マンションミニ・ハイスピードタイプ」は 3700円/月

  • eo光:「eo光ネット メゾンタイプ」は 4,900円/月


この値段は純粋な回線使用料を示していて、光モデムの月額レンタル料は含まれていない。光モデムの月額レンタル料は NTTは945円、eo光は420円。NTTの場合はさらにプロバイダ料金(1000円ほど)も含まれていない。これを整理すると、




  • NTT: 3700 + 945 + 1000 = 5645円/月

  • eo光: 4900 + 420 = 5320円/月


となる*4

300円ほどの差額があるがあえて無視して、僕の通信費は 5700円/月だと考える*5。この料金は固定と思ったほうがいい。つまり安くはできない。毎月口座から差っぴかれる金額だ。どこに申し込もうが変わらない。


とりあえず上記を整理した上で kakaku.comを見てみる。なんか大出血的に非現実的な金額が列挙されているが踊らされてはならない。見るべきところはそこじゃない。


たとえばココとかを例に挙げる。


いろんなプロバイダがあって、すべて自分の選択肢と思ってしまうが、実際には住んでいる場所によっては選べないプロバイダもある。いくら安くても提供エリアに住んでいないとそのプロバイダは選べない。たとえば、僕の場合は NTT と eo光 の2つしか対応していないので、spaaqs は選択できない。これは spaaqs のサイトで電話番号を入れると分かる。めんどくさいが。


選べないプロバイダもあるんだと認識したら、ざっと一覧を見てみる。

まず「実質費用」てのが目を引く。やたらと目立つ赤い数字だ。しかし、この大出血価格はまったく検討材料にならない。なぜか。これは単なるモデル価格だからだ。パリコレでモデルが着てる服は、たぶん近所のおばちゃんのほとんどが着ることができない。それと同じだ。内訳を注意深く見ると分かる。月額費用が4300円なんて書かれていても、今の僕の光収容状態ではそんな安いプランは選べない。僕はどうあがいても5700円/月だ。というわけで無視だ*6


次に目が行くのが「月額費用」だ。説明を読むとマトモそうなことが書いてあって、これこそ検討材料にすべきと思わせるが、残念ながらこれも見るところではない。結局これもモデル価格だからだ。よって無視。

じゃあどこを見るのか。まずはキャッシュバック。「価格.com経由限定キャンペーン」欄の「現金30,000円バック」とか書かれているところだ。これが大きいのをまず見る*7。たとえば、僕の場合 5700円を2年払うと、13万7千円/2年だ。でもキャッシュバックが3万円だと、10万7円/2年になる。月額では 10万7千円/2年 → 4600円/月となる。キャッシュバックが4万円だと (13.7 - 4) / 24 ≒ 4000円/月。なぜ 2年で考えるかというと、違約金があるから。NTTでもeo光でも2年以内に解約すると違約金が発生し1~2万ほど徴収される。なので2年以上使わないとせっかくのキャッシュバックが意味がなくなる。これはたとえば、プロバイダの継続利用依頼月数がたとえ1年だったとしても同じだ。1年でプロバイダを乗り換えることはできても、そのとき同時に光回線を解約すると違約金が発生する。マメな人はプロバイダの無料期間と継続利用依頼月数を毎月チェックして転々と渡り歩けるだろうが、マメでない僕なら2年間はそのプロバイダと回線に固定されると考える。ここを見て、キャッシュバックがないプロバイダを選択肢から外す。


次にプロバイダの無料期間を見る。これが6ヶ月とかだと、(1000円 * 6) / 2年 = 250円/月で利いてくる。これを小さいと思うかどうか。キャッシュバックが3万円と4万円のときの月額を思い出す。その差額600円/月だ。そう考えると、無料期間も結構な効き方だと思える。でも無料期間が 2ヶ月だとたったの 83円/月にしかならない。ここを見て、無料期間がなかったり 3ヶ月以下だったら、そのプロバイダを選択肢から外す。


「安くできる」かどうかは、上の2つ(キャッシュバックとプロバイダの無料期間)で決まると思っていい。ただしキャッシュバックは、それを受け取れるかどうかがカギとなる。キャッシュバックの受け取り方はプロバイダによって細かく違うが、大体下記のようなものだと考えておくのがいい。キャッシュバックとはなにか。




  1. 申し込んでも、すぐには受け取れない
    たとえば、「開通後12ヶ月後」とか平気で書いてある。

  2. 自動的に振り込んでくれるわけじゃない
    契約した時にプロバイダから与えられるメールアドレスに、キャッシュバック手続きの知らせが送られてきて、それに期限内に答えないと振り込んでもらえない。

どちらも厄介だ。つまり、キャッシュバックを受け取れるかどうかは、1年後の自分に懸かっているというわけだ。そんな先の自分の行動なんて信用できないという人は、「光回線どうですか~」とたまに自宅を訪ねて来る業者さんを素直に受け入れる方がいいと思う*8。大幅に安くはできないが、申し込んだだけで自動的に Wii とか 1万~2万の商品券がもらえるし、その場で契約すれば手続きに時間がかからないから時間的にもお得だ。2万円の商品券がもらえたとすると、( 5700 * 24 ) - 2万 / 24 = 4900円/月くらいになる。でも 3000円/月以下を目指すなら、あえてキャッシュバックのリスクを負うことを覚悟する。


結局どこを見るのか。「プラン名」をクリックした先に表示されるページの「期間限定キャンペーンについて」の「合計69,358円割引」とか書かれているやつだ。この金額は、上でごちゃごちゃ書いていることをすべて含んでいる。この例(nifty)でいくと、僕の場合は




  • 2年間をばか正直に払った場合:5700円/月

  • プランを適用した場合:((5700 * 24) - 69358) / 24 = 2818円/月


となって、目標の3000円/月をクリアできる。


eo光の場合は 5700円/月ではなくて 5300円/月だけど、計算してみると




  • eo光のプランの場合: ((5300 * 24) - 33320) / 24 = 3912円/月


となってクリアできないことが分かる。


こうやって一番安いところを見つければいい。



上記の結果、今回は nifty を選んだ*9


キャッシュバックは、額が大きいので受け取りをミスるだけで、計画が水の泡になる。


リスクを減らすために、下記のようなことをしておく。



  • キャッシュバック手続きの知らせを受け取るために、プロバイダのメールアドレスを普段使いの GMail に転送しておく*10 *11

  • Evernote の TODO で 12ヶ月後くらいの日付に、「そろそろ、 キャッシュバック手続きが届くぞ」と入れておく


以上。あんまり他の人の役に立つとは思えないけど、考え方の一例として残しておく。




*1:ADSLモデムの調子が悪いのか、3時間で5回ほどリレーがカチカチ言って接続が切れてしまう。ADSLモデムを3回ほど交換してもらったが現象変わらず。もううんざりだ。


*2:ここでのコミコミは プロバイダ料 + 接続料を指す。光電話、セキュリティ、その他の一切のオプションは含まない。固定電話は休止する。要するにつながってれば、それでいいんだ。


*3:まあ、マンションタイプと呼ばれているやつだが、その中でも戸数が少ないところ向けので、大型マンションのと比較すると700円/月ほど高いやつだ。一戸建てと比較すると300円ほどは安い。


*4:eo光のほうが300円ほど安くなるが、現時点でeo光の回線を使っているサードパーティのプロバイダはないので、プロバイダの無料期間やキャッシュバックの金額はeo光のキャンペーンに固定されてしまう。結果、それほど安くはならない。


*5:現状のADSLより200円ほど高くなるから、ちょっとビビるが今は気にしない


*6:まあこういう広告的な金額は、客の都合なんて考えずに一番安いプラン(タイプ2とか)を表示するのが、商売人的には普通だ。


*7:プロバイダによっては、現金じゃなくて「なんとかポイント」で支払われるとかあるけど、それが自分にとって価値がない場合は、たとえキャッシュバック額が大きくても意味がないので選択肢から外す。


*8:彼らはしばしば胡散臭がられて、冷たくあしらわれることが多いと思うけど、提示する商品券の額によってはもっと好意的に受け入れられるべきだと思う。だって普通にADSLを払っているより安くなる方法をアドバイスしてくれてるんだから。何も分かっていない愚かなヤツに限って、人に冷たい。悲しいけど良くあることだ。


*9:なぜ、nifty より割引額が大きい Toppa! を選ばなかったのか。パソ通時代に nifty serve に入りたくても月額料金が高くて入れなかった、そういうチンケでノスタルジックなバイアスがかかったんだろうな。


*10https://mail.google.com/support/bin/answer.py?ctx=gmail&hl=ja&answer=21288


*11:ただし、[アカウントとインポート]っていうのは、簡易HTML形式では表示されないので注意。これを表示するには標準HTML形式で表示する必要あり





2011/06/23

ふつうの電卓で逆数とか



しばらく前に、電験3種用にふつうの電卓を買った。



カシオジャスト型電卓 JF-120GT-N

カシオジャスト型電卓 JF-120GT-N







ふだん関数電卓しか使わない者にとっては不便極まりない。関数電卓なら1キーで済むところを沢山押さなければいけない。たとえば・・・









ふつうの電卓関数電卓
メモリ登録  MC M+  →Mキー 
5の2乗とか  5 × × =  x^2キー 
5の逆数とか  5 ÷ ÷ = =  1/xキー 

なんちゅうキーバインドか。emacs なんてかわいいと思える。特にメモリキーは、M+とかM-とか要らんから普通のメモリ登録キーがほしい。M+の何が便利なのか事務系の人にでも聞いてみたい。


この型番自体にも少し難があって、


省電力モードに入る直前に、0.5秒ほど「CASIO」って表示が出る

というわけの分からん仕様だ。頭がおかしいとしか思えん*1


かといって、ルート(1/2乗)があって、MC と MR が別々で、12桁の普通の電卓って他にはあんまり無いんだなあ。


まあ、GTは何気に便利だし、ルートが使えるだけマシって思っておこうか。




*1:可能ならROMを書き換えて、CASIOを表示する前にジャンプ命令を入れたい





2011/06/10

クラウドの public フォルダ



クラウドの public フォルダへのリンクを貼っておく。

外からログインなしで使えるように。



あと、diigo もあったか。ま、あとで追加しとこう。



2011/05/18

VC++ で Boost を使ったプログラムを static link でビルドする



Boost に限らず、静的リンクした exe を作るには、


VC++ メニュー / プロジェクト / 構成プロパティ / コード生成


ランタイムライブラリ を マルチスレッド (/MT) にする。


配布前の Release ビルド だけで設定しとくのが吉。





2011/05/15

クロージャ



いままで、「ふーん」くらいにしか思ってなかったけど、すごく分かりやすい解説を見つけたのでメモる。


猿でもわかるクロージャ超入門


xyzzy でやってみる。



;; 問題:呼び出すたびに、1,2,3,...を返すような関数 f( )を定義せよ。
(defun outer ()
(let ((x 0))
(defun inner ()
(incf x))))

(setq f (outer))

;; test
(funcall f)
;=>1

(funcall f)
;=>2

(funcall f)
;=>3


クロージャ、「使える!」と思った。





仮置き: cl 用の小物(作りかけ)



適当に作った clozure CL 用の cl-mode と、その native-compile 用のコマンド。

scheme-mode をパクらせていただいた。

念のために、作りかけを置いとく。プロセス周りがかなり怪しい。



cl-mode.l

;;; -*- Mode: Lisp; Package: EDITOR -*-
;;;
;;;
; cl-mode
; based on scheme-mode (wrote by MATSUOKA Hiroshi)
;
(require "lispmode")
(provide "cl-mode")

(in-package "editor")
(export '(*cl-mode-hook*
*cl-keyword-file*
*cl-mode-map*
*cl-indent-map*
cl-mode
*cl-run-command*
*cl-run-pop-to-args*
make-cl-scratch
*cl-mode-scratch-buffer*
*cl-process*
*cl-process-open-hook*
*cl-process-close-hook*
*cl-process-send-filter*
*cl-process-read-filter*
*cl-view-mode-map*
*cl-mode-version*
cl-view-mode))

(defvar *cl-mode-version* "based-scheme-mode-20090118")
;;; cl-mode
(defvar *cl-mode-map* nil)
(unless *cl-mode-map*
(setq *cl-mode-map* (make-sparse-keymap))
(define-key *cl-mode-map* #\RET 'lisp-newline-and-indent)
(define-key *cl-mode-map* #\LFD #'(lambda () (interactive) (cl-eval-last-sexp) (newline)))
(define-key *cl-mode-map* '(#\C-c #\C-e) 'cl-eval-current-buffer)
(define-key *cl-mode-map* #\TAB 'lisp-indent-line)
)

(defvar *cl-process* nil)
(defvar *cl-process-open-hook* 'cl-default-open-hook)
(defvar *cl-process-close-hook* nil)
(defvar *cl-process-send-filter* 'cl-default-send-filter)
(defvar *cl-process-read-filter* 'cl-default-read-filter)

(defvar *cl-run-command* nil)
(defvar *cl-run-pop-to-args* nil)
(defvar *cl-keyword-hash-table* nil)
(defvar *cl-keyword-file* "cl")
(defvar *cl-mode-scratch-buffer* "*cl scratch*")

(defun cl-default-send-filter (proc sexp)
(format nil "~A\r\n" sexp))

(defun cl-default-read-filter (proc text)
(when *cl-run-pop-to-args*
(unless (find-buffer (car *cl-run-pop-to-args*))
(save-excursion
(switch-to-buffer (car *cl-run-pop-to-args*))
(setup-temp-buffer (selected-buffer))))
(apply 'pop-to-buffer *cl-run-pop-to-args*))
(insert text)
(set-window (get-buffer-window (process-buffer proc)))
(refresh-screen))

(defun cl-default-open-hook (buffer)
(set-buffer buffer)
(make-process *cl-run-command*))

(defun cl-open-process ()
(interactive)
(when (null *cl-process*)
(let* ((process (funcall *cl-process-open-hook* (selected-buffer))))
(setf *cl-process* process)
(when *cl-process*
(set-process-sentinel
*cl-process*
#'(lambda (proc)
(when *cl-process-close-hook*
(funcall *cl-process-close-hook* proc))
(setf *cl-process* nil)))
(set-process-filter *cl-process* *cl-process-read-filter*))))
*cl-process*)

(defun cl-eval-string (sexp)
(when sexp
(let ((process (cl-open-process)))
(when process
(process-send-string process (funcall *cl-process-send-filter* process sexp))))))

(defun cl-eval-current-buffer ()
(interactive)
(let* ((text (buffer-substring (point-min) (point-max))))
(when (and text (> (length text) 0))
(cl-eval-string text))))

(defun cl-eval-last-sexp()
(interactive)
(save-excursion
(let* ((p (point))
(s (progn (backward-sexp) (point)))
(e (progn (forward-sexp) (point)))
(text (buffer-substring s e)))
(goto-char p)
(when (and text (> (length text) 0))
(cl-eval-string text)))))

(defvar *cl-mode-abbrev-table* nil)
(unless *cl-mode-abbrev-table*
(define-abbrev-table '*cl-mode-abbrev-table*))

; completion
(defvar *cl-completion-list* nil)
(defun cl-completion ()
(interactive)
(or *cl-completion-list*
(setq *cl-completion-list*
(make-list-from-keyword-table *cl-keyword-hash-table*))
(return-from cl-completion nil))
(let ((opoint (point)))
(when (skip-syntax-spec-backward "w_")
(let ((from (point)))
(goto-char opoint)
(do-completion from opoint :list *cl-completion-list*)))))

(defvar *cl-mode-hook* nil)
(defun cl-mode ()
(interactive)
(kill-all-local-variables)
(setq mode-name "CL")
(setq buffer-mode 'cl-mode)
(use-keymap *cl-mode-map*)
(use-syntax-table *lisp-mode-syntax-table*)
(and *cl-keyword-file*
(null *cl-keyword-hash-table*)
(setq *cl-keyword-hash-table*
(load-keyword-file *cl-keyword-file* t)))
(when *cl-keyword-hash-table*
(make-local-variable 'keyword-hash-table)
(setq keyword-hash-table *cl-keyword-hash-table*))
(when *cl-mode-abbrev-table*
(setq *local-abbrev-table* *cl-mode-abbrev-table*))
(run-hooks '*cl-mode-hook*))

(defun make-cl-scratch ()
(interactive)
(switch-to-buffer *cl-mode-scratch-buffer*)
(cl-mode)
(make-local-variable 'need-not-save)
(setf need-not-save t)
(make-local-variable 'auto-save)
(setf auto-save nil))

;;; cl-mode.l ends here


cl-native-compile.l

;;; cl-native-compile.l
;;;

(require "cl-mode")

(provide "cl-native-compile")


(defvar *cl-native-compile-template* (merge-pathnames "etc/cl-compile-template-ccl" (si:system-root))
"コンパイルスクリプトを生成するテンプレートファイルを指定")

(defvar *cl-native-compile-script-name* "compile-ccl.lisp"
"コンパイルスクリプトのファイル名")

(defvar *cl-native-compile-top-level-func-name* nil
"トップレベル関数の名前を文字列で指定する。
nil なら、ソースファイルの一番上の defun をトップレベル関数とみなす。")

(defun cl-native-compile ()
(interactive)
(let ((fn (get-buffer-file-name))
(ext "lisp"))
(if (interactive-p)
(cond (fn (when (and (buffer-modified-p)
(string= (pathname-type fn) ext))
(save-buffer))
(call-interactively 'cl-native-compile-1))
(t (call-interactively 'emacs-write-file)
(cl-native-compile-internal (get-buffer-file-name))))
(cl-native-compile-internal fn))))

(defun cl-native-compile-1 (filename)
(interactive "fNative compile file: " :default0 (get-buffer-file-name))
(cl-native-compile-internal filename))

(defun cl-native-compile-internal (filename)
(let ((script (cl-native-compile-create-compile-script filename)))
(when script
(cl-native-compile-kick-compile-command script))))

(defun cl-native-compile-kick-compile-command-dos (script)
"DOS窓を開いてコンパイルを実行する。"
(let* ((ccl (map-slash-to-backslash *cl-run-command*))
(script (pathname-name script))
(dir (directory-namestring script))
(cmd (format nil "cmd.exe /c ~A --no-init --load ~A" ccl script)))
(call-process cmd :exec-directory dir :show :show)
cmd))

(defun cl-native-compile-kick-compile-command (script)
"バッファを開いてコンパイルを実行する。"
(let* ((ccl (map-slash-to-backslash *cl-run-command*))
(script (pathname-name script))
(dir (directory-namestring script))
(cmd (format nil "~A --no-init --load ~A" ccl script))
(buf (get-buffer-create "*cl-native-compile*"))
(proc (progn (execute-subprocess cmd nil buf nil dir)
(buffer-process buf))))
(sleep-for 0.5)
(switch-to-buffer buf)
;(process-send-string proc (concat cmd "\n"))
;(insert "\n")
;(kill-process proc)
cmd))

(defun cl-native-compile-create-compile-script (lisp-path)
"native compile 用のスクリプトを生成しファイル名を返す。すでにある場合は生成せず、そのファイル名を返す。"
(let ((template *cl-native-compile-template*)
(script (merge-pathnames *cl-native-compile-script-name* (directory-namestring lisp-path)))
temp-buffer top-level ret)
(cond ((file-exist-p script) (setq ret script))
((null (file-exist-p lisp-path)) (error "ソースファイル ~A がありません。" src))
((null (file-exist-p template)) (error "テンプレートファイル ~A がありません。" template))
(t (unwind-protect
(progn
(setq temp-buffer (create-new-buffer "*cl-native-compile*"))
(set-buffer temp-buffer)
(insert-file-contents lisp-path)
(setq top-level (cl-native-compile-get-top-level-func))
(cond ((null top-level) (error "トップレベル関数が見つかりません。"))
(t
(progn
(erase-buffer temp-buffer)
(insert-file-contents template)
(cl-native-compile-replace-template lisp-path top-level)
(write-file script)
(setq ret script)))))
(when temp-buffer
(delete-buffer temp-buffer)))))
ret))

(defun cl-native-compile-replace-template (lisp-path top)
(let ((src (file-namestring lisp-path))
(exe (concat (pathname-name lisp-path) ".exe")))
(goto-char (point-min))
(replace-buffer "{TIME-STAMP}" (format-date-string "%Y.%#m.%#d  %H:%M:%S (%z)") :once t)
(goto-char (point-min))
(replace-buffer "{SRC-NAME}" src)
(goto-char (point-min))
(replace-buffer "{EXE-NAME}" exe)
(goto-char (point-min))
(replace-buffer "{TOP-LEVEL-FUNC}" top :once t)
(goto-char (point-min))))

(defun cl-native-compile-get-top-level-func ()
"ソースファイルからトップレベル関数を探して関数名を返す。
もし、*cl-native-compile-top-level-func-name* が non-nil なら探さずに、無条件にその値を返す。"
(cond (*cl-native-compile-top-level-func-name*)
(t
(let ((re "^ *( *defun +\\(.+\\) +"))
(if (scan-buffer re :regexp t)
(match-string 1)
nil)))))


clozure CL 用の設定

;;; cl-mode
(require "cl-mode")
(push '("\\.lisp$" . cl-mode) *auto-mode-alist*)

; インタプリタの起動コマンド (clozure CL)
(setf *cl-run-command*
(format nil "\"~A\""
(map-slash-to-backslash "D:/util/ccl/wx86cl.exe")))

; インデントを空白に
(add-hook '*cl-mode-hook*
#'(lambda ()
(ed::set-buffer-local 'indent-tabs-mode nil)))
; 評価結果を別窓にしたい場合
(setf *cl-run-pop-to-args* '("*cl run*" 2 nil))
(define-key *cl-mode-map* #\LFD #'(lambda () (interactive) (ed::cl-eval-last-sexp)))

(defalias 'cl 'make-cl-scratch)


xyzzy/etc/cl-compile-template-ccl(コンパイル用のテンプレートファイル)

;;; compile-ccl.lisp
;;;
;;; compile script for Clozure CL
;;; THIS FILE IS AUTOMATICALLY CREATED BY `cl-native-compile.l'.
;;;
;;;   created: {TIME-STAMP}
;;;   source:  {SRC-NAME}
;;;   out:     {EXE-NAME}

(load "./{SRC-NAME}")

(format t "now compiling...")

(ccl:save-application "{EXE-NAME}"

;;; compile-ccl.lisp ends here





2011/05/14

scratch バッファ専用の auto-save-buffers



scratch バッファでプログラムをテストしてると、まれに xyzzy がフリーズしてしまうことがある。フリーズすると、いままで scratch バッファで書いてたものがパーになるのでつらい。


そこで scratch バッファだけを RAM ディスクに自動保存するようにしてみた。


tips/xyzzyでファイルの自動保存をパクらせてもらった。



;;; auto-save-scratch-buffer
;;;
;;; *scratch* バッファ専用の auto-save-buffers
;;; 保存先は RAM disk を想定
;;;
;;; インストール (下の一行を .xyzzy に書く)
;;; (require "auto-save-scratch-buffer")

(provide "auto-save-scratch-buffer")
(in-package "editor")

(export '(auto-save-scratch-buffer
*auto-save-scratch-buffer-interval*
*auto-save-scratch-buffer-path*))

(defvar *auto-save-scratch-buffer-p* nil
"auto-save-scratch-buffer で保存中なら non-nil")

(defvar *auto-save-scratch-buffer-interval* 10
"自動保存するまでのアイドル時間")

(defvar *auto-save-scratch-buffer-path* "R:/scratch"
"自動保存するファイルの path")

(defun auto-save-scratch-buffer ()
"scratch バッファを自動セーブする"
(let ((buf (find-buffer "*scratch*")))
(when (and (eq (selected-buffer) buf)
(buffer-modified-p buf)
(check-valid-pathname (directory-namestring *auto-save-scratch-buffer-path*)))
(setf *auto-save-scratch-buffer-p* t)
(set-buffer buf)
(write-file *auto-save-scratch-buffer-path* t)
(set-buffer-modified-p nil buf)
(refresh-screen 0)
(message "saved scratch.")
(setf *auto-save-scratch-buffer-p* nil))))

(add-hook '*post-command-hook*
#'(lambda ()
(stop-timer 'auto-save-scratch-buffer)
(start-timer *auto-save-scratch-buffer-interval* 'auto-save-scratch-buffer t)))

;;; auto-save-scratch-buffer ends here


インストール




  1. 上記を auto-save-scratch-buffer.l として site-lisp に保存。byte-compile。

  2. .xyzzy に (require "auto-save-scratch-buffer") を足す。


デフォでは 10秒おきに保存。


そういえば、emacs でも同じようなのを書いたような・・・。





Git Bash の home ディレクトリを指定する



windows の git をふつうにインストールすると、$HOME が



/c/Documents and Settings/<windows のユーザ名>


となってて気持ち悪い。windows の環境変数で HOME を設定してないとこうなる。


システムのプロパティから環境変数を設定すればいいんだけど、めんどくさいので ショートカットで HOME を指定することにした。


Git Bash というショートカットアイコンがデスクトップにあるので、これのプロパティを開いて、リンク先と作業フォルダを設定する。


たとえば、マイドキュが D:\docu で、git のインストール先が d:\Git の場合は、下記のように変更。



リンク先:
C:\WINDOWS\system32\cmd.exe /c "set HOME=D:\docu & D:\Git\bin\sh.exe --login -i"

作業フォルダ:
D:\docu


これで、デスクトップの Git Bash アイコンから起動する限り、~は D:\docu を指すようになる。


でもしょせんは、 cmd.exe なんだよなあ。





ビルトイン関数かどうか



以前から探してて、あるにはあった。


ココによると、 si::*builtin-function-p だそうな。


ただ、ちょっと使いにくいので、ラップしとく。



(defun builtin-function-p (symbol)
"symbol がビルトイン関数かどうかを返す。"
(and (fboundp symbol)
(si::*builtin-function-p (symbol-function symbol))))





テンポラリなバッファを作る



他のアプリからテキストをコピペして置換とかするとき、一時的なバッファがほしくなるときがある。



(if (fboundp 'temp-buffer)
(msgbox "`temp-buffer' という関数はすでに存在します。")
(defun temp-buffer ()
(interactive)
(set-buffer (create-new-buffer "*temp*"))
(setq need-not-save t)
(setq auto-save nil)))


M-x temp-buffer で一時的なバッファを作れる。


小さいながら、よく使うコマンド。





※ temp-buffer というありがちな名前が、他の lisp 関数とガッチンコするとまずいので、一応チェックするようにした。





2011/05/13

フラグを反転する



フラグの反転くらい、さらっと書きたい。



(setq *hoge-state* (not *hoge-state*))


ってのを



(notf *hoge-state*)


ってやりたい。



(defmacro notf (var)
`(setq ,var (not ,var)))


名前が今ひとつナニだが。





2011/05/12

xyzzy で common lisp hyperspec を引いてみる (2)



ココに書いたやつの続き。


hyperspecのコマンドとしては、hyperspec と hyperspec-format がある。


でも ふつうに書いた .xyzzy ("user"パッケージ)からは見えなくて、hyperspec::hyperspec とかしないといけない。hyperspec.l を見る限り、ちゃんと export されているんだが、実に不思議。(←パッケージが分かってない)


というわけで M-x で呼ぶときは M-x hyperspec ではなくて、M-x hyperspec::hyperspec としなければならない。


まあ、見えないなら見えないで、同じ名前で新しくコマンドを作ってやった。



(defun hyperspec ()
"hyperspec をWWWブラウザで開く。ポイント位置が文字列なら、format文字を引く。"
(interactive)
(if (eq (parse-point-syntax) :string)
(call-interactively 'hyperspec::hyperspec-format)
(call-interactively 'hyperspec::hyperspec)))


これを M-x hyperspec として呼ぶと、




  • ポイントが文字列の時は hyperspec::hyperspec-format

  • そうでないときは hyperspec::hyperspec


となる。


hyperspec::hyperspec-format は format 関数で使う文字を調べるのに使える。


たとえば、



(format nil "~D個見つかりました。" count)


の、"D"にポイントを置いて M-x hyperspec とすると、Dが十進表示だということが分かる。


これは意外と便利。でもなんでか、"~%"は引けない。なんでか。





diigo に置いた画像をテスト



diigo に置いた画像をはてなダイアリーで表示できるかテスト。



どうかな?


一応いけた。・・・と思ったけど、少し時間をおいた後でリロードしてみると、表示されなくなった。


diigo の画像のリンクを見てみると、&Expires= というのがある。ということは、アクセス期限が設定されてるってことか。


というわけで、diigo を画像アップローダとしては使えないっぽい。


他を探そうか。





2011/05/11

xyzzy で common lisp hyperspec を引いてみる



common lisp のリファレンスとしては common lisp hyperspec が有名。


xyzzy から common lisp hyperspec を引けるようにしてくれた方がおられた。


http://lispuser.net/emacs/lisphacking.html#sec-4


以下使い方。


1 ココから hyperspec.l を落として、load-path の通ったところに置く。


2 ftp://ftp.lispworks.com/pub/software_tools/reference/HyperSpec-7-0.tar.gz から hyperspec の tar-ball を落として展開し、適当な場所に置く。


3 .xyzzy に下記を書く。



(require "hyperspec")
(setq hyperspec::*hyperspec-root* "~/cl/HyperSpec-7-0/HyperSpec/")
(defvar hyperspec::*hyperspec-symbols-alist* nil)
(defvar hyperspec::*hyperspec-format-characters-alist* nil)


C-c C-h で シンボルを入力すると、デフォルトのWWWブラウザが立ち上がり、リファレンスを参照できるようになる。


関係ないけど、google chrome では ftp できないことがあった。そんなときは ie でやる。





shell-mode で C-k したとき、サブプロセス を消す



これも、だいぶ前に書いたもの。


M-x shell でコマンドプロンプトに入って、作業後に C-k して "サブプロセスが走っています。" とか言われてムキッとなった人に。


けっこう重宝するので貼っておく。



(defun kill-process-and-buffer ()
(interactive)
(let* ((buf (selected-buffer))
(proc (buffer-process buf)))
(when proc
(kill-process proc)
(sleep-for 0.5))
(kill-buffer buf)))

(add-hook 'ed::*shell-mode-hook*
#'(lambda ()
(define-key ed::*shell-mode-map* #\C-\d 'kill-process-and-buffer) ; unix 風に C-d でも抜けるように
(define-key ed::*shell-mode-map* '(#\C-x #\k) 'kill-process-and-buffer)))


フック先を変えれば shell 以外でも使える。





2011/05/09

xyzzy で重複行を削除する



CSVファイルとか、XMLのタグ抽出したりとかで、何かと必要になることが多いのが重複行の削除。

xyzzy では C-x # uniq して、外部の uniq.exe を使うのがデフォの様子。

だけど、これぐらいの日常タスクなら xyzzy だけでやりたいと思ったから適当に書いといた。



  • 範囲はリージョンで指定する

  • 連続して重複していようが、ばらけていようが、2回以上の出現は重複とみなす

  • ならびは元のデータに合わせる

  • 大文字小文字区別 あり uniq-line-region

  • 大文字小文字区別 なし uniq-line-region-case-insensitive

下のようになる。

(元データ)   uniq-line-region    uniq-line-region-case-insensitive
----------   ----------------    ---------------------------------
AAA          AAA                 AAA
ccc          ccc                 ccc
CCC          CCC                 xxx
aaa          aaa                 BBB
AAA          xxx
aaa          BBB
xxx          bbb
BBB
bbb
ccc
aaa
bbb
aaa
aaa


(defun uniq-line-region (from to &optional case-insensitive)
"重複行を削除する。case-insensitive を省略するか nil の場合は、大文字小文字の区別をする。
non-nil のときは大文字小文字を区別しない。"
(interactive "*r")
(save-excursion (save-restriction
(narrow-to-region from to)
(goto-char (point-min))
(let (l)
(loop
(let ((s (buffer-substring (progn (goto-eol) (point)) (progn (goto-bol) (point)))))
(unless (member s l :test (if case-insensitive #'string-equal #'string=))
(setq l (cons s l)))
(unless (forward-line 1) (return))))
(delete-region from to)
(with-output-to-selected-buffer
(map nil #'(lambda (x) (format t "~A~%" x)) (nreverse l)))))))

(defun uniq-line-region-case-insensitive (from to)
"重複行を削除する。大文字小文字を区別しない。"
(interactive "*r")
(uniq-line-region from to t))


似たようなタスクとして、リージョンをソートしたいときは下記が参考になる。






2011/05/08

refer-for で定義元のソースにジャンプ



refer-for で、


[File ]: なんちゃら.l


の行で enter 押すとそのファイルを開いて、定義の箇所を見れるようにした。


今のところ、対応しているのは下記だけ。




  • 関数名

  • 変数名

  • マクロ名



(defvar *refer-for-jump-dir* `(,(merge-pathnames "lisp" (si:system-root))
,(merge-pathnames "site-lisp" (si:system-root)))
"reference の `File' の欄から *.l を検索するとき、検索対象のディレクトリを指定する。")

(defvar *refer-for-jump-file-read-only* t
"reference の `File' の欄から *.l を開くとき、read-only にするかどうかを指定する。
nil なら普通に開く。non-nil なら read-only で開く。")

(defvar refer-for-jump-file-alist
'(("Accessor" . 'ignore)
("BufferLocal" . 'ignore)
("Keyword" . 'ignore)
("Macro" . "^[ \t]*\([ \t]*defmacro[ \t]+XXNAMEXX[ \t]+\(") ; 改行も
("Misc" . 'ignore)
("Special Form" . 'ignore)
("Struct" . "^[ \t]*\([ \t]*defstruct[ \t]+\([ \t]*XXNAMEXX[ \t]+")
("Tips" . 'ignore)
("Variable" . "^[ \t]*\([ \t]*defvar[ \t]+XXNAMEXX[ \t]+")
("Function (interactive)" . "[ \t]*\([ \t]*defun[ \t]+XXNAMEXX[ \t]+")
("Function" . "[ \t]*\([ \t]*defun[ \t]+XXNAMEXX[ \t]+"))
"`Type'欄と、それをソースファイルから検索するときの正規表現テンプレートの alist。'ignore は「今のところ無視する」という印。")

(defvar refer-for-jump-content-alist '((type . "^\\[Type \\]: \\(.+\\)$")
(name . "^■\\(.+\\)$"))
"*Reference*バッファの欄のシンボルとその検索に使う正規表現の alist")


(defun refer-for-jump-get-content ()
"ポイントが *Reference*バッファの`File'欄や`Type'欄の行にある場合、
欄のシンボルとその後ろの文字列を取得し、多値で返す。見つけられなかった場合は nil を返す。
例: 見つけた場合こんなのを返す 'seealso と \"buffer-read-only\""
(let ((lim (save-excursion (progn (goto-eol) (point)))))
(save-excursion
(goto-bol)
(if (scan-buffer "^\\[\\(.+\\) *\\]: *\\(.*\\)$" :regexp t :limit lim)
(let ((desc (string-trim " \t" (match-string 2)))
(header (intern (nstring-downcase (substitute-string (match-string 1) "[ \t]+" "")))))
(values header desc))))))

(defun refer-for-jump-get-desc-at-point (sym)
"現在参照中のリファレンス項目の 文字列を取得する。
例: 'type --> \"Function (interactive)\" を返す。"
(let ((re (cdr (assoc sym refer-for-jump-content-alist))))
(save-excursion
(when (scan-buffer re :regexp t :reverse t)
(string-trim " \t" (match-string 1))))))

(defun refer-for-jump-file (file)
"reference の `File'欄から定義元のソースファイルを開く。"
(flet ((get-file-path (name)
(find-path-from-top-directory name *refer-for-jump-dir*)))
(let* ((type (refer-for-jump-get-desc-at-point 'type))
(name (refer-for-jump-get-desc-at-point 'name))
(re-template (cdr (assoc type refer-for-jump-file-alist :test #'string=))))
(cond ((null file))
((string= file "builtin.l") (error "ビルトイン関数なので開きません。"))
((null name) (error "reference の 項目名が見つかりません。"))
((null type) (error "reference の Type が見つかりません。"))
((null re-template) (error "Type: ~A には未対応です。" type))
((eq re-template 'ignore))
(t
(let* ((path (get-file-path file))
(buf-new (ed::find-file-internal path)))
(set-buffer buf-new)
(when *refer-for-jump-file-read-only*
(setq buffer-read-only t))
(let ((re (substitute-string re-template "XXNAMEXX" name)))
(unless (scan-buffer re :regexp t)
(delete-buffer buf-new)
(error "定義元が見つかりませんでした。")))))))))

(defun refer-for-jump-seealso (name)
"オリジナルの refer-for-search-seealso とだいたい同機能 (ただし、re は無効)"
(let ((str (format nil "^~A$" (regexp-quote name))))
(refer-for::output (refer-for::search str :by-title t))
(refer-for::set-history str t)))

;;; command
(defun refer-for-jump ()
"ポイントがある行によって、いろんなところへ飛ぶ。
`File'欄にあるときは、ソースファイルを検索する (refer-for-jump-file)
`See also'欄にあるときは、そのリファレンス項目に移動する (refer-for-jump-seealso)"
(interactive)
(multiple-value-bind (header desc) (refer-for-jump-get-content)
(case header
('seealso (refer-for-jump-seealso desc))
('file (refer-for-jump-file desc)))))

(define-key refer-for::*refer-for-mode-map* #\RET 'refer-for-jump)


ほんのすこし doc-string を書く努力をしようと思った。





ファイル名をディレクトリから探してフルパスを返す





(defun find-path-from-top-directory (name dirs)
"name というファイル名をディレクトリ配下で検索して、フルパスを返す。存在しなければ nil を返す。
同名ファイルが複数個存在したとしても、最初に見つけた1つしか返さない。
検索対象のディレクトリはリストで与えてもよい。ディレクトリ名の検索には使えない。"
(flet ((get-path-list (dir wild)
(directory dir :absolute t :recursive t :file-only t :wild wild))
(name-filter (name path)
(let ((n (car (last (split-string path #\/)))))
(if (string-equal name n) path nil))))
(unless (consp dirs) (setq dirs (cons dirs nil)))
(let* ((ext (pathname-type name))
(w (if ext (concat "*." ext) "*"))
find)
(dolist (d dirs)
(when (file-exist-p d)
(setq find (find name (get-path-list d w) :test #'name-filter)))
(when find (return find))))))





きょうの「なんでやねん」



common lisp の教本ばっかり読んでると、シンボルは内部的には大文字になってるんだよなと漠然と思ってた。


なので common な処理系ならなんでも (eq 'HOGE 'hoge ) は t になるんじゃないかと。


xyzzy では下のようになった。



;;; xyzzy
(eq 'hoge 'hoge)
;=> t

(eq 'HOGE 'hoge) ; おお? 違うのか。
;=> nil

(eq 'nil nil)
;=> t

(eq 'NIL nil) ; おおお?
;=> nil


NTEmacs-24 でやったら、xyzzy と同じになった。


ということは、xyzzy は emacs に合わせたんだな。きっと。


ちなみに clozure CL でやってみたら、上記はすべて T だった。


今頃こんなのを書いてること自体あほなんだが、emacs や xyzzy 用に書いたのを他の cl に持っていくときは要注意かもしれず。