入出力

【コマンドライン】と【コンソール】

【コマンドライン】にメッセージを出力する prompt 関数があります。これは、Visual LISP の【コンソール】やファイルには出力できません。

その他に、ここで説明する AutoLISP の出力関数で PRINx 系関数が存在します。これらの関数は Visual LISP からプログラムを走らせている場合で、Visual LISP の設定により【コマンドライン】にも出力されますが、設定により【コンソール】のみの出力とすることも出来ます。この設定は Visual LISP のメニューより【ツール】>【環境オプション】>【一般的なオプション】の【診断】タブにあります。

一方、AutoCAD ユーザーがコマンドからプログラムを実行した場合には、PRINx 系関数は【コマンドライン】に出力して、Visual LISP の【コンソール】へは出力しません。結局は、この性質が判っていれば prompt 関数でも PRINx 系関数でも同じことですが、PRINx 系関数は変数の内容を手軽に出力できるためデバッグ用として Visual LISP から【コンソール】へ出力させ、prompt 関数は、AutoCADユーザーに対してメッセージを【コマンドライン】に表示するといった使い分けが良いと思います。

ファイルのオープンとクローズ

AutoLISP関数
(open filename mode)
filename:文字列
mode:文字列
ファイルを開きます。
戻り値:ファイルディスクリプタ、またはnil
ACETUTIL関数
(acet-file-open filename mode)
filename:文字列
mode:文字列
ファイルを開きます。
戻り値:ファイルディスクリプタ、またはnil

open 関数とacet-file-open 関数は、ファイルを開いてアクセス可能な状態にします。両者に違いはありません。

filenname 引数にはファイル名を指定します。

mode 引数はアクセスモードを表す文字列を指定します。

mode 説明
“r” 読み込みモード
“w” 上書きモード
ファイルが存在しない場合は、新しいファイルが作成されます。既に存在している場合は、上書きされます。
“a” 追加モード
既存のファイルの後ろに、追加する形で書き出します。ファイルが存在しなかった場合は、新しいファイルが作成されます。

AutoLISP には、バイナリーの入出力はありません。また、ランダムアクセスもありません。以降の入出力関数は、文字列あるいは文字のみを扱えます。

正常にファイルを開くことができれば、open 関数はファイルディスクリプタを返します。失敗した場合は nil を返します。

ファイルディスクリプタはファイルにアクセスするのに必要なだけでなく、開いたファイルを閉じるにも必要です。開いたファイルは、必ず閉じることが必要です。

AutoLISP関数
(close file-desc)
file-desc:ファイルディスクリプタ
開いているファイルを閉じます。
戻り値:nil

close 関数は、開いているファイルを閉じます。引数は open 関数で取得したファイルディスクリプタです。

ファイルをアクセス可能なように開いて、必要な処理を行ったあとファイルを閉じる一連の流れは以下のとおりです。

(setq fileName (vl-filename-mktemp)) ;テンポラリファイル名を作成
(if (setq fd (open fileName "w"))    ;上書きモードでオープン
    (progn
        ;;
        ;; 一連のファイルへの出力操作
        ;;
        (close fd)                   ;ファイルのクローズ(必須)
    )
)

出⼒関数

AutoLISP関数
(write-char integer [file-desc])
integer:整数
file-desc:ファイルディスクリプタ
コンソールまたは開いているファイルに、1 文字を書き出します。
戻り値:整数

write-char 関数は出力先に1 文字を書き出します。integer 引数は ASCII コードによる文字を表す整数です。

返り値は、出力した文字コードを表す整数が返ります。

_$ (ascii "A")⏎
65
_$ (write-char 65) ⏎
A65 ;Aが関数の出力、後の65 は関数の戻り値
AutoLISP関数
(write-line string [file-desc])
string:文字列
file-desc:ファイルディスクリプタ
コンソールまたは開いているファイルに、文字列を書き出します。
戻り値:文字列

write-line 関数は出力先に文字列を書き出します。出力ごとに自動的に改行されるほか、文字列の中のエスケープ文字は有効です。

戻り値は、指定した文字列そのものです。

(setq fileName (vl-filename-mktemp))    ;テンポラリファイル名を作成
(if (setq fd (open fileName "w"))       ;上書きモードでオープン
  (progn (write-line "One good turn deserves another." fd)
         (write-line "He who runs after two hares will catch neither." fd)
         (close fd)                     ;ファイルのクローズ
  )
)

書き出したファイルを、テキストエディタなどで開くと以下のようになります。

One good turn deserves another.⏎
He who runs after two hares will catch neither. ⏎

ビープ音

古いAutoLISPのコードを調べていると次のようなものが見つかります。標準出力の"CON"が使え、エスケープコードのBEEPの出力することで、音を鳴らす事が出来るのではないかと思えますが、試してみたところ何も起こりませんでした。現在は使えないテクニックのようです。ビープ音については acet-sys-beep 関数を参照してください。

(defun beep ( / f)
    (write-line "¥007" (setq f (open "CON" "w")))
    (setq f (close f))
)

⼊⼒関数

AutoLISP関数
(read-char [file-desc])
file-desc:ファイルディスクリプタ
キーボード入力バッファまたは開いているファイルから読み込んだ文字を表す整数を返します。
戻り値:整数、またはnil

read-char 関数は入力元から 1 文字を読み出します。ファイルディスクリプタを省略した場合は、ユーザーがキーボードのキーを押すのを待ちます。ファイルからの場合は直ちに読み込みますが、読み込むものが無い場合は nil を返します。

返り値は、文字コードを表す整数が返ります。

_$ (read-char)⏎
65 ;キーボードで「A」を入力

なお、キーボードからユーザーの一文字程度の入力を受け取る目的では getkword 関数を使う方が簡便で確実です。

AutoLISP関数
(read-line [file-desc])
file-desc:ファイルディスクリプタ
キーボード入力バッファまたは開いているファイルから一行読み込み、文字列として返します。
戻り値:文字列、またはnil

read-line 関数は入力元から一行読み取ります。なお、文字列にそのまま格納できない「”」ダブルクォーテーションなどの文字が含まれていた場合は、制御文字(エスケープコード)に自動的に置換されます。

戻り値は読み込んだ文字列です。ファイルの終端に達した等、読み込むものが存在しない場合は nil を返します。

下はキーボードからの入力の例です。空白を含む文字列を入力することができ、Enter キーで確定します。入力は「”」ダブルクォーテーションで囲む必要はありません。

_$ (read-line)⏎ ; He that falls today may rise tomorrow. とタイプしてEnter
"He that falls today may rise tomorrow."

なお、キーボードからユーザーの文字列を受け取る目的では getstring 関数を使う方が簡便で確実です。

次の例はファイルから読み取る例です。acad.pgp ファイルの内容をリストに格納します。

(setq fileName (findfile "acad.pgp") ;acad.pgp ファイルを検索
      contents nil
)
(if (and fileName (setq fd (open fileName "r")))       ;読み込みモードでオープン
    (progn
        (while (setq line (read-line fd))
            (setq contents (append contents (list line)))
        )
        (close fd)                                     ;ファイルのクローズ
    )
)

実行すると、contents 変数には、各行ごとに分かれた文字列がリスト形式で格納されます。

(";¥tACAD.PGP - Command Alias Definitions"
 ";¥tCopyright (C) 1997-2000 by Autodesk, Inc."
 ""
(後略)

PRINx 関数

AutoLISP にはバイナリー出力はありません。しかしデバッグ中には、文字列で表せないオブジェクトを、なんらかの形で表示したい場合があります。PRINx 関数にオブジェクトを出力するように指示すると、簡単な文字列の情報に自動的に変換され表示することができるようになります。また、整数や実数を渡しても、自動的に文字列に変換して出力が行えます。

PRINx 関数にはいくつかの種類があります。その分け方は二通りあります。一つ目は、エスケープコードを解釈するか無視するかです。これはそれぞれ princ 関数系列と prin1 関数系列にあたります。二つ目は、文字列に変換するだけか変換しした上で出力もするか、です。

  エスケープコードは有効 (princ 関数系列) エスケープコードを無視 (prin1 関数系列)
文字列に変換 vl-princ-to-string 関数 vl-prin1-to-string 関数
文字列に変換して出力 princ 関数 prin1 関数
print 関数

princ 関数系列は次の通りです。princ 関数はファイルに出力が可能なように、ファイルディスクリプタを指定できます。また、princ 関数の戻り値は、必ずしも文字列ではなく、文字列に変換する前の引数である式が評価された値です。

AutoLISP関数
(vl-princ-to-string expr)
expr:式
LISP データを、princ 関数で出力したかのような文字列にして返します。
戻り値:文字列
AutoLISP関数
(princ [expr [file-desc]])
expr:式
file-desc:ファイルディスクリプタ
LISP データを、【コンソール】に表示したり、開いているファイルに書き出したりします。
戻り値:アトム、またはリスト

prin1 関数系列は次の通りです。prin1 関数と print 関数には、ファイルに出力が可能なように、ファイルディスクリプタが指定できます。また、prin1 関数と print 関数の戻り値は、必ずしも文字列ではなく、文字列に変換する前の引数である式が評価された値です。

AutoLISP関数
(vl-prin1-to-string expr)
expr:式
LISP データを、prin1 関数で出力したかのような文字列にして返します。
戻り値:文字列
AutoLISP関数
(prin1 [expr [file-desc]])
expr:式
file-desc:ファイルディスクリプタ
LISP データを、【コンソール】に表示したり、開いているファイルに書き出したりします。
戻り値:アトム、またはリスト
AutoLISP関数
(print [expr [file-desc]])
expr:式
file-desc:ファイルディスクリプタ
LISP データを、【コンソール】に表示したり、開いているファイルに書き出したりします。一回の出力ごとに改行を行います。
戻り値:アトム、またはリスト

出力の差を princ 関数と prin1 関数の場合で、具体的に確認します。

まず、整数、実数、リスト、オブジェクトの場合は、二つの系列で差はありません。

expr 引数のタイプ princ 関数 prin1 関数 共通
変換前 変換後(文字列)
整数 10 10
実数 1234.5 1234.5
リスト (1 2 3) (1 2 3)
オブジェクト #<FILE internal>
(ファイルディスクリプタの場合)
#<file D:¥Users¥mChair¥AppData¥Local¥Temp¥$VL~~001>

差があるのは、文字列の扱いです。

expr 引数のタイプ princ 関数
変換前 変換後(文字列)
文字列 "ABCD¥nEFG¥n" ABCD⏎(改行)
EFG⏎(改行)
expr 引数のタイプ prin1 関数
変換前 変換後(文字列)
文字列 "ABCD¥nEFG¥n" "ABCD¥nEFG¥n"

prin1 関数の場合はエスケープコードは解釈されません。「¥n」はそのまま「¥」と「n」の二文字になります。さらに、prin1 関数の場合は、文字列を表す「”」ダブルクォーテンションも除去されないことに注目してください。「”」も含めた文字列として出力されます。

さて、prin1 関数は、文字列引数をそのままベタで出力するため、ファイルなどに改行を含める術がありません。そこで prin1 関数から派生した print 関数は、一回の出力ごとに「先頭に改行文字と末尾に半角の空白」を付加して出力します。

princ 関数、prin1 関数、そして print 関数の違いを確認するため、以下のようなプログラムで各関数を使用してみます。

(setq fileName (vl-filename-mktemp))          ;テンポラリファイル名を作成
(if (setq fd (open fileName "w"))             ;上書きモード
    (progn
        (princ "-----princ-----" fd) ;_ princ の場合の文字列
        (princ "¥n" fd) ;_ princ の場合の改行
        (princ 1 fd)    ;_ princ の場合の整数
        (princ "¥n" fd) ;_ princ の場合の改行
        (princ 1.0 fd)  ;_ princ の場合の実数
        (princ "¥n" fd)                       ;改行
        (prin1 "-----prin1-----" fd) ;_ prin1 の場合の文字列
        (prin1 "¥n" fd) ;_ prin1 の場合の改行
        (prin1 1 fd)    ;_ prin1 の場合の整数
        (prin1 "¥n" fd) ;_ prin1 の場合の改行
        (prin1 1.0 fd)  ;_ prin1 の場合の実数
        (princ "¥n" fd)                       ;改行
        (print "-----print-----" fd) ;_ print の場合の文字列
        (print "¥n" fd) ;_ print の場合の改行
        (print 1 fd)    ;_ print の場合の整数
        (print "¥n" fd) ;_ print の場合の改行
        (print 1.0 fd)  ;_ print の場合の実数
        (princ "¥n" fd)                       ;改行
        (close fd)                            ;ファイルのクローズ
    )
)

出力したファイルを、テキストエディタで開くと以下のようになります。

-----princ-----⏎
1⏎
1.0⏎
"-----prin1-----""¥n"1"¥n"1.0"⏎

"-----print-----" ⏎
"¥n" ⏎
1 ⏎
"¥n" ⏎
1.0

サウンド

ACETUTIL関数
(acet-sys-beep sound)
sound:整数
ビープ音を鳴らします。
戻り値:nil

acet-sys-beep 関数は、ビープ音を鳴らします。

sound 引数には、ビープ音の種類を指定します。Windows のビープ音は、Windows の【コントロールパネル】で設定されているものです。

sound 説明
-1 Windows の【一般の警告音】。サウンドカードを利用できない場合、ネイティブなコンピュータスピーカーのビープ音。
0 Windows の【一般の警告音】
16 Windows の【システムエラー】
32 Windows の【メッセージ(問い合わせ)】
48 Windows の【メッセージ(警告)】
64 Windows の【メッセージ(情報)】

外部 ObjectARX アプリケーションによる関数 EXRXSUBR です。