Museum

Home

Lab Overview

Retrotechnology Articles

Online Manuals

⇒ mh-format(n) — NEWS-os 4.1C

Media Vault

Software Library

Restoration Projects

Artifacts Sought

Related Articles

scan(1)

repl(1)

ap(8)

dp(8)

 

名称

mh−format − MH メッセージシステムのためのフォーマットファイル

形式

いくつかの MH コマンド

解説

いくつかの MH コマンドは、 その実行中にフォーマット文字列またはフォーマットファイルを利用します。 例えば scan(1) は、 各メッセージについてどのようにスキャンリスティングを作成するかを 指示するフォーマット文字列を使い、 repl(1) ではメッセージに対してどのように返信を出すかを 指示するフォーマットファイルを使います。
 
フォーマット文字列は、MH により効率よく解析されるように設計されています。 これはフォーマット文字列が、書いたり理解したりするのに、 必ずしも容易ではないことを意味します。 従って、初心者や一般的な利用者だけでなく、熟練した MH ユーザ においても、これを取り扱う必要はありません。
 
scan コマンド用のフォーマットの例が /usr/new/lib/mh/scan.time, /usr/new/lib/mh/scan.size および /usr/new/lib/mh/scan.timely にあります。 /usr/new/lib/mh に、その他の scan, repl フォーマットファイルが 各サイトによって記述されるでしょうから、参照してください。 これは、ローカルな MH エキスパートが 実際に新しいフォーマットのコマンドを書いたり、 既存のものを修正したりするのに十分なものです。 この章ではそのやり方について説明します。
注: C言語の printf 関数について熟知している必要があります。
 
フォーマット文字列は普通のテキストと、‘%’ で始まる 特殊な複数文字エスケープシーケンスで構成されます。 フォーマット文字列を指定する時には、 C言語で通常用いられるバックスラッシュ文字 : ‘\b’、‘\f’、‘\n’、‘\r’、‘\t’ が使えます。 フォーマットファイル中で行を継続する場合は、行末に ‘\’ を置きます。
 
エスケープシーケンスには、 ヘッダーのコンポーネント、組み込み関数、 およびフローコントロールの3つのタイプがあります。 コンポーネントエスケープは、‘%{component}’ というように 指定し、メッセージ中の各ヘッダを表します。 例えば、‘%{date}’ はメッセージの “Date:” フィールドを参照します。 コンポーネントエスケープは全て文字列の値を持ちます。 通常、コンポーネント中のコントロールキャラクタ(タブ、改行を含む)は いったんスペースに変換され、 次に、先行するあるいは連続するスペースを省略することで、圧縮されます。 コマンドによっては、いくつかのコンポーネントについて解釈が違う場合が ありますので、詳細については各コマンドのマニュアルを参照してください。
 
関数エスケープは ‘%(function)’ という形で指定されます。 関数は全て組み込みであり、殆どが文字列あるいは数値を返します。 コントロールエスケープは、‘%<escape’、‘%|’、‘%>’ のうちの一つです。 これらを用いて、次の4とおりの条件制御構造が表現できます。

%<(function)Command-String%>
%<{component}Command-String%>
%<(function)Then-Command-String%|Else-Command-String%>
%<{component}Then-Command-String%|Else-Command-String%>

これらの制御構造は、曖昧でなければネストして構いません。 初めの2つの制御構造では、関数あるいはコンポーネントの値が ゼロでない(整数値エスケープの場合)もしくは 空でない(文字列エスケープの場合)ならば、 対応する ‘%>’ までの Command-String が全て解釈されます。 さもなければ対応する ‘%>’ までをスキップして、解釈を再開します。 次の2つの制御構造では、関数あるいはコンポーネントの値が ゼロでないもしくは空でないならば、 最初のコマンド文字列 Then-Command-String が解釈され、 そうでなければ2番目のコマンド文字列 Else-Command-String が解釈されます。 解釈されるコマンド文字列はどちらか一方だけです。 ‘%|’ コントロールエスケープを解釈すると、対応する ‘%>’ までをスキップします。
 
多くの関数は次のような型の引数を必要とします。

引数解説形式例
literal数字、%(func 1234)
または文字列%(func text string)
compヘッダーコンポーネント%(func{in-reply-to})
date日付コンポーネント%(func{date})
addrアドレスコンポーネント%(func{from})
exprオプショナルコンポーネント、 %(func(func2))
関数またはコントロール、%(func %<{reply-to}%|%{from}%>)
あるいは関数のネスト%(func(func2{comp}))

 
date と addr の2つの型は comp と同じ形式を持ちますが、 指定するヘッダーコンポーネントは、 日付(date)あるいはアドレス(addr)文字列でなければなりません。 expr 型の引数はオプショナルですが、他は必ず必要です。 expr 型の引数では、コンポーネントおよび関数エスケープ引数の場合には 引数の頭に付ける ‘%’ を省略しなければならず、 コントロールエスケープ引数の場合には引数の頭にスペースと ‘%’ が必要です。
 
フォーマット文字列の評価は、 整数型レジスタ num と文字列型レジスタ str を持つ 単純なマシンを基にしています。 オプショナルな expr 引数を受け取ることのできる 関数エスケープを処理する際、expr 引数が与えられていなければ、 num または str の現在の値を引数として使用します。 コンポーネントエスケープは、 そのメッセージヘッダの内容を str に書き込みます。 整数または boolean 値を返す関数エスケープは num に、 文字列を返す関数エスケープは str にそのリターン値を書き込みます。 (boolean 型は整数のサブセットであり、普通 0=false, 1=true です。) コンポーネントエスケープおよび、 数 または 文字列 を返す関数エスケープは、 num あるいは str に値をセットしたうえで、 この値を呼出し元に返します。 これらのエスケープは、他のエスケープシーケンスの 引数の一部として呼ばれたのでなければ、 リターン値をプリントアウトします。 boolean 値を返す関数エスケープは、呼出し元にその値を返しますが、 プリントアウトはしません。

 関数引数リターン値解釈
msg整数メッセージ番号
cur整数メッセージはカレント
size整数メッセージのサイズ
strlen整数str の長さ
width整数出力バッファのサイズ(バイト)
charleft整数出力バッファに残っているバイト数
timenow整数NEWS−OS 起動以来の時間(秒)
me文字列ユーザのメールボックス
eqliteralbooleannum == arg
neliteralbooleannum != arg
gtliteralbooleannum > arg
matchliteralbooleanstr が arg を含んでいる
amatchliteralbooleanstr が arg で始まっている
plusliteral整数arg と num を加算する
minusliteral整数arg から num を減算する
divideliteral整数num を arg で割る
numliteral整数num に arg を書き込む
lit literal文字列str に arg を書き込む
nonzeroexprbooleannum は 0 ではない
zeroexprbooleannum は 0 である
nullexprbooleanstr は空
nonnullexprbooleanstr は空ではない
voidexprstr あるいは num に書き込む
compcomp文字列str にコンポーネントの内容を書き込む
compvalcomp整数num に “atoi(str)” を書き込む
trimexprstr 中の空白を整える
putstrexprstr をプリントする
putstrfexprstr を指定幅でプリントする
putnumexprnum をプリントする
putnumfexprnum を指定幅でプリントする

 
次の関数に与える引数は日付コンポーネントでなければなりません。

関数引数リターン値解釈
secdate整数秒
mindate整数分
hourdate整数時(0-23)
wdaydate整数曜日(日曜日が0)
daydate文字列曜日(略式)
weekdaydate文字列曜日
sdaydate整数曜日が判るか
(0=暗黙的, −1=不明)
mdaydate整数日
ydaydate整数年間通算日
mondate整数月
monthdate文字列月名(略式)
lmonthdate文字列月名
yeardate整数年
zonedate整数タイムゾーン(時)
tzonedate文字列タイムゾーン(文字列)
szonedate整数タイムゾーンが明記されているか
(0=暗黙的, −1=不明)
date2localdate日付をローカルタイムゾーンに変換する
date2gmtdate日付を GMT に変換する
dstdate整数夏時間が使われているか
clockdate整数UNIX 出現以来の秒数
rclockdate整数現在時刻までの秒数
twsdate文字列正式な RFC-822 表記による日付
prettydate文字列ユーザフレンドリーな表現
nodatedate整数str が日付ではない

 
次の関数に与える引数はアドレスコンポーネントでなければなりません。 ‘∗’ の付いた関数のリターン値は、ヘッダーコンポーネント中で最初 に現れたアドレスだけに関するものです。

関数引数リターン値解釈
properaddr文字列正式な RFC-822 表記によるアドレス
friendlyaddr文字列ユーザフレンドリーな表現
persaddr文字列個人名∗
noteaddr文字列コメントテキスト∗
mboxaddr文字列ローカルメールボックス∗
mymboxaddr整数ユーザのアドレスか?(0=no, 1=yes)
hostaddr文字列ホストドメイン∗
nohostaddr整数ホストの指定がない∗
typeaddr整数ホストのタイプ∗
(0=ローカル, 1=ネットワーク, −1=uucp, 2=不明)
pathaddr文字列アドレスのルート部∗
ingrpaddr整数グループ内にアドレスが含まれるか∗
gnameaddr文字列グループ名
formataddrexprarg を(コンマで区切られた)アドレスリストの
形で str に追加する
putaddrliteralstr に格納したアドレスリストに、arg を
ラベルとして先頭に付け、プリントする
行幅は num で指定する

 
エスケープがネストした場合は、内側から外側への順で解釈されます。 一番外側のエスケープは ‘%’ で始まらなければならず、 内側のエスケープは ‘%’ が付いてはいけません。 例えば、

%<(mymbox{from} To: %{to}%>
はヘッダーコンポーネント “From:” の内容を str に書き込み、 次に (mymbox) が str を読んでその結果を num に書き込みます。 次にコントロールエスケープが num を評価します。 もし num がゼロでなければ、文字列 “To: ” に続けて ヘッダーコンポーネント “To: ” の内容がプリントされます。 ここで、(mymbox{comp}) について簡単に説明します。 一般的に、これはヘッダーコンポーネント “comp” 中の 各アドレスを、ユーザのメールボックス名および 全ての Alternate-Mailboxes と比較し、 いずれかのアドレスがマッチすれば true を返します。 また、“comp” ヘッダーがメッセージ中になかった場合も true を 返します。 この条件を明示的にテストしたければ、(null) 関数を使います。 関数あるいはコンポーネントエスケープが解釈され、結果がその場でプリント される際、オプションでフィールド幅を指定し、 フィールドを何文字でプリントするか指示できます。 例えば、%4(size) のような数値エスケープは、メッセージのサイズを 高々4桁でプリントします。オーバフローした場合は、‘?234’ のように 先頭に ‘?’ が表示されます。 %4(me) のような文字列エスケープの場合は、最初の4桁文字が プリントされ、あとは切り捨てられます。 フィールドが短い場合は、フィルキャラクタ(通常は空白)が加えられて、 右詰めになります。 フィールド幅引数が 0 で始まっている場合は、フィルキャラクタは 0 です。 同様に、関数 (putnumf) および (putstrf) は 頭に付けたフィールド幅引数で指定した文字数分だけ、結果をプリントします。 例えば %06(putnumf(size)) は、6文字の幅のフィールドに、 先頭に 0 を詰めてメッセージサイズをプリントします。 %14(putstrf{from}) は、 ヘッダーコンポーネント “From:” の内容を、 必要に応じて空白を付け足して14文字でプリントします。 putstrf では、フィールド幅に負の値を使うことで、 フィールドの先頭に空白を詰めて文字列を右揃えにすることができます。 関数 (putnum) および (putstr) は フィールド幅引数を全く無視し、必要最小限の文字数で結果をプリントします。 出力できる最大幅が内部レジスタに保存されています。 これを越える出力は全て切り捨てられます。 これらを理解したところで、scan のデフォルトのフォーマット文字列を 見てみます。 ここでは読み易くするため、いくつかの部分に分けています。 最初の部分は、
 

%4(putnumf(msg))%<(cur)+%| %>%<{replied}−%| %>
 
であり、メッセージ番号を4桁でプリントし、そのメッセージが カレントであれば ‘+’、カレントでなければ空白をプリントし、 “Replied:” フィールドがあれば ‘−’、なければ空白をプリントします。 次は、
 

%02(putnumf(mon{date}))/%02(putnumf(mday{date}))
 
では、月と日が ‘/’ で区切られてそれぞれ2桁の数字でプリントされます (ゼロで埋められます)。 次に、
 

%<{date} %|∗%>
 
では、“Date:” フィールドがあれば空白、なければ ‘∗’ が プリントされます。 次に、
 

%<(mymbox{from})To:%14(putstrf(friendly{to}))
 
では、メッセージが自分自身からであれば、‘To:’ に続けて、 “To:” フィールド中の最初のアドレスが “user−friendly” な 表記でプリントされます。 続いて、
 

%|%17(putstrf(friendly{from}))%>
 
では、もしメッセージが自分自身からでなければ、 “From:” アドレスがプリントされます。 そして最後に、
 

%{subject}%<{body}<<%{body}>>%>
 
では、サブジェクト、‘<<’、および本文の冒頭がプリントされます。 さらに複雑な例として、デフォルトの replcomps フォーマットファイル について次に述べます。
 

%(lit)%(formataddr %<{reply-to}%|
 
これは str をクリアし、もし “Reply-To:” ヘッダーがあれば それをフォーマットし、なければ else 節
 

%<{from}%|%<{sender}%|%<{return-path}%>%>%>%>)\
 
を実行します。 これは “From:”、“Sender:” および “Return-Path:” ヘッダー のどれか一つが見つかった時点でそれだけをフォーマットします。 次に、
 

%<(nonnull)%(void(width))%(putaddr To: )\n%>\
 
では、formataddr の結果が空でなければ、アドレスとして width 幅の フィールドの中に(必要に応じて行を折り返しながら) ラベル “To: ” に続けてプリントします。
 

%(lit)%(formataddr{to})%(formataddr{cc})%(formataddr(me))\
 
では str がクリアされ、qTo:” と “Cc:” ヘッダーおよび ユーザのアドレスが、一緒に (repl の “−cc” スイッチに何が指定されるかによる) フォーマットされます。
 

%<(nonnull)%(void(width))%(putaddr cc: )\n%>\
 
フォーマットした結果が空でなければ、ラベル “cc: ” に続けて プリントされます。
 

%<{fcc}Fcc: %{fcc}\n%>\
 
もし repl に “−fcc folder” スイッチが与えられた場合 (%{fcc} に関する詳細は repl (1) を参照してください)、 “Fcc:” ヘッダーが出力されます。
 

%<{subject}Subject: Re: %{subject}\n%>\
 
もし題目コンポーネントがあれば、返信用の適当な題目が出力されます。
 

%<{date}In-reply-to: Your message of "\

%<(nodate{date})%{date}%|%(tws{date})%>."%<{message-id}

             %{message-id}%>\n%>\

--------

 
もし日付コンポーネントがあれば、“In-Reply-To:” ヘッダーが、 冒頭に “Your message of ” を付けて出力されます。 日付が解析可能であれば正式なフォーマットで、 そうでなければそのままの形で出力されます。 message-id があれば、それも出力されます。 通常のプレーンなテキストと同様に、ダッシュ(‘-’) の列もそのまま出力されます。 この最後の部分は、もう少し詳しく説明するのに良い例です。 この部分を疑似コードで以下に示します。

if (comp_exists(date))  then
print (“In-reply-to: Your message of \\*(lq”)
if (not_date_string(date.value) then
print (date.value)
else
print (rfc822(date.value))
endif
print (“\\*(rq”)
if (comp_exists(message-id)) then
print (“\n\t”)
print (message-id.value)
endif
print (“\n”)
endif

これは複雑なようですが、実際には、個々のフィールドを取り出し、 ユーザの希望するあらゆるフォーマットでプリントするのに 十分対応できる方法なのです。

関連ファイル

なし

プロファイルコンポーネント

なし

関連事項

scan(1), repl(1), ap(8), dp(8)

デフォルト値

なし

コンテクスト

なし

歴史

このソフトウェアは MH 6.3 から利用できるようになりました。 これ以前は、出力フォーマットの記述はずっと書き易かったのですが、 柔軟性がはるかに乏しいものでした。

バグ

MH が BERK オプション付きでコンフィギュレーションされているホストでは、 アドレスの解析ができません。

NEWS-OSRelease 4.1C

Typewritten Software • bear@typewritten.org • Edmonds, WA 98026