Pacal再入門:Resultの扱い

 Pacal再入門:「ファイル存在の確認」を分割したコード - MuhのFreeBSD日記で、関数の戻り値を一時的に保存しておく為の'result'を変数として宣言すると、Lazarusで識別子'result'がダブっていると怒られる謎について書いたら、有り難い事にコメントを頂いた。

戻り値を返すための特別な識別子として `Result` 変数があるため、varで再宣言するとエラーになっているのだと思います。
FPCとDelphiでは、Result変数はvarで宣言無しでも使えます。 

  試してみた結果。

 resultを変数宣言を削除、Lazarusの環境下でコンパイル

 結果ご指摘頂いたとおり、エラーはでなかった。

 しかしながら、同じソースをLazarusを使わずコマンドラインからコンパイルした場合、Identifier not found "Result" と、またもや叱られる結果となった。

 Delphiでは試していない。コマンドラインから使用したコンパイラは、'\lazarus\fpc\3.0.4\bin\x86_64-win64\fpc.exe'。

 気になってにググってみたら、以下のようなスレッドを見つけた。

 Identifier not found "result" for Free Pascal Compiler version 2.6.4 [2014/02/26

 即ち、コマンドラインからfpc.exeでコンパイルして、Lazarusと同様の結果を得る為には、コマンドラインに'-MObjFPC'オプションをつける。もしくは、ソースにディレクティブとして、{$mode objfpc}を追加すれば良いらしい。

 ディレクティブの方を試してみたところ、コマンドモードの方でも変数宣言なしでコンパイルする事ができた。

 識別子'Result'が変数宣言なしに使えるという事自体に、たいしたメリットはない。

 互換性の問題は今後も発生するかもしれないが、それはその時対応すればよいという事で、ResultをRsultValueに変更する事で、互換性の問題については、とりあえずの回避する事にする。

 ... 更に気になって、調べて見たら、

 -Mobjfpc FPC mode with Object Pascal support との事。

 つまり、fpcはオプションなしでコンパイルした場合、プレーンなPascalとしてコンパイルされ、-Mobjfpc オプションをつけてコンパイルするとObject Pascalとしてコンパイルされる。

 Resultの問題は、PascalとObject Pascalの言語仕様の違いとして捉えるべきらしい。

Pascal再入門:ID3TAGの読み取り、車輪の再発明

 ID3TAGの仕様の解説を参考に、コマンドモードで使えるID3TAGの読み取りの為のプログラムを書こうとしている。必要に迫られているわけではなく、Pascalのプログラミングを思い出す為の題材として適当だと思い、現物合わせしながら、とりあえず手持ちの楽曲ファイルのタグを読み出せればいいと思っていたのだが、オフセット値の計算とか文字コードとか何かと面倒臭い。

 Delphiで書かれたID3v2の読み込みの為のプログラムのソースコードと解説(Delphi 6 ローテクTips/ID3タグ自作関数 ID3v2読み込み - カルト・ドラン)を見つけた。有り難く参考にさせて頂く。

Pascal再入門:ID3TAGの解析、リハビリに適度な低水準処理

 ID3TAGにはバージョンがあって、ID3V1の構成は単純で取り扱いは簡単だが、ID3V2の場合は各情報のオフセットを読み取る必要があり、それもバージョンにより取り扱いが異なるようだ。

 ファイルの冒頭から3バイトの識別子でV1とV2を区別し、V1の場合はその後に固定長の情報、即ち「曲名」「アーティスト名」「アルバム名」...等が並ぶ。V2の場合はちょっとややっこしくて、3バイトの識別子のあとの2バイトがサブバージョンになり、そのサブバージョンで構成が異なる。

 参考にしているMP3 ファイルのタグについての解説 (id3v1, id3v2, MPEG フレームヘッダ, XING ヘッダ)には、ID3v2.2とID3v2.3が解説されている。

 

 Unit ID3TAGを書き加えた。

unit id3tag;
interface
procedure id3v2(tag :array of byte);
procedure readfile(s : string);
implementation
var
   F	  : File;
   procedure id3v2(tag :array of byte);
   begin
      writeln('id3v2', '.' ,(tag[4]), (tag[5]));
      writeln('[',tag[1],'.' ,tag[2],'.' ,tag[3],'.' ,tag[4],'.' ,tag[5],'.' ,tag[6],'.' , tag[7],'.' , tag[8],'.' , tag[9],'.' , tag[10],'.' , tag[11],']');
   end;

   procedure readfile(s : string);
   var
      R : array[1..128] of byte;
      i : integer;
   begin
      Assign(F,s);
      Reset(F,1);
      BlockRead(F, R, SizeOf(R));
      Close(F);
      if ((char(R[1])='I') and (char(R[2])='D') and (char(R[3])='3'))
	 then id3v2(R[1..10]); 
      for i := 1 to 128 do
      begin
	 write(char(R[i]));
      end;
      writeln();
      writeln('dummy3');
   end;
end.

 これを実行した場合、以下のようになる。

>sim4 11-Chiquitita.mp3
sim4 11-Chiquitita.mp3
11-Chiquitita.mp3 is Exists.
finded arg is "11-Chiquitita.mp3"
id3v2.00
[68.51.3.0.0.0.3.47.118.0.0]

...

dummy3

  ...はバイト配列をそのまま出力しているので、文字化けする。ID3、/vTDAT、UFID、http://www.cddb.com/id3/taginfo1.html ,,,等は読み取れる。

Pascal再入門:とりあえずmp3ファイルを読み込んでみる

 今、書こうとしているのは、mp3ファイルからid3tagを読み取る為のプログラム。

 Pascalでのテキストファイルのシーケンシャルな読み書きは、日常的に使っていたのだが、バイナリーとかランダムアクセスは使う機会がなかった。

 更に、id3tagの構造とか文字コードの知識とかが必要。あまり自信がない。座学で知識を収集してからでは、いつまで経っても先に進まないので、とりあえず読み込んでみる。

 対象は、前回分割したunitの片割れ。分割したのは、対象を局所化する為。

 
unit id3tag;
interface
procedure readfile(s : string);
implementation
procedure readfile(s : string);
var
   F : File;
   R : array[1..128] of byte;
   i : integer;
begin
   Assign(F,s);
   Reset(F,1);
   BlockRead(F, R, SizeOf(R));
   Close(F);
   for i := 1 to 128 do
   begin
      write(char(R[i]));
   end;
   writeln();
   writeln('dummy3');
end;
end.

  このunitと、呼び出し側のプログラムのコードを再コンパイルして、適当なmp3のファイル名を引数にして実行すると、文字コードとバイナリの混在した出力が得られる。最初の3文字'ID3'が読み取れたので。プログラムは正常に動いている。この後の出力を解析する必要がある。

 

 ID3TAGに関しては、とりあえず、最初にヒットした以下のサイトを参考にする。

MP3 ファイルのタグについての解説 (id3v1, id3v2, MPEG フレームヘッダ, XING ヘッダ)

Pacal再入門:Unitを2つに分ける

 引数として与えられたファイル名の妥当性の検証の為のコードと、未実装のID3TAG解析の為のコードを分ける為に、Unitを分割した。呼び出される側のUnitと本体のProgramを毎回コンパイルしなければならないのは面倒臭いが、これは仕方がない。

program sim4;
uses myApp, id3tag;
var st : string;
begin
   if argchk(argc) then begin
      st := argv[1];
      if existchk(st) then begin
         main(st);
	 readfile(st);
      end;
   end;
end.
unit myApp;
interface
function argchk(c : integer) :boolean;
function existchk(s : string):boolean;
procedure main(st   : string);
implementation
uses
sysutils;
function argchk(c : integer) :boolean;
var
   result : boolean;
begin
   if c=2 then result := true else begin
      result:=false;
      if c<2 then writeln('Missing arg') else writeln('Too much args');
   end;
   argchk:=result;
end;
function existchk(s : string):boolean;
var
   result : boolean;
begin
   if FileExists(s) then
   begin
      result := true;
      writeln(s, ' is Exists.')
   end
   else begin
      result := false;
      writeln(s, ' is not Exists.')
   end;
   existchk := result;
end;   
procedure main(st   : string);
begin
   writeln('finded arg is', ' "', st, '"');
end;
end.
unit id3tag;
interface
procedure readfile(s : string);
implementation
procedure readfile(s : string);
begin
   writeln('dummy3');
end;
end.

 きちんと再コンパイルしたつもりだが、unit myApp中のprocedure readfileの呼び出しはprogram sim4で呼び出す事にして、myAppの方は//でコメントアウトしたのだが、ダブって呼び出された。原因は不明。

 コマンドラインで使うコンパイラオプションも良く判らないので、オプションなしで使っている。ソース中で使うべきデレクティブも無視。

 Free Pascal - Advanced open source Pascal compiler for Pascal and Object Pascal - Home Pageにドキュメント類は整備されているのだが、なかなか読む気になれない。本棚に紙のマニュアルも発見しているのだが、分厚過ぎて背表紙を見ただけで、持ち出したくなくなる。

  fpでCUIベースのIDEが起動するらしいのだが、FreePascalではなくLazarusuをインストールした為か、fp.exeは見当たらない。このインストールではC:\lazarus\fpc\3.0.4\bin\x86_64-win64\配下にバイナリーがある。あまり環境を汚したくないので、パスは通さずに、C:\lazarus\fpc\3.0.4\bin\x86_64-win64\fpc <ターゲットのソース>でコンパイルしている。また、ソースコードもdesktop/doc/fpc配下に置いている。最終的には生成される単一のexeファイルのみで実行できるので、後腐れがなくていい。

Emacs Lispのメリット

 Pascalの再学習を始めて判ったEmacsLispのよいところは、細かな事を覚えなくても、なんとなく動くプログラムが書けてしまう事。お約束が少ないので、最初の敷居を踏み越えてしまえば、類推的に先に進めてしまう。お約束はあるのだが、それほど複雑なものではない。

 Pascalがそんなにややっこしい言語だとは思っていなかったのだが、一旦忘れてしまって再学習となると、結構細かくて面倒くさい。覚えなおす事が多過ぎる。コンパイラ独特のお約束もある。

 一昨年、Lispをいじり始めた時、BASICの気軽さに似ていると思ったのだが、これはインタプリタの気軽さだったのかもしれない。昔はインタプリタは遅くて初心者用の言語というイメージがあったが、今はハードウェアの処理速度が速くなったし、主記憶容量も比べ物にならない。逆にコンパイラが吐き出す実行ファイルは大きくなり、NETとかLLVMとかの前提になったりして、昔の単純にマシン語に変換するコンパイラではなくなってしまっている。

 Emacs Lispの主戦場はあくまでもEmacs用のマクロ言語なので、一般的なプログラミング言語とは用途は異なるのだが、目的がEmacsの世界で用が済んでしまうのなら、対象が具体的な事もあいまって、手軽で強力な手段になる。

NTEmacsの背景色を変更と文字の大きさ

 Windowsのデスクトップ上のEmacsアイコンのショートカット先をrunemacs.exeに変更。

 白背景は目が疲れるので、Emacs24に最初から同梱されているテーマ - AOEの日記を参考に、

 ~/.emacs.d/init.elに、

(load-theme 'misterioso t)

 を記述。

 文字の大きさは、Emacs で文字の大きさを一時的に変更する C-x C-0 - Qiitaを参考に、

C-x C-0 大きくするなら、+ 小さくするなら - 元に戻すのなら0。

一時的な調整で、そのバッファでしか有効ではないが、とても便利。

 但し端末エミュレーターからの接続では無効、-noxでインストールしている仮想環境上のコンソールでも無効。Windows上のNTEmacsでは有効。

 

 Windowsの環境を快適にし過ぎると、仮想環境上のFreeBSDが用無しになってしまう。