unit uSearchRec;

(*
  by take_tk 2001-04-06
  [ap-list:1414]
*)

interface

uses Rubies;

var
  sSearchRec: Tvalue;

procedure Init_SearchRec;

implementation

uses uDateTime, uConv, SysUtils, uStrUtils, uDefUtils, uPhi;

function SearchRec_alloc(real: TSearchRec): Tvalue;
var
  ary: Tvalue;
  time: TDateTime;
begin
  ary := rb_ary_new;
      //	protect from invalid file date like ..
      //	c:\save2dsk.bin 1980/00/00 00:00:00
  //rb_ary_push(ary, INT2FIX(real.Time));	//Time: Integer;
  try
    time := FileDateToDateTime(real.Time);
  except
    time := encodeDate(1900,1,1);
  end;
  rb_ary_push(ary, ap_DateTime(time));
    //
  rb_ary_push(ary, INT2FIX(real.Size));		//Size: Integer;
  rb_ary_push(ary, INT2FIX(real.Attr));		//Attr: Integer;
  rb_ary_push(ary, ap_String(real.Name));	//Name: TFileName;
  
  // not support
  //rb_ary_push(ary, INT2FIX(real.ExcludeAttr);	//ExcludeAttr: Integer;
  //rb_ary_push(ary, INT2FIX(real.FindHandle);	//FindHandle: THandle;
  //						//FindData: TWin32FindData;
  result := rb_struct_alloc(sSearchRec, ary);
end;

(*
: Win.dos_dir(mask, attr)
  ディレクトリを検索して Win::SearchRec の配列を返します。

  "Win.dos_dir" searches disignated directory by "mask" and "attr", and returns an array of SearchRec(s).

  mask は 'c:/windows/*.*' という書式で指定します。
  '\' で区切ることもできますが，Ruby で書く場合には '\\' のようにエスケープする必要があるでしょう。

  mask is like this; 'c:/windows/*.*'. You may use '\\' for delimtters.

  attr には次の指定が可能です。( Dos/Windows の仕様とは異なるので注意 )

  attr is differ from the same of Dos/Windows.  When "Win::FA_FILE" was designated, dos_dir choose files which have not faDirectory bit nor faVolumeID bit. Default is "Win::FA_ANY_FILE" which matches all.

      Win::FA_ANY_FILE      すべて ( デフォルト )
      Win::FA_FILE          ファイル
      Win::FA_DIRECROY      ディレクトリ
      Win::FA_VAOLUME_ID    ボリュームラベル ( 無効 ? )

  * 以下の指定は無効です。
      Win::FA_READ_ONLY     読みとり専用
      Win::FA_HIDDEN        隠し属性
    除外するには読みとり後に Win::SearchRec#attr を調べてください。

  * Win::FA_FILE は Dos/Windows の仕様にはありません。
      Win::FA_FILE          not (FA_DIRECROTY or FA_VOLUME_ID)

  * 以下は指定できますが，最近の Windows では無効のようです。
      Win::FA_VAOLUME_ID ボリュームラベルにマッチ

  取得した Win::SearchRec#attr は次の定数で判断してください。
    Win::FA_READ_ONLY
    Win::FA_HIDDEN
    Win::FA_SYS_FILE
    Win::FA_VOLUME_ID
    Win::FA_DIRECTORY
    Win::FA_ARCHIVE
    Win::FA_ANY_FILE

*)

const
  faFile = faAnyFile + 1;
  faDirVol = faDirectory or faVolumeID;

function Win_dos_dir(argc: integer; argv: Pointer; This: Tvalue): Tvalue; cdecl;
var
  p: Pvalue;
  stat: Tvalue;
  mask: string;
  info: TSearchRec;
  attr: Integer;
  TimeFrom, TimeTo: TDateTime;
begin
  if argc < 1 then ap_raise(ap_eArgError, sToo_few_args);
  p := argv;

  mask := dl_String(p^); inc(p);

  if ( argc > 1 ) and ( p^ <> Qnil ) then begin
    attr := FIX2INT(p^); inc(p);
  end else
    attr := faAnyFile;

  if ( argc > 2 ) and ( p^ <> Qnil ) then begin
    TimeFrom := DateTimeToFileDate(dl_DateTime(p^)); inc(p);
  end else
    TimeFrom := 0;

  if ( argc > 3 ) and ( p^ <> Qnil ) then begin
    TimeTo := DateTimeToFileDate(dl_DateTime(p^)); inc(p);
  end else
    TimeTo := 0;

  result := rb_ary_new;

  if FindFirst(mask, faAnyFile, info) = 0 then
  try
    repeat
      if ( attr = faAnyFile )
      or ( ( ( attr and faFile ) <> 0 ) and ( (info.attr and faDirVol) = 0 )
      or ( ( info.attr and attr ) <> 0 ) )
      then begin
        if  ( (info.attr and faDirVol) <> 0 )
        or  ( ( ( TimeFrom = 0 ) or ( info.time >= TimeFrom ) )
          and ( ( TimeTo   = 0 ) or ( info.time <= TimeTo ) ) )
        then begin
          stat := SearchRec_alloc(info);
          rb_ary_push(result, stat);
        end;
      end;
    until FindNext(info) <> 0;
  finally
    FindClose(info);
  end;
end;

const
  props: array[0..3] of PChar = (
    'Time',
    'Size',
    'Attr',
    'Name'
  );

procedure Init_SearchRec;
var
  ary: Tvalue;
  i: Integer;
begin
    //Time: Integer;
    //Size: Integer;
    //Attr: Integer;
    //Name: TFileName;
    //ExcludeAttr: Integer;
    //FindHandle: THandle;
    //FindData: TWin32FindData;
  ary := rb_ary_new;
  rb_ary_push(ary, rb_str_new2('SearchRec'));
  for i := low(props) to high(props) do
    rb_ary_push(ary, ap_String(LowerCase1(props[i])));
  sSearchRec := rb_apply(ap_cStruct, rb_intern('new'), ary);
  rb_global_variable(@sSearchRec);

    //faReadOnly    $00000001   読み出し専用ファイル
    //faHidden      $00000002   非表示ファイル
    //faSysFile     $00000004   システムファイル
    //faVolumeID    $00000008   ボリュームファイル
    //faDirectory   $00000010   ディレクトリファイル
    //faArchive     $00000020   アーカイブファイル
    //faAnyFile     $0000003F   すべてのファイル
    //faFile        $00000040   ファイル # Apollo extension
  ap_define_const(mPhi, 'faReadOnly', INT2FIX(faReadOnly));
  ap_define_const(mPhi, 'faHidden', INT2FIX(faHidden));
  ap_define_const(mPhi, 'faSysFile', INT2FIX(faSysFile));
  ap_define_const(mPhi, 'faVolumeID', INT2FIX(faVolumeID));
  ap_define_const(mPhi, 'faDirectory', INT2FIX(faDirectory));
  ap_define_const(mPhi, 'faArchive', INT2FIX(faArchive));
  ap_define_const(mPhi, 'faAnyFile', INT2FIX(faAnyFile));
  ap_define_const(mPhi, 'faFile', INT2FIX(faFile));

  DefineModuleFunction(mPhi, 'dos_dir', Win_dos_dir);
end;

end.
