[FDclone3 に関するテクニカルノウハウ集]


1.機種依存性吸収のために用意されている識別子

　machine.h の中や、make config で生成される config.h の中で
は、各種の識別子が定義されています。これらの識別子は、OS の
違いを吸収するために設けられています。
　自分の環境で、うまくコンパイルできない、どうもおかしな挙動
を示すというような場合には、これらの識別子を定義したり、定義
を取り消したりして調整して下さい。
　各識別子の意味を以下に列挙します。

SYSV
SVR4
BSD4
BSD43	各種 OS の元となるタイプを示します。SYSV, SVR4 は、
	machine.h の後半で、OS 特有の定義のために参照されて
	いますが、BSD4, BSD43 は、参考として定義されているだ
	けなので、実際にはソース中で参照されていません。

OSTYPE	各 OS を表す識別子を定義しています。フロッピードライ
	ブのデフォルト設定を OS に応じて行なうために使用され
	ています。

CODEEUC	漢字コードとして、EUC (Extended Unix Code) 漢字を用
	います。未定義の場合は Shift JIS になります。インス
	トール後の man ページや、漢字コード未指定時のデフォ
	ルト値に影響します。
	入出力やファイル名に用いる漢字コードに関しては、コン
	パイル後に動的に変更可能です。
DEFKCODE
	OS 標準で用いる漢字コードを示す文字列を指定します。
	定義された場合には、漢字コードに関する各種内部変数の
	初期値として用いられます。
UTF8DOC	ドキュメントの漢字コードとして UTF-8 を用います。未
	定義の場合は CODEEUC の定義に従います。DEFKCODE の値
	が「utf8-mac」もしくは「utf8-iconv」の場合は、その指
	定による UNICODE マッピングを用います。
UTF8LANG
	環境変数 LANG に「UTF」が含まれている場合に、OS 標準
	で用いる漢字コード及びドキュメントの漢字コードとして
	用いる文字列を指定します。LANG が「UTF」を含まない場
	合には意味を持ちません。
NOMULTIKANJI
	複数の漢字コードが共存する環境を考慮する必要がありま
	せん。
PATHNOCASE
	パス名に含まれる大文字小文字の区別が無視されます。
COMMNOCASE
	シェルコマンド名に含まれる大文字小文字の区別が無視さ
	れます。
ENVNOCASE
	環境変数名に含まれる大文字小文字の区別が無視されます。
NOUID
	ユーザ ID やグループ ID がありません。
NODIRLOOP
	ディレクトリ構造が絶対にループし得ません。
NOSYMLINK
	シンボリックリンクが実装されていません。
BSPATHDELIM
	パス名区切り子がバックスラッシュ文字です。
USECRNL
	テキストの改行文字として CR-NL を用います。
CWDINPATH
	コマンドサーチパスに暗黙の了解としてカレントディレク
	トリが含まれています。
DOUBLESLASH
	// (または \\) で始まるパス名が、特殊な意味を持つパ
	ス名 (実例としては Cygwin に於ける共有フォルダ) とし
	て許容されている。
USEMANLANG
	man(1) の参照する検索パス名が、/usr/man/ja_JP.SJIS/
	のように環境変数 LANG で示される文字列を含み、多国語
	対応されています。
LANGWIDTH
	USEMANLANG が設定されている場合に、環境変数 LANG で
	示される文字列の先頭から man(1) の検索パス名に用いる
	文字数	を指定します。一般的な NLS (Native Language
	System)	では 2 文字または 5 文字になります。
USEDATADIR
	UNICODE 変換テーブル fd-unicd.tbl や日本語入力用かな
	漢字変換テーブル fd-dict.tbl を、fd の起動ディレクト
	リでなく Makefile.in の DATADIR で指定されたディレク
	トリに置きます。
SUPPORTSJIS
	cc(1) や man(1) が完全に Shift JIS を正しく扱えます。
	2 byte 目に '\' が来るような漢字に対しても、この '\'
	を meta character として扱いません。
BSDINSTALL
	BSD ライクな install(1) が標準のコマンド検索パス上に
	実装されており、-c (copy) や -s (strip) といったオプ
	ションが使えます。
BSDINSTCMD
	BSD ライクな install(1) のコマンド名が "install" 以
	外の場合、そのコマンド名を定義します。BSDINSTALL を
	定義していない場合は意味を持ちません。
TARUSESPACE
	tar(1) の t オプションの出力の際に、各行のファイルモ
	ード文字列 (Ex:rw-rw-rw-) の直後に必ず空白が入ってい
	る場合に定義します。BSD 系の OS では、空白がなく直後
	に UID/GID が続く場合が多いようです。GNU tar では空
	白が入ります。
	ここで仮に定義を間違えたとしても、.fd2rc や /etc/fd2rc
	の記述で動的に変更することは可能です。
TARFROMPAX
	tar(1) の実装が pax(1) 由来のもので、t オプションの
	出力が pax(1) で使われている書式になっている場合に定
	義します。
	ここで仮に定義を間違えたとしても、.fd2rc や /etc/fd2rc
	の記述で動的に変更することは可能です。
BUGGYMAKE
	make(1) が、1 秒以内に連続して作成されたファイルの依
	存関係を正しく判断できません。
BUGGYSIGNALH
	<signal.h> をインクルードするとモジュール毎に同一の
	実体を生成してしまい、リンク時にエラーになります。
CPP7BIT	cpp(1) が、漢字などの 8bit 文字を通すことができませ
	ん。
OLDARGINT
	cc(1) が、古典タイプの関数引数を int 型と見なします。
CCCOMMAND
	標準として用いるべき c コンパイラのフルパスを定義し
	ます。一部の OS では、BSD 版 cc と SYSV 版 cc が混在
	することがありますので、どちらかに統一しておきましょ
	う。未定義の場合には cc が用いられます。
EXTENDCCOPT
	cc(1) に与えるオプションを定義します。未定義の場合は
	"-O" が指定されます。"-O"(Optimize) に未対応の場合に
	は、ヌルを定義しておきましょう。
CCOUTOPT
	コンパイルのみでリンクをしない場合 (-c オプション指
	定時) に、出力ファイル名を cc(1) に与えるオプション
	を、出力ファイル名の make(1) マクロ付で定義します。
	デフォルトの "-o $@" 以外を必要とする時に指定して下
	さい。
CCLNKOPT
	実行ファイルのリンクをする場合 (-c オプション無指定
	時) に、出力ファイル名を cc(1) に与えるオプションを、
	出力ファイル名の make(1) マクロ付で定義します。デフ
	ォルトの "-o $@" 以外の時に指定して下さい。
USETERMINFO
	端末データベースとして、termcap(5) library の代わり
	に terminfo(5) library を用います。
TERMCAPLIB
	termcap(5) ライブラリとしてリンクしなくてはならない
	ライブラリを定義します。未定義の場合は -ltermcap が
	指定されます。
REGEXPLIB
	正規表現ライブラリとしてリンクしなければならないライ
	ブラリがある場合定義します。
SOCKETLIB
	ソケットライブラリとしてリンクしなければならないライ
	ブラリがある場合定義します。
EXTENDLIB
	その他追加でリンクしなくてはならないライブラリがある
	場合定義します。

UNKNOWNFS
	FDclone が想定している以外のファイルシステムを OS が
	採用しています。その他、ディレクトリ書込み機能がうま
	く実現できない場合にも、安全のため定義しておきます。
	詳細は 2. の項目を参照して下さい。

NOFILEMACRO
	cc(1) がマクロ __FILE__ を評価できません。
NOFUNCMACRO
	cc(1) がマクロ __FUNCTION__ を評価できません。
NOLINEMACRO
	cc(1) がマクロ __LINE__ を評価できません。
FORCEDSTDC
	__STDC__ がプリデファインされていないけれども、プロ
	トタイプ宣言等に ANSI 標準 C の書式を要求する仕様に
	なっている場合に定義します。ANSI 準拠であることが保
	証されている場合、無条件にこれを定義してしまっても特
	に支障ありません。
STRICTSTDC
	モダンタイプのプロトタイプ宣言と、K&R の旧式の関数宣
	言との混在を許さない、頑なな ANSI 標準 C 仕様になっ
	ている場合に定義します。関数の引数の型絡みでエラーが
	大量に出るときに定義して下さい。
NOSTDC	__STDC__ がプリデファインされているけれども、K&R の
	旧式の C 言語仕様が期待されている場合に定義します。
NOCONST	__STDC__ がプリデファインされているけれども、修飾子
	const に対応していない場合に定義します。
NOVOID	void 型を用いることができません。
NOUINT	u_int 型を用いることができません。
NOLONGLONG
	long long 型を使うことができません。
HAVELONGLONG
	long long 型に対応しています。
NOUID_T	uid_t, gid_t が <sys/types.h> で定義されていません。
USEPID_T
	fork(2) や wait(2) がプロセス ID として pid_t 型を用
	います。
DECLSIGLIST
	大域変数 sys_siglist[] が <signal.h> の中で宣言され
	ており、ソースリスト中で改めて宣言する必要がありませ
	ん。
NOSIGLIST
	大域変数 sys_siglist[] が標準ライブラリの中に存在し
	ません。
DECLERRLIST
	大域変数 sys_errlist[] が <stdio.h> または <errno.h>
	の中で宣言されており、ソースリスト中で改めて宣言する
	必要がありません。
PWNEEDERROR
	/lib/libPW.a をリンクする際に、大域変数 Error[] をソ
	ース中に用意しなくてはなりません。
NOERRNO	大域変数 errno が <errno.h> の中で宣言されていません。
NOFILEMODE
	ファイルモードを示す定数 S_IRUSR, S_IWUSR 等が <sys/
	stat.h> の中で定義されていません。
NOUNISTDH
	<unistd.h> が存在しません。
NOSTDLIBH
	<stdlib.h> が存在しません。
NOTZFILEH
	<tzfile.h> が存在しません。
USELEAPCNT
	構造体 tzhead がメンバ tzh_leapcnt を持ちます。
USESELECTH
	関数 select(2) を利用する際に必要な構造体 fd_set が、
	<sys/select.h> の中で定義されています。
USESYSDIRH
	ディレクトリファイルのブロックを示す定数 DEV_BSIZE
	が、<sys/dir.h> の中で定義されています。
USETIMEH
	構造体 tm が、<sys/types.h> や <sys/time.h> を参照す
	るだけでは定義されず、<time.h> が必要です。
USESTDARGH
	可変引数を扱う va_list 型が <stdarg.h> の中で定義さ
	れています。
USEMKDEVH
	デバイス番号用マクロ (または関数) major()/minor() が
	<sys/mkdev.h> の中で定義されています。
USEMKNODH
	デバイス番号用マクロ (または関数) major()/minor() が
	<sys/mknod.h> の中で定義されています。
USELOCKFH
	ファイルロック関数 lockf(2) のコマンドを示す各定数が
	<sys/lockf.h> の中で定義されています。
USETERMIO
	端末インタフェースとして、termio 構造体を用います。
USETERMIOS
	端末インタフェースとして、termios 構造体を用います。
	USETERMIO, USETERMIOS 共に未定義の場合には sgttyb
	構造体を用います。
HAVECLINE
	構造体 termios がメンバ c_line を持ちます。
USEDEVPTMX
	擬似端末用デバイスとして /dev/ptmx と /dev/pts/? を
	用います。
USEDEVPTY
	擬似端末用デバイスとして /dev/ptyXX と /dev/ttyXX を
	用います。
USEDIRECT
	構造体 dirent の代わりに direct を用います。
SYSVDIRENT
	構造体 dirent がメンバ d_fileno を持たず d_ino を持
	ちます。
NODNAMLEN
	構造体 dirent がメンバ d_namlen を持ちません。
NODRECLEN
	構造体 dirent がメンバ d_reclen を持ちません。代わり
	にメンバ d_fd を持ちます。
DNAMESIZE
	構造体 dirent のメンバ d_name のサイズを示します。
HAVETIMEZONE
	大域変数 timezone が GMT からのオフセット値を表しま
	す。
NOTMGMTOFF
	構造体 tm がメンバ tm_gmtoff を持ちません。
NOSTBLKSIZE
	構造体 stat がメンバ st_blksize を持ちません。
NOFTPH
	<arpa/ftp.h> が存在しません。
USEINSYSTMH
	<netinet/in_systm.h> が <netinet/ip.h> を使用するた
	めに必要です。
NOHADDRLIST
	構造体 hostent がメンバ h_addr_list を持ちません。

(以下の 5 つは排他的です。同時に複数定義できません。)
USESTATVFSH
	ファイルシステム情報を得るために、<sys/statvfs.h> で
	宣言されている関数群を用います。
USESTATFSH
	ファイルシステム情報を得るために、<sys/statfs.h> で
	宣言されている関数群を用います。
USEVFSH
	ファイルシステム情報を得るために、<sys/vfs.h> で宣言
	されている関数群を用います。
USEMOUNTH
	ファイルシステム情報を得るために、<sys/mount.h> で宣
	言されている関数群を用います。
USEFSDATA
	ファイルシステム情報を得るために、構造体 fs_data を
	用いる関数群を用います。

USEFFSIZE
	構造体 statfs のメンバの中で、ファイルシステムのブロ
	ックサイズとして f_fsize を参照します。未定義の場合
	は f_bsize を参照します。
	USESTATVFSH, USEFSDATA を定義した場合は意味を持ちま
	せん。
NOFBLOCKS
	構造体 statfs がメンバ f_blocks を持ちません。
NOFBFREE
	構造体 statfs がメンバ f_bfree を持ちません。
NOFFILES
	構造体 statfs がメンバ f_files を持ちません。
USESTATVFS_T
	構造体 statvfs の代わりに statvfs_t を用います。
STATFSARGS
	関数 statfs(2) の用いる引数の数を定義します。
	USESTATVFSH, USEFSDATA を定義した場合は意味を持ちま
	せん。
USEFSTATFS
	ファイルシステム情報取得関数として statfs(2) を用い
	られず、代わりに fstatfs(2) を用います。

(以下の 10 つは排他的です。同時に複数定義できません。)
USEMNTENTH
	マウント情報を得るために、<mntent.h> で宣言されてい
	る関数群を用います。
USEMNTTABH
	マウント情報を得るために、<sys/mnttab.h> で宣言され
	ている関数群を用います。
USEGETFSSTAT
	マウント情報を得るために、関数 getfsstat(2) を用いま
	す。
USEGETVFSTAT
	マウント情報を得るために、関数 getvfsstat(2) を用い
	ます。
USEMNTCTL
	マウント情報を得るために、関数 mntctl(3) を用います。
USEMNTINFOR
	マウント情報を得るために、関数 getmntinfo_r(3) を用
	います。
USEMNTINFO
	マウント情報を得るために、関数 getmntinfo(3) を用い
	ます。
USEGETMNT
	マウント情報を得るために、関数 getmnt(3) を用います。
USEGETFSENT
	マウント情報を得るために、関数 getfsent(3) を用いま
	す。
	(この手法はマウント前の情報を取得してしまうのでお奨
	めできません。窮余の策だと思って下さい。)
USEREADMTAB
	マウント情報を得るために、/etc/mtab を直接読みます。

USEPROCMNT
	マウント情報ファイルとして /proc/mounts を使用します。
	(この手法は mount(8) ではなくカーネルからの情報を取
	得してしまうのでお奨めできません。窮余の策だと思って
	下さい。)

(以下の 2 つは排他的です。同時に複数定義できません。上記の 8
つの選択肢のうち USEMNTINFO 以外を定義した場合は意味を持ちま
せん。)
USEVFCNAME
	構造体 vfsconf のメンバの中で、マウントタイプを表す
	文字列として vfc_name を参照します。また、vfsconf 型
	の取得に getvfsbytype() を用います。
USEFFSTYPE
	構造体 statfs のメンバの中で、マウントタイプを表す文
	字列として f_fstypename を参照します。

(以下の 3 つは排他的です。同時に複数定義できません。)
USERE_COMP
	正規表現検索のために関数 re_comp(3) を用います。
USEREGCOMP
	正規表現検索のために関数 regcomp(3) を用います。
USEREGCMP
	正規表現検索のために関数 regcmp(3) を用います。

USERAND48
	乱数発生用関数として random(3) ではなく rand48(3) を
	用います。
USESETENV
	環境変数設定用関数として setenv(3) が使えます。
NOSELECT
	低レベル入出力関数 select(2) を使うことができません。
DEFFDSETSIZE
	低レベル入出力関数 select(2) を使うために、予め識別
	子 FD_SETSIZE にオープンファイルの最大数を定義してお
	く必要があります。
SELECTRWONLY
	低レベル入出力関数 select(2) が、読書き用に open さ
	れているファイル記述子に反応しません。
NOVSPRINTF
	書式付出力関数 vsprintf(3) を使うことができません。
NOTERMVAR
	termcap(5) ライブラリ内に PC, ospeed, BC, UP といっ
	た大域変数が用意されていません。
USEUTIME
	タイムスタンプ設定関数として utimes(2) を用いられず、
	代わりに utime(3) を用います。
USEGETWD
	カレントディレクトリ検査関数として、getcwd(3) を用い
	られず、代わりに getwd(3) を用います。
ULONGIOCTL
	入出力制御関数 ioctl(2) の第 2 引数として、unsigned
	long 型を用います。
NOFTRUNCATE
	ファイルサイズ制御関数 ftruncate(2) を使うことができ
	ません。
USEFCNTLOCK
	ファイル制御関数 fcntl(2) を flock(2) の代わりに用い
	ます。
USELOCKF
	ファイルロック関数として flock(2) を使うことができず、
	代わりに lockf(2) を用います。
NOFLOCK
	ファイルロック関数として flock(2) も lockf(2) も使う
	ことができません。
NOSYSLOG
	システムロガー関数 syslog(3) を使うことができません。
USETIMELOCAL
	時間変換関数 timelocal(3) が localtime(3) の逆関数と
	して使えます。
USEMKTIME
	時間変換関数 mktime(3) を timelocal(3) の代わりに用
	います。
USESYSCONF
	設定情報取得関数 sysconf(3) を用いて各種システム設定
	値を取得します。
USELLSEEK
	ファイル制御関数 _llseek(2) を lseek(2) の代わりに用
	います。32bit Linux 環境では 2^32 bytes を越える範囲
	の offset 指定ができないので _llseek(2) が必要です。
USEUNAME
	ホスト名取得関数 uname(2) を gethostname(2) の代わり
	に用います。
NOKILLPG
	プロセスグループ管理関数 killpg(2) を使うことができ
	ません。
USEWAITPID
	ソフトウェアシグナル待ち関数 waitpid(2) を wait3(2)
	の代わりに用います。
USESIGACTION
	シグナル操作関数 sigaction(2) を signal(2) の代わり
	に用います。
USESIGPMASK
	シグナル操作関数 sigprocmask(2) を sigsetmask(2) の
	代わりに用います。
USERESOURCEH
	リソース情報を取得・設定する際に <sys/resource.h> で
	定義された関数群を用います。
USEULIMITH
	リソース情報を取得・設定する際に <ulimit.h> で定義さ
	れた関数群を用います。
USEGETRUSAGE
	プロセス時間情報を取得する際に getrusage(2) を用いま
	す。
USETIMES
	プロセス時間情報を取得する際に times(2) を用います。
GETPGRPVOID
	プロセスグループ取得関数 getpgrp(2) が引数を持ちませ
	ん。
USESETPGID
	プロセスグループ設定関数 setpgid(2) を setpgrp(2) の
	代わりに用います。
NOSETPGRP
	プロセスグループ設定関数 setpgrp(2) を使うことができ
	ません。
USETCGETPGRP
	制御端末用関数として ioctl(2) ではなく tcgetpgrp(3)
	及び tcsetpgrp(3) を用います。
USESETVBUF
	バッファリング関数 setvbuf(3) を setlinebuf(3) の代
	わりに用います。
SIGARGINT
	ソフトウェアシグナル関数 signal(3) の第 2 引数として、
	int 型を返す関数へのポインタが用いられます。
SIGFNCINT
	ソフトウェアシグナル関数 signal(3) の第 2 引数として、
	int 型の引数を持つ関数へのポインタが用いられます。
USESTRERROR
	エラー文字列関数 strerror(3) を sys_errlist[] の代わ
	りに用います。
GETTODARGS
	時刻取得関数 gettimeofday(2) の用いる引数の数を指定
	します。デフォルトは 2 です。
GETTODNULL
	時刻取得関数 gettimeofday(2) の第 2 引数が NULL でな
	くてはなりません。
USESETSID
	セッション制御関数 setsid(2) を用いることができます。
USEMMAP
	ファイルマップ関数 mmap(2) を用いることができます。
NOGETPASS
	パスワード入力関数 getpass(3) を使うことができません。
USESOCKLEN
	ソケット関数 bind(2)/connect(2)/accept(2) の第 3 引
	数として socklen_t 型を用います。
NOSENDFLAGS
	ソケット関数 send(2) の第 4 引数にフラグを使うことが
	できません。
USEINETATON
	アドレス操作関数 inet_aton(3) を inet_addr(3) の代わ
	りに用います。
USEINETPTON
	アドレス操作関数 inet_pton(3) を inet_addr(3) の代わ
	りに用います。
NOGETPWENT
	ユーザ ID 取得関数 getpwent(3) を使うことができませ
	ん。
NOGETGRENT
	グループ ID 取得関数 getgrent(3) を使うことができま
	せん。
USESETREUID
	ユーザ ID 設定関数 setreuid(2) を seteuid(2) の代わ
	りに用います。
USESETRESUID
	ユーザ ID 設定関数 setresuid(2) を seteuid(2) の代わ
	りに用います。
USESETREGID
	グループ ID 設定関数 setregid(2) を setegid(2) の代
	わりに用います。
USESETRESGID
	グループ ID 設定関数 setresgid(2) を setegid(2) の代
	わりに用います。
USEGETGROUPS
	グループアクセスリスト取得関数 getgroups(2) が利用可
	能です。

SENSEPERSEC
	1 秒間にキー入力を関知する回数を指定します。端末通信
	速度の遅い場合に定義すると良いでしょう。デフォルトは
	50 回です。
WAITKEYPAD
	ESC キーコードの入力を受けてから待つ時間です。端末通
	信速度の遅い場合に定義すると良いでしょう。デフォルト
	は 360ms です。
WAITTERMINAL
	端末が応答するエスケープシーケンスの各文字を待つ時間
	です。端末の反応が鈍い場合に定義すると良いでしょう。
	デフォルトでは WAITKEYPAD の値を継承します。
WAITKANJI
	マルチバイト文字の入力中に次のキーコード入力を待つ時
	間です。端末通信速度の遅い場合に定義すると良いでしょ
	う。デフォルトは 120ms です。
HDDMOUNT
	フロッピードライブ機能をハードディスクドライブに対応
	させます。PC-UNIX 以外でこの機能を用いたい場合は設定
	して下さい。


2.ディレクトリ書込み機能

　コマンド WRITE_DIR (w) を用いることで、FDclone の表示ディ
レクトリの並びをそのままファイルシステムに書込むことができま
す。
　但し、この機能は各 OS の持つファイルシステムの構造と挙動を
解析した上での機能なので、未解析のファイルシステムについては
ディレクトリ書込み機能は使えません。
　解析済のファイルシステムであるかどうかは、各ファイルシステ
ムのマウント情報からファイルシステムタイプを示す文字列を参照
し、その文字列から判断しています。
　FDclone でディレクトリ書込み機能をサポートしているファイル
システムは以下のとおりです。

	4.3	NEWS-OS 3,4.x
	4.2	SunOS 4.x
	ufs	SVR4, OSF/1, FreeBSD, NetBSD
	ffs	NetBSD, OpenBSD
	hfs	HP-UX, HI-UX
	ext2	Linux
	ext3	Linux
	jfs	AIX
	efs	IRIX		(SGI 独自仕様)
	sysv	SVR3		(SystemV Rel.3 仕様)
	dg/ux	DG/UX		(SystemV Rel.3 仕様)

　これ以外の文字列で示されるタイプのファイルシステムでは、残
念ながらディレクトリ書込み機能を用いることはできません。
　もう少し正確に言うならば、上記以外のファイルシステムでも、
ディレクトリ書込みができる可能性がありますが、未確認のため安
全策をとって、ツールの機能としては殺してあります。

　もし、探求心のある方で、自分の持つファイルシステムでディレ
クトリ書込み機能が使えないことを悔しく思うならば、info.c の
中にある writablefs() を書換えてみることをお奨めします。
　ひょっとすると書込みに成功するかも知れませんし、失敗してデ
ィレクトリ内が目茶苦茶になってしまうかも知れません。
　もっと探求心のある方でしたら、自分でファイルシステムの構造
を解析し、ディレクトリ書込みアルゴリズム自体を書換えてみると
良いかも知れません。
　これらの改造の結果、ディレクトリ書込み機能のサポート対象が
増えるようでしたら、是非作者までご一報下さい。次回のリリース
に反映させて頂きます。

　一方、ファイルシステムのタイプとしては書込み機能が使えるは
ずなのに、OS 側の都合によってうまく機能が働かない場合があり
ます。
　例えば ext2/ext3 ファイルシステムでは、dir_index 属性を有
効にしてある場合には書込み機能が一切反映されませんが、それは
tune2fs(8) によりそういう設定にされているためです。
　もしくは、どんなファイルシステムであっても書込みできないよ
うな OS もあるでしょう。
　このような場合には、安全を最優先して、コンパイル時に識別子
UNKNOWNFS を定義しておいて下さい。

(補足) ディレクトリ書込みのアルゴリズム
	1.カレントディレクトリ内にテンポラリディレクトリ (仮
	  に TMP と呼ぶ) を作成。この時、TMP のファイル名は
	  先頭に並べたいファイルのファイル名と同じ長さにして
	  おく。
	2.TMP がディレクトリエントリ内で物理的に先頭にあるか
	  どうかチェック。
	3.TMP 以外の全ファイル (含ディレクトリ) を TMP 下に
	  移動。
	4.もし 2. で先頭になかった場合、TMP の名前をリネーム。
	  これで TMP はエントリ内の先頭にあることが保証され
	  る。
	5.並べたい順に、TMP 内のファイルを一つずつ元に移動。
	  但し、先頭に並べたいファイルだけは残しておく。
	6.ディレクトリのブロックサイズを考慮し、ブロック境界
	  に隙間ができる場合には、短いファイル名のダミーファ
	  イルを作成し隙間を埋める。
	7.ファイル移動が終ったら、TMP の名前をリネーム。これ
	  で TMP はエントリの最後尾にあり、エントリ先頭に空
	  き領域が確保される。
	8.先頭に持って並べたいファイルを TMP 内から元に戻す。
	9.TMP 及び 6. で作成されたダミーファイルを削除。
	10.完了。
註) ディレクトリファイルを直接操作している訳ではないので、デ
    ィレクトリサイズによってはかなり長い時間を要します。


3.ファイルシステム情報

　βテストで一番の難点だったのが、各 OS 毎に異なるファイルシ
ステムに関する情報取得法です。
　大雑把に分類すると、ファイルシステム情報に関して 5 種類、
マウント情報に関して 8 種類の手法を用意してあります。OS によ
っては、このうち複数の手法に対応できるものもあります。

　OS 側で複数の手法が用意されている場合、そのうちどれを用い
るかという難しい問題があります。というのも、手法の選択によっ
ては、その OS では不具合の生じる場合があるからです。
　一般には、1.で列挙されている順に優先順位をつけてもらえば良
いと思いますが、OS によってはこの優先順位は必ずしも正しくは
ないかも知れません。
　最終的には、可能な手法を全部試してみて、その中で最適なもの
を実装後に選択してやるしかないと思います。

　コンパイルすらできなかった場合は、文句なしにそれは選択ミス
です。コンパイルが成功したら、色々なディレクトリパスに対して
INFO_FILESYS (i) コマンドを実行してみて下さい。
　INFO_FILESYS コマンドの出力は、df(1) の出力とほぼ同じです。
丸め誤差を考慮しても明らかにおかしな値が出るようであれば、選
択ミスかも知れません。

　選択ミスによる出力値の異常は、2 つの原因が考えられます。
	1.マウントポイントを取り違えた。
	2.ファイルシステム情報の取得ミス。
　出力情報の中で、「ファイルシステム」や「マウントポイント」
の項目が正しくない場合には、マウント情報取得法に関する選択を
変えてみて下さい。
　また、これらの項目は正しいのに容量が正しくない場合には、フ
ァイルシステム情報に関する選択を変えてみて下さい。

　最悪の場合、どの選択をしても、正しい出力が得られない場合が
あります。その場合は諦めざるを得ません。
　但し、出力に誤りがあったとしても、FDclone の中ではこれらの
情報ミスは致命的な欠陥には結び付きません。INFO_FILESYS コマ
ンド以外には利用されないので、このコマンドさえ使わなければ支
障ありません。

　ただ、どの OS にも正しい情報取得法は用意されているはずです。
それを知っていれば、FDclone にその取得法を実装することが可能
ですので、もし対処法を講じられた場合は、作者までご一報下さい。
次回のリリースに反映します。


4.キーコード

　キーボードからの入力は、一般のキーであればそのキーの刻印の
文字を表す ASCII コードを受信することになりますが、各種機能
キーの場合には、キーボードは ESC で始まるシーケンスを吐きま
す。
　これらのシーケンスと ESC そのものの入力を正しく判断するた
めに、FDclone では ESC 受信後に 360ms 待って、後続の入力コー
ドがなければ ESC そのものの入力と見なしています。
　但し、この数値は作者周辺の環境で色々確認してみた際の値です
ので、絶対的な根拠は何もありません。この値でうまく動かない環
境があるようであれば、machine.h 内で WAITKEYPAD の値を 360ms
より大きい値で定義してみて下さい。

　また、キーシーケンスと実際のキーの対応表として、termcap ま
たは terminfo の記述を参照しています。記述がなかったキーにつ
いては、VT200 互換端末のキーマップをデフォルトとして用います。
　この対応が実際のキーボードの送信コードと合致していない場合、
そのキーの取得ができなくなります。そのような場合には termcap
や terminfo の登録を正しいものに改めることをお奨めします。


5.アーカイブブラウザの登録

　アーカイブブラウザを新規登録する場合には、.fd2rc などにフ
ォーマット文字列を記述する必要があります。ここでは、マニュア
ルに触れられていない具体例についてお話しします。
　フォーマット文字列の書式は下記のようになっています。

	"%n %n %n ... " top bottom

　top, bottom については、ほとんどのアーカイバについては回避
できると思いますので、普通は共に 0 で構いません。両方共に 0
ならば記述を省略することもできます。
　アーカイブファイル情報以外にコピーライト表示などの余計な行
が表示されてしまう場合のみ、それぞれ、先頭行から、最終行から
の削除する行数を数値で指定して下さい。
　また、-i オプションで削除したい行をパターンとして指定する
こともできますし、-e オプションでエラーメッセージを指定して
出力内容に応じてエラー扱いにすることもできます。

　フォーマットを表す文字列は、printf(3) や scanf(3) の書式に
似ているので、C 言語に慣れている人なら特に迷うことはないと思
います。
　面倒なのは、各フィールドが空白文字やタブによって区切られて
いない場合でしょう。一部のアーカイバでは、別々の情報が連続し
て表示されることがあります。
　次の例は、BSD 系の tar による出力例です。

rw-r--r--9999/999  17531 Aug  7 11:50 1995 main.c

　先頭のファイルモードを表す文字列と、その次のユーザ ID を表
す文字列との間に何の区切りもありません。このような場合、ファ
イルモードを表す文字列の長さを明示的に指示してやる必要が生じ
ます。
　この例ですと 9 文字分の長さですので、「%9a」で表せることに
なります。なので、全体のフォーマット文字列は次のようになりま
す。

	"%9a %u/%g %s %m %d %t %y %*f"

　この例では「%9a」の後ろに空白文字を記述していますが、空白
文字は 0 個以上の空白文字またはタブにマッチしますので、この
フォーマット文字列は上記の出力例のように空白文字が無い出力に
もマッチします。
　逆にフォーマット文字列にこの空白文字が無い場合には、出力側
に空白文字が現れた場合にスキップしてくれません。BSD 系の tar
ではユーザ ID が 3 桁に満たない場合に空白を挿入して表示しま
すので、この空白文字が無いとその挿入された空白文字は続く「%u」
フィールドの一部として扱われてしまいます。
　フィールド内に空白文字やタブが含まれていた場合の扱いはフィ
ールドの種類によって異なりますが、後続のフィールド種によって
は空白文字をフィールドに含んでしまうとまずい場合もあります。
　必要のないフィールドでは無視されますが、ファイル名を示すフ
ィールドでは末尾の空白文字のみ無視して残りはファイル名の一部
と見なします。それ以外のフィールドでは、前後の空白のみ無視し
て情報を取得しますが、複数のフォーマット文字列候補があった場
合にはそのフォーマット文字列の優先度を下げてしまいます。
　因みに、この例ではファイル名を示すフィールドの長さが「行末
まで」に指定されていますので、空白文字やタブ文字を含む行末ま
での全ての文字がファイル名と見なされます。


　なお、アーカイバによっては年表示や時刻表示ができなかったり、
これらを兼用していたりするものがあります。以下は LHa による
出力例です。

drwxr-xr-x  9999/999         0 ****** Jun  8 12:04 demo/
-rw-r--r--  9999/999        49 100.0% Dec  8  1994 demo/Makefile

　このように、時刻フィールドと年フィールドが兼用され、タイム
スタンプの古いものでは時刻表示がありません。
　このような場合は、アーカイバブラウザの表示がおかしくなるこ
とを覚悟の上で、{ } を用いて年情報と時刻情報が同じフィールド
であるというように指定します。
　この場合、前者の例では 2012 年という年表示になり、後者の例
では 0:00 という時刻表示 (1994 時という時刻は存在し得ないた
め) になります。
　以下にこの場合のフォーマット文字列を記しておきます。

	"%a %u/%g %s %x %m %d %{yt} %*f"


　このように、アーカイバの出力形式は環境によって異なりますの
で、どの環境でも同様にアーカイブブラウザを使えるようにしてお
くためには、-f オプションを用いて複数のフォーマット文字列を
登録しておくと良いでしょう。
　tar や LHa のように比較的一般的に利用されているアーカイバ
に関しては、幾つかの異なるフォーマット文字列を標準で予め用意
してありますが、それ以外のアーカイバについては、各ユーザ側で
調べて登録しておいて下さい。
　但し、複数のフォーマット文字列が登録されている場合には、記
述された順に比較が行われますので、記述順に注意して下さい。例
えば、"%*f" のように一行丸ごとをファイル名と見なさせるような
フォーマット文字列は、どんな出力行にも完全にマッチしてしまい
ますので、これ以降に記述されたフォーマット文字列が比較対象と
なることはあり得ません。


6.フロッピードライブの登録

　システムに付属のフロッピーディスクドライブ内の MS-DOS フォ
ーマットのフロッピーを、FDclone 上から一般のファイルシステム
と同様に扱うためには、.fd2rc などにそのドライブを登録してや
る必要があります。
　この登録のためには、まずフロッピーディスクドライブ用のドラ
イバが OS に組み込まれていることと、そのドライバアクセス用の
インタフェースがスペシャルファイルとして用意されていることが
必要です。
　詳細は OS によって異なりますが、fd(4) のマニュアルに詳しく
書かれている場合が多いようです。

　一般的な例ですが、一つの物理的なドライブに対し、複数のフォ
ーマットが対応されているケースが多いようです。この複数のフォ
ーマットは、自動識別される場合もありますし、スペシャルファイ
ル名によって分類されている場合もあります。
　前者の場合、ドライブ登録行のデバイスファイルには同じスペシ
ャルファイル名を記し、フォーマットのパラメータでそれぞれを区
別させます。
　後者の場合、ドライブ名は同じでもデバイスファイルにはそれぞ
れのフォーマットに応じたスペシャルファイル名を記しておく必要
があります。
　また、ここでは選ぶデバイスファイルは、できるだけ raw デバ
イスにしておいた方が良いでしょう。

　以下は SPARCsystems と NWS-3400シリーズの内蔵ドライブに関
する設定例です。

SPARC:
	A:	"/dev/rfd0c"	2  18 80	(1440KB	2HD)
	A:	"/dev/rfd0c"	2   9 80	(720KB	2DD)
	A:	"/dev/rfd0c"	2 108 80	(640KB	2DD)

NWS-3400:
	A:	"/dev/rfd00a"	2  18 80	(1440KB	2HD)
	A:	"/dev/rfd01a"	2   9 80	(720KB	2DD)
	A:	"/dev/rfd03a"	2   8 80	(640KB	2DD)

　これらの設定は、OS が同じでもマシンや構成が異なればそれに
依存しますので、コンパイル時の組込みで行なうよりも、共通設定
ファイルで行なった方がいいかも知れません。
　逆に、完成された FDclone のバイナリを使う可能性のあるマシ
ンがそれ一台だけであるならば、組込みでコンパイルしてしまう手
も有効です。
　組込みでコンパイルしたい場合は、dosdisk.c の中にある fdtype
という構造体配列の値を書き換えます。設定する要素は、.fd2rc
等での登録と全く同じです。
　但し、ドライブ名は "A:" といった文字列でなく、アルファベッ
ト 1 文字で表します。ここでは、必ず大文字にしておいて下さい。

　どのスペシャルファイルが、どのドライブのどういうフォーマッ
トを指しているかは、OS や機種に完全に依存しますので、各マニ
ュアルを参照するか、メーカに直接質問して下さい。
　配布パッケージでは、標準的な機種の内蔵ドライブに対する設定
を組込みで行なうようにしてありますが、これはインストールする
人間の判断で変更して下さい。

　尚、MS-DOS のファイル名に関する制限によるコンバートは、以
下のルールによって行なわれます。これは、BSD on Windows の仕
様と同じにしてあります。
	1.ファイル名が 8+3 文字を越える部分は削除。
	2.行頭または 2 つ目以降の . は $ に変更。
	3.任意の + は ` に変更。
	4.任意の , は ' に変更。
	5.任意の [ は & に変更。
　フロッピードライブのファイル名を FDclone から見る場合には、
上記 2-5 の逆変換が行なわれます。
　但し、ドライブ名に小文字を指定し LFN アクセスしている時に
はこのルールは使われません。新規ファイル作成時に作られる SFN
は Windows95/98 のファイル名生成規則に従います。


　また、PC-UNIX ではフロッピーディスクドライブと同様にハード
ディスクドライブの登録もできます。登録方法は、マニュアルにあ
るとおり、ヘッド数等の項目値の代わりに "HDD" または "HDD98"
という文字列を記します。
　この時指定するスペシャルファイルは、各パーティション (スラ
イス) 別に分割されたものではなく、物理ドライブ装置単位に用意
されているものを指定します。
　以下に、代表的な PC-UNIX について、この物理ドライブ装置単
位のスペシャルファイル名を挙げておきます。二台目以降の装置で
は、下記ファイル名の '0' または 'a' の部分が '1' または 'b'
以降の文字になります。(Solaris では 'd' に続く '0')
	Solaris	/dev/rdsk/c0d0p0 (IDE)	/dev/rdsk/c0t1d0p0 (SCSI)
	Linux	/dev/hda (IDE)		/dev/sda (SCSI)
	FreeBSD	/dev/rwd0 (IDE)		/dev/rsd0 (SCSI)
	 または	/dev/rad0 (IDE)		/dev/rda0 (SCSI)
	NetBSD	/dev/rwd0d (IDE)	/dev/rsd0d (SCSI)
	OpenBSD	/dev/rwd0c (IDE)	/dev/rsd0c (SCSI)


7.関数

　sh(1) の関数定義と同じです。確認のため、Ver. 1.x の関数実
装との違いを列挙しておきます。
	1.'\' を用いなくても複数行に分けて記述できる。
	2.コマンド文字列の行頭になくても関数と見なされる。
	3.パイプやリダイレクト等と併用できる。
	4.関数定義内の引数にパラメータマクロを用いることがで
	  きない。
　1.-3. は FDclone をシェル化した結果実現されましたが、その
弊害で 4. の FDclone ならではの拡張機能が失われてしまいまし
た。
　そこで Ver. 2.00 以降では evalmacro という組込みコマンドを
用意し、関数内では明示的にマクロ展開を行なわせてから実行する
という手法により、パラメータマクロを用いることを可能にしてい
ます。

　パラメータマクロを用いることの利点は、主に選択ファイル名を
引数に用いることができることにあると思っています。
　この機能を一番発揮できる例として、ワイルドカードを用いて検
索したファイル名に対し、何らかのコマンドを適用する関数を考え
てみましょう。

	delete() {
		MARK_FIND $1
		DELETE_FILE
	}

　使用例としては、「delete '*.bak'」などとしてやれば、カレン
トディレクトリ内の拡張子「.bak」を持つファイルが全て消去され
ます。
　'' で括らないと、関数 delete に引数が渡る前に「*.bak」が展
開されてしまうので気をつけましょう。

　このケースでは、コマンドラインの引数である「*.bak」が位置
パラメータ $1 に代入されるので、1 行目は「MARK_FIND *.bak」
と展開されます。
　2 行目の DELETE_FILE は引数を取らず、選択ファイルがあれば
全て削除するコマンドですので、1 行目で選択された「*.bak」の
ファイルが全て削除されます。
　ここで気をつけなくてはならないのは、1 行目で「*.bak」にマ
ッチするファイル名が一つもなかった場合、DELETE_FILE の対象と
なるファイルが選択されないので、対象がカーソル位置のファイル
となってしまう点です。
　尤も、DELETE_FILE は削除に先だって確認を聞いてきますので、
その時点で気づきますし、予めカーソル位置を DELETE_FILE では
消せないファイル、例えば「..」の位置に置いておけば安全です。
　因みに、この関数 delete は、引数をつけずにコマンドラインか
ら実行した場合、MARK_FIND のデフォルトの動作、つまりワイルド
カード文字列の入力要求をしてきますので、対話的に削除という形
式になります。

　では、もう少し複雑なケースを見てみましょう。

	rename() {
		MARK_ALL 0
		MARK_FIND $1
		evalmacro mv %%M $2
	}

　これは、指定のファイル名を一括してリネームする関数です。今
度は念を入れて 1 行目にマークのクリアを入れてみました。仕様
上、MARK_FIND は既存のマークを消さずに選択していきます。
　リネームですから、3 行目は RENAME_FILE を用いれば良いよう
にも思えますが、実は無理なのです。というのも、RENAME_FILE に
はカーソル位置のファイル名の変更という仕様しかなく、選択ファ
イルを連続してリネームする機能はないからです。
　そこで、UNIX 標準コマンドである mv(1) を用います。連続実行
には、mv(1) の機能ではなく、パラメータマクロの機能を用います。
これが 3 行目の %M です。

　例えば、コマンドラインから「rename '*.c' '%XM.c.bak'」と入
力すると、拡張子「.c」を持つファイルが全て「.c.bak」という拡
張子に置き換わります。
　'' をつけないと、関数 rename に引数が渡る前に「*.c」や「%XM」
が展開されてしまうので気をつけましょう。

　この例では $1="*.c", $2="%XM.c.bak" ですから、3 行目を展開
すると「mv %M %XM.c.bak」です。%M は選択ファイル名が順々に展
開されていくパラメータマクロ、%XM はその拡張子を取ったもので
す。
　2 行目で「*.c」を選択していますから、3 行目ではその選択フ
ァイルを逐一「*.c.bak」という形にリネームしていくという寸法
です。

　ここで注意すべき点は、関数定義の際にパラメータマクロ「%M」
を「%%M」と記述している点です。
　仕様上、初期設定ファイルや source コマンドの入力ファイル中
では、関数内と同様パラメータマクロは評価されませんので、この
部分の記述は「%M」で構いません。
　しかし、この関数定義を EXECUTE_SH のコマンドラインから行な
う場合は、「%M」のままだとこのパラメータマクロを評価した後で
関数定義を行なってしまいます。
　そこで、パラメータマクロ評価後に「%M」となるような文字列と
して「%%M」を指定する訳です。
　関数の引数の場合と同様に「'%M'」としても確かに「%M」は未評
価になるのですが、関数定義時には「'」を評価しないため「'%M'」
のまま定義されてしまい、期待した動作にはなりません。
　EXECUTE_SH から関数定義を行なう場合はこのように厄介な問題
が伴いますので、初期設定ファイルや source コマンドの入力ファ
イル、もしくは fdsh (EXECUTE_SH で空行を入力することで起動)
で定義すると無難でしょう。

　MARK_FIND と組合わせるこの用法は、どことなく RISC プログラ
ミングを彷彿とさせるものがあり、なかなかに理解しにくいものだ
とは思います。
　しかし、単にコマンド列挙だけならばエイリアスでもできること
で、関数としての機能を十分に使いこなそうと思えば、こういった
使い方を知っておいた方が良いでしょう。


8.コンパイル時の機能制限

　コンパイル時に、以下の識別子を定義しておくと、それぞれの機
能を実装しない実行ファイルを作ることができます。

	_NOARCHIVE	アーカイヴブラウザが使用不能
	_NODOSDRIVE	MS-DOS フロッピーがアクセス不能
	_NOUSELFN	LongFileName が使用不能 (MS-DOS 版)
	_NOTREE		ツリー表示画面が使用不能
	_NOROCKRIDGE	疑似 RockRidge 拡張機能が使用不能
	_NOCOMPLETE	ファイル名補完機能が使用不能
	_NOWRITEFS	ディレクトリ書込み機能が使用不能
	_NOEDITMODE	編集モードの代替キー機能が使用不能
	_NOKANJICONV	漢字コードが動的に変更不能
	_NOKANJIFCONV	filename の漢字コードが動的に変更不能
	_NOUNICODE	UNICODE の対応不能
	_NOENGMES	英語メッセージが表示不能
	_NOJPNMES	日本語メッセージが表示不能
	_NOCOLOR	カラー表示機能が使用不能
	_NOKEYMAP	keymap, getkey 組込みコマンドが使用不能
	_NOORIGSHELL	内蔵シェルが使用不能
	_NOUSEHASH	コマンドパス検索用ハッシュ関数が使用不能
	_NOORIGGLOB	filename globbing に正規表現ライブラリ関数を使用
	_NOSPLITWIN	ウィンドウ分割機能が使用不能
	_NOPRECEDE	先行ファイル表示機能が使用不能
	_NOCUSTOMIZE	カスタマイザ機能が使用不能
	_NOEXTRACOPY	強化されたコピー機能が使用不能
	_NOBROWSE	組込みコマンド browse が使用不能
	_NOEXTRAMACRO	%T, %M マクロがステートメント中で使用不能
	_NOTRADLAYOUT	オリジナル版『ＦＤ』準拠の画面レイアウトが使用不能
	_NODOSCOMMAND	UNIX 版で COMMAND.COM 内蔵コマンドが使用不能
	_NOEXTRAWIN	各分割ウィンドウのサイズが変更不能
	_NOPTY		疑似端末機能が使用不能
	_NOEXTRAATTR	ファイル属性変更コマンドの拡張機能が使用不能
	_NOLOGGING	ログファイル機能が使用不能
	_NOIME		簡易日本語 IME 機能が使用不能
	_NOCATALOG	メッセージカタログ機能が使用不能
	_NODYNAMICLIST	各種設定登録数の制限が不能
	_NOSOCKET	ソケットを用いたネットワーク機能が使用不能
	_NOSOCKREDIR	ソケットを用いたリダイレクト機能が使用不能
	_NOFTP		FTP 接続機能が使用不能
	_NOHTTP		HTTP 接続機能が使用不能
	_NOUNICDTBL	fd-unicd.tbl が使用不能 (代わりに埋込み)
	_NODICTTBL	fd-dict.tbl が使用不能 (代わりに埋込み)

　config.hin を編集してこれらの識別子の定義を追加しておけば、
機能を縮小してサイズを小さくしたり、エンドユーザに使用させた
くない機能を抑制したりできます。


9.PC-UNIX でのフロッピードライブの同期

　フロッピードライブ機能では、ディスクアクセスの高速化を図る
ためにキャッシュメモリを用いています。
　連続して同じ箇所のディスクアクセスを行なおうとすると、二回
目以降は実際のディスクアクセスの代わりにキャッシュメモリに保
存されているものを参照します。
　このため、FDclone 以外のプロセスがこのディスクに同時にアク
セスすると、一時的に双方で内容が異なってしまうことがあります。
　多くの PC-UNIX には、MS-DOS ファイルシステムを mount して
直接アクセスする機能が用意されており、この機能を用いて見た内
容とフロッピードライブの内容は同期しません。

　MS-DOS ファイルシステム側で書込みを行なうと、まずファイル
システム側のキャッシュメモリに書込まれ、これより後のタイミン
グで実際のディスク書込みが行なわれます。
　また、実際のディスク書込みが行なわれた後も、FDclone 側では
そういう書込みのあった事実を察知できないので、FDclone 側のキ
ャッシュを読みに行っている間は古い情報を参照し続けます。
　ファイルシステム側のキャッシュメモリの内容を実際のディスク
に反映するには、sync(2) システムコールの発行を行なうことによ
り実現されます。
　ディスクの内容をフロッピードライブ側のキャッシュメモリに反
映するには、フロッピードライブの再オープンまたは REREAD_DIR
コマンドにより実現されます。
　また、REREAD_DIR コマンドでは、フロッピードライブ機能を使
用している場合に限り、sync(2) の発行を行なっているので、同時
に双方の同期を取ることができます。

　フロッピードライブ側で書込みを行なうと、まず FDclone 側の
キャッシュメモリに書込まれ、これより後のタイミングで実際のデ
ィスク書込みが行なわれます。
　また、一般にファイルシステムはバッファリングしながらディス
クアクセスを行ないますので、フロッピードライブ側で実際のディ
スク書込みが行なわれた後も、その該当箇所がファイルシステムの
キャッシュバッファにあれば、バッファ内の古い情報を参照し続け
ます。
　フロッピードライブのクローズまたは REREAD_DIR コマンドによ
り、FDclone 側のキャッシュメモリと実際のディスクの内容とは同
期が取られますが、MS-DOS ファイルシステムの側では更新されな
い場合もあります。
　この場合には、フロッピードライブのクローズまたは REREAD_DIR
コマンドの実行後、一旦 MS-DOS ファイルシステムを umount し、
再度 mount し直すことで確実に内容が更新されます。


　但し、Linux の場合は状況はこの限りではありません。Linux に
は raw デバイスを持たないという特殊事情があるためです。

　Linux 以外の OS では、フロッピードライブ機能の設定の際に使
うデバイス名に raw デバイスを選ぶことで、FDclone がデバイス
に対しアクセスを行なうと同時に実際のディスクアクセスを行なわ
せることができます。
　しかし、Linux には raw デバイスがなく、デバイス自体がバッ
ファー経由でディスクアクセスしているため、この同期を実現させ
ることができません。

　まず、フロッピードライブに対する書込みですが、sync(2) の発
行によりフロッピードライブで書込んだバッファとファイルシステ
ム側の読込みバッファが共に実際のディスクに書込まれます。
　このため、フロッピードライブで幾ら更新しても、ファイルシス
テム側のバッファにより常に上書きされてしまうので、更新が反映
されません。
　この回避策として、Linux ではフロッピードライブのオープン時
にファイルシステムとして mount されていた場合は読取り専用と
して扱うことにしています。

　また、フロッピードライブからの読込みですが、こちらの方は同
期を実現する権限が root にしかないため、一般ユーザは実際のデ
ィスクの内容を知る術を持ちません。
　このため、MS-DOS ファイルシステム側で書込んだ内容をフロッ
ピードライブ側で参照するためには、フロッピードライブ側での書
込みと同様に、一旦 MS-DOS ファイルシステムを umount してやる
必要があります。
　ところが、ディスクがフロッピーのようにリムーバルメディアで
あった場合にはデバイスバッファーは umount により破棄されるの
ですが、ハードディスクのように固定メディアの場合には umount
しても破棄されない仕様になっています。
　これを破棄させるには、root 権限でその指示をする以外に術は
ありません。
　フロッピードライブのオープン及び REREAD_DIR コマンドでは、
root 権限で起動されている場合に限りこの Linux バッファー破棄
命令を発行しています。
　Linux 上でどうしても同期を取りたい場合は、一旦 root 権限で
FDclone を起動し、フロッピードライブ機能を使って下さい。


　尤も、この同期問題の根本的問題点は、一つのディスク媒体を複
数の手法でアクセスすることにあるので、異なる手法で同時にアク
セスしないという運用による回避が一番望ましいと思います。
　フロッピードライブ機能を用いている間は、対応する MS-DOS フ
ァイルシステムを umount しておくか、もしくは他のユーザやプロ
セスがアクセスしないよう気をつけるなど、運用上の工夫で何とか
カバーして下さい。


10.組込みコマンド browse

　マニュアルでは仕様についてしか記述されていませんので、ここ
では実例を示しながら組込みコマンド browse の使いかたを解説し
ていきます。

　browse コマンドの基本は、まずブラウザを起動し、その中のフ
ァイルを選択すると次のブラウザを起動し、といった具合に再帰的
にブラウザを起動することにあります。
　例えば簡単な例で、指定した年月のカレンダーを表示するような
browse コマンドを紹介しましょう。
	browse \
	'for i in 0 1 2 3 4 5 6 7 8 9; do echo 200$i; done' \
	-f "%f" \
	'for i in 1 2 3 4 5 6 7 8 9 10 11 12; do echo $i; done' \
	-f "%f" \
	'cal $1 $2%K'

　わかり易いように引数を行単位で区切って書いていますので、行
末に「\」がついていますが、これらは一つのコマンド行ですので、
本来は一行で記述されるべきものです。
　1 行目はコマンド名です。2 行目は「2000」から「2009」までの
文字列を一行ずつ表示させるコマンドマクロです。シェルの文法は
ここでは触れませんので、この記述でそうなるものだと理解して下
さい。
　3 行目はアーカイブブラウザ用のフォーマットです。この 2 行
目によって出力される結果はタイムスタンプやファイルサイズ等の
情報を含んでいませんから、ファイル名を示す「%f」だけを指定し
ています。
　この記述により、「2000」から「2009」までのファイル名を画面
に一覧表示し、その中から一ファイルを選ばせるようなブラウザが
構築されます。

　このうちいずれかのファイルを選択すると、4 行目の次のコマン
ドが実行されます。これは「1」から「12」までの文字列を一行ず
つ表示させるコマンドマクロです。
　5 行目は先と同様に、出力結果からファイル名要素だけを抽出す
るように指示したアーカイブブラウザ用フォーマットです。この結
果、「1」から「12」までの中からいずれかを選ばせるようなブラ
ウザが構築されます。

　6 行目は外部コマンド cal を実行させています。$1, $2 といっ
た位置パラメータにはこれまで選択してきたファイル名が保存され
ていますので、それぞれ「1」から「12」までのいずれか、「2000」
から「2009」までのいずれかが保存されます。
　このコマンドには -f オプションが付属していませんので、ここ
ではこの出力は単に画面に表示されて終わりです。そのまま終わっ
てしまったのでは出力を読む暇がありませんので、「%K」マクロを
つけてキー入力待ちをさせています。

　総合的に見ると、このコマンドは
	1. まず年を選択する。
	2. 次に月を選択する。
	3. 選択された年月のカレンダーを表示する。
という構成のブラウザになっています。


　では次はもう少し複雑な例を見てみましょう。
	browse \
	'echo "host1
	host2
	host3"' \
	-f "%f" \
	-p 'RHOST=$1; RPATH=' \
	'rsh $RHOST "ls -lag $RPATH"' \
	-f "%a %l %u %g %s %m %d %{yt} %*f" \
	-i "total *" \
	-p 'RPATH=$1; while [ "$#" -gt 2 ]; do shift; RPATH=$1/$RPATH; done' \
	-d loop \
	'rcp $RHOST:$RPATH ./${RPATH##*/}'

　1 行目はコマンド名です。2-4 行目は「host1」「host2」「host3」
を一行ずつ表示させます。5 行目はフォーマットです。ここまでは
上の例と大差ないでしょう。
　6 行目の -p オプションは少し特殊な働きをします。いすれかの
ファイルを選択すると次の選択に移るはずですが、ここではその前
に「RHOST=$1; RPATH=」というコマンドを実行させるように指定し
ています。
　これは選択したファイル名を「RHOST」内部変数に代入し「RPATH」
内部変数の値を空にさせるコマンドです。ファイルを選択すると次
の段階のコマンドが実行されるので、その中で記述すれば十分のよ
うにも思えますが、そうしないのには二つの意味があります。
　一つには次の段階ではループが発生しているからですが、これは
後述します。もう一つには、出力をアーカイブブラウザ用に使って
しまうコマンドの中で内部変数を定義しても、その内容は後に残ら
ないからです。
　一般に、「|」を用いたシェルのパイプラインは子プロセスで実
行され、子プロセスで変更された各種設定値は親プロセスには影響
を及ぼしません。
　勿論、カレントプロセスで実行した出力結果をアーカイブブラウ
ザに渡すような実装にすることも可能ですが、ここではそういう仕
様にはしてありません。そういうものだと思って下さい。

　さて、いずれかの「host?」を選ぶと次の選択に進みます。ここ
では 7 行目のコマンドが実行されます。
　先に -p オプションで設定された内部変数が早速使われています。
外部コマンド rsh では、第一引数にリモートホスト名を、第二引
数にリモートホスト上で実行するコマンド文字列をそれぞれ記述し
ます。
　「RPATH」の内容は空なので、ここでは選択されたホスト上で、
「ls -lag」を実行させることになります。8 行目のフォーマット
は ls の出力形式を表しています。
　9 行目の -i オプションは ls の出力の中から無視させたい文字
列を選んでいます。「ls -lag」は先頭行に「total 123」のように
全容量を表示させてしまうので、それを無視するように指定してい
ます。
　10 行目では先と同様に内部変数の値を設定しています。ややこ
しいことを書いてあるように見えますが、結局は内部変数「RPATH」
の値は「.../$3/$2/$1」になります。
　「[ "$#" -gt 2 ]」という条件がついているので、一番最後の位
置パラメータはこの中に含まれません。一番最後の位置パラメータ
には一番最初に選択されたファイル名が保存されているので、この
場合はホスト名ですね。
　11 行目では「選択されたファイルがディレクトリだったら、次
に進まずに先と同じコマンドを実行する」という指定をしています。
ディレクトリの選択に対しては、何度でも rsh を実行することに
なります。
　結局、ディレクトリが選択され続ける限りは、その名前を内部変
数「RPATH」に追加していって、その内容に対して ls を実行する
という作業を繰り返すことになります。
　ここでループが生じているので、先の「RHOST」「RPATH」の初期
化は -p オプションで記述する必要があったのです。

　では、ディレクトリ以外を選択した場合はどうなるでしょう。デ
ィレクトリ以外に対してループは指定されていないので、次の 12
行目に進むことになります。
　外部コマンド rcp では、第一引数にコピー元のファイル名を、
第二引数にコピー先のファイル名をそれぞれ記述します。各々のフ
ァイル名の頭に「ホスト名:」をつけると、リモートホストのファ
イルであることを意味します。
　12 行目の実行に先だって 10 行目の -p オプションで指定され
たコマンドが実行されていますので、内部変数「RPATH」には選択
されたファイルのフルパス名が保存されています。
　また、「${RPATH##*/}」という記述はこのフルパス名の中から最
後の要素のみを抽出しますので、結局この記述では、選択されたホ
スト上の選択されたファイルを、ローカルのカレントディレクトリ
に同じ名前でコピーすることになります。

　総合的に見ると、このコマンドは
	1. まずホスト名を選択する。
	2. 次にディレクトリを再帰的に選択する。
	3. 最後にファイル名を選択する。
	4. 選択されたリモートホストから、選択されたディレク
	   トリの選択されたファイルをローカルのカレントディ
	   レクトリにコピーする。
という構成のブラウザになっています。
　先のカレンダーの例と比べると随分ブラウザらしくなっていると
思います。似たような構成の例が _fdrc の getftp() という関数
定義にありますので、気が向いたらこちらも紐解いてみて下さい。


　さて、ブラウジングするからにはディレクトリの下を一方的に掘
り進んで行くだけでは困ります。上のディレクトリに戻ったり別の
ディレクトリに入り直したり、そういう出入りが不可欠です。
　組込みコマンド browse で構築されたブラウザでは、マニュアル
にも書かれているとおり、「..」というファイル名が特殊な扱いに
なっています。これは一般のブラウザでも同じことです。
　「..」は親ディレクトリを表すファイル名であることが明確なの
で、アーカイブブラウザに渡された出力の中に「..」が現れなかっ
たとしても「戻るためのファイル名」として用いられます。一覧に
「..」が無くても [Bs] キーを押すか LOG_DIR コマンドで「..」
を選ぶかすれば上のディレクトリに戻れます。
　この場合、「..」は無条件にディレクトリなので -d オプション
の指示に従います。上の例では rcp に進まずに rsh を実行し続け
ます。
　また、-d noprep されない限りは -p オプションで指定されたコ
マンドを実行しますので、上の例では「RPATH」の値も設定されま
す。
　[Bs] キーを押した場合も「..」を選んだこととして扱われるの
で、$1 には「..」が保存されています。なので、「RPATH」には常
にカレントディレクトリ名が保存されていることになります。

　良く見ると 10 行目の -p オプションの中で shift を実行して
いますので、位置パラメータは全部無くなってしまうようにも思え
ますが、マニュアルにもあるとおり、この位置パラメータはファイ
ル選択時にまとめて設定されますので、shift しようが組込みコマ
ンド set で他の値に設定しようが、次のファイル選択時には元に
戻っています。
　但し、-p オプションのコマンドが実行されてから次のアーカイ
ブブラウザ用コマンドが実行されるまでの間にはファイル選択があ
りませんから、-p オプションで消されてしまった位置パラメータ
は次のアーカイブブラウザ用コマンドの中では参照できないことに
注意して下さい。


　最後に一つ重要な注意点に言及しておきます。例にある rsh や
ftp のような外部コマンドを用いた場合、その出力形式は OS や環
境によって異なるという点です。

　一般のアーカイブブラウザでも、外部コマンドである各種アーカ
イバの出力が同様に環境依存であるため、組込みコマンド launch
では -f オプションを用いて複数のフォーマット文字列を登録して
おく必要があります。
　これと同様のことが組込みコマンド browse に関しても言える訳
ですが、単一の環境には単一の実装しか存在しないアーカイバコマ
ンドと異なり、rsh や ftp のようなネットワークを利用したコマ
ンドでは、単一の環境しか用いない場合でも、リモートホストが異
なるだけで全く異なる出力形式になってしまいます。
　上記の例では割と一般的な出力形式に対するフォーマット文字列
を示しましたが、実用に堪えられるようにするためには、もっと多
種多様なリモートホストに対応できるようにするため、フォーマッ
ト文字列は複数登録しておくべきでしょう。
　同様に、-i オプションや -e オプションも複数登録しておくと
良いでしょう。


11.かな漢字変換辞書

　標準状態では、同梱の mktankan.c が単漢字変換用のテキスト辞
書を作成し、これを元にかな漢字変換辞書 fd-dict.tbl が作成さ
れます。
　この状態では、fd-dict.tbl は品詞情報を含んでいませんので、
これをそのまま用いる限りは、かな漢字変換入力モードでは単漢字
変換しかできません。
　内蔵の変換エンジンは品詞情報を元にした単文節変換に対応して
いますので、品詞情報を含むテキスト辞書を別途用意してやれば、
かな漢字変換入力モードで単文節変換を行なうことができます。

　対応している辞書形式は pubdic 形式です。また、Wnn、Canna、
SJ3 の辞書をテキスト変換したものも使うことができます。
　これらの辞書をコンパイル時に Makefile.in の DICTSRC に記述
することで、かな漢字変換辞書 fd-dict.tbl がこれらの辞書に基
づくものになります。

　DICTSRC に記述する際は、絶対パスもしくはコンパイルするディ
レクトリからの相対パスで辞書ファイル名を記述して下さい。勿論、
同じディレクトリに置いた場合はファイル名のみの記述で構いませ
ん。
　複数の辞書ファイルを記述する場合は、空白で区切って列挙して
下さい。但し、実行時にそれらの辞書を使い分けることはできない
ので、全ての辞書から変換候補が選ばれます。
　また、辞書が一つしかない場合は、「make DICTSRC=./pubdic.p」
のように make のコマンドラインから指定しても構いません。

　一旦コンパイルを実行してしまった後に辞書指定を変更する場合
は、先に作成されている fd-dict.tbl を削除してからコンパイル
する必要があります。
　この場合は「make rmdict」を実行して下さい。他のコンパイル
結果を保持したまま辞書関連のファイルだけを削除します。


12.メッセージカタログ

　標準状態では、同梱の mkcat.c が kanji.hin に書かれたメッセ
ージ文字列を元に、日本語用メッセージカタログ fd-cat.ja 及び
英語用メッセージカタログ fd-cat.C を作成します。
　これらのメッセージカタログが fd の起動ディレクトリにある場
合、その拡張子文字列を内部変数 MESSAGELANG に設定することで、
表示メッセージをそのカタログの内容に置換えられます。

　独自のメッセージカタログを使用したい場合は、標準のメッセー
ジを編集して新しいメッセージカタログを作成して下さい。
　コンパイルの過程で _fd-cat.ja 及び _fd-cat.C というテキス
トファイルが自動生成されます。これらがそれぞれのメッセージカ
タログのソースファイルになっています。
　但し、これらのソースファイルは Shift JIS または EUC 漢字で
記述する必要があります。識別子 CODEEUC が設定されている環境
では EUC 漢字、それ以外では Shift JIS です。
　シングルバイト文字のメッセージカタログを作成する場合は漢字
コードを特に気にする必要はありません。日本語以外のマルチバイ
ト文字のメッセージカタログは現在非対応です。

　メッセージカタログの生成には mkcat.c を用います。ここでは
仮に _fd-cat.fr をソースに使って fd-cat.fr を生成する手順を
示します。
　コンパイルを実行したディレクトリで以下のコマンドを実行して
下さい。生成された fd-cat.fr を fd の起動ディレクトリにコピ
ーすれば、追加のメッセージカタログとして使用可能です。
	./mkcat _fd-cat.fr fd-cat.fr

　但し、コンパイル前に識別子 USEDATADIR を定義してある場合は
注意が必要です。
　この場合、メッセージカタログは fd の起動ディレクトリではな
く Makefile.in の DATADIR で指定されたディレクトリに置く必要
があります。
　DATADIR の直下に fd のバージョン番号毎にディレクトリを作成
してその下にコピーします。例えば DATADIR=/fd でバージョンが
3.00 だとすると、ディレクトリ名は /fd/3.00 になります。
　このメッセージカタログ用ディレクトリは、インストール時に自
動的に作成されるので、先に一旦インストールを実行しておくと良
いでしょう。
