見出し画像

Notes C API探訪: NSFFormulaCompile(関数)

Notes/Dominoの@式は、LotusScriptが登場するR4以前からある、重要なプログラミング言語です。その昔、@式だけでテンプレート製品を作ったこともありました。今回は、テキストで書かれた@式を、コンパイルしてバイナリ形式に変換し、ハンドルを受け取る関数を紹介します。

NSFFormulaCompile

NSFFormulaCompile関数は、テキスト形式の@式をバイナリ形式にコンパイルします。

#include <nsfsearc.h>
STATUS LNPUBLIC NSFFormulaCompile (
  char far *FormulaName,
  WORD FormulaNameLength,
  const char far *FormulaText,
  WORD FormulaTextLength,
  FORMULAHANDLE far *rethFormula,
  WORD far *retFormulaLength,
  STATUS far *retCompileError,
  WORD far *retCompileErrorLine,
  WORD far *retCompileErrorColumn,
  WORD far *retCompileErrorOffset,
  WORD far *retCompileErrorLength);

FormulaNameとFormulaNameLengthで、ビューの列の内部名を指定します。ビューを作成する時以外は0を渡します。
FormulaTextとFormulaTextLengthで、LMBCSテキスト形式の@式を指定します。
rethFormulaは、ハンドルを受け取る変数へのポインタを渡します。受け取ったハンドルは、使用後OSMemFree関数で解放する必要があります。
retFormulaLengthは、バイナリ形式でのサイズを受け取る変数へのポインタを渡します。
retCompileErrorは、コンパイルエラーのステータス値を受け取る変数へのポインタを渡します。
retCompileErrorLineは、コンパイルエラーが発生した行数を受け取る変数へのポインタを渡します。
retCompileErrorColumnは、コンパイルエラーが発生した列数を受け取る変数へのポインタを渡します。
retCompileErrorOffsetは、コンパイルエラーが発生した場所までのオフセット位置を受け取る変数へのポインタを渡します。
retCompileErrorLengthは、コンパイルエラーが発生したオフセット位置からの長さ(範囲)を受け取る変数へのポインタを渡します。

ステータスメッセージを標準出力に表示する

NSFFormulaCompileのサンプルコードを紹介するに先立ち、ステータスメッセージを標準出力に表示する機能を関数にまとめたいと思います。

まず、main関数などプログラムの初期設定のどこかで、以下のコードを実行しておきます(参考元→標準出力にユニコードを出力させる)。

std::wcout.imbue( std::locale( "", std::locale::ctype ) );

これでstd::cout、std::wcoutのいずれも、Windowsの標準出力で正しく表示できるようになります。

次に、以下のような関数を定義します。

// logger.h
#ifndef LOGGER_H
#define LOGGER_H

#ifdef NT
#pragma pack(push, 1)
#endif

#include <global.h>

#ifdef NT
#pragma pack(pop)
#endif

namespace logger {

void printStatusMessage(STATUS status);

} // namespace logger

#endif // LOGGER_H
// logger.cpp
#include "logger.h"
#include <string>
#include <iostream>

#ifdef NT
#pragma pack(push, 1)
#endif

#include <osmisc.h>
#include <misc.h>
#include <nls.h>

#ifdef NT
#pragma pack(pop)
#endif

#define MAXMESSAGE (MAXSPRINTF * NLS_MAXRATIO_XLATE_FROM_LMBCS)

namespace logger {

void printStatusMessage(STATUS status) {
 char lmbcs[MAXSPRINTF + 1];
 char buffer[MAXMESSAGE + 1];
 WORD len = OSLoadString(NULLHANDLE, ERR(status), lmbcs, MAXSPRINTF);
 WORD wlen = OSTranslate(
       OS_TRANSLATE_LMBCS_TO_UNICODE,
       lmbcs, len,
       buffer, MAXMESSAGE);
 std::wstring message(
       reinterpret_cast<wchar_t*>(buffer),
       wlen / sizeof(wchar_t)
       );
 std::wcout << message << std::endl;
}

} // namespace logger

この記事で紹介したコードを流用しています。
プログラム中にある#pragma packは、構造体メンバーの境界、配置の制御をします。Notes C API、特にWindowsでは構造体の境界を1バイトにしなければなりません。そのため、Notes C APIのヘッダファイルをロードする時のみ、境界を1バイトにパッキングしています。シンボルに「NT」が存在する場合のみパッキングしているのは、シンボルNTがLinuxやMacOSにはないためです。

サンプルコード

前出のlogger::printStatusMessage関数を利用したサンプルコードです。

#include <iostream>
#include "logger.h"

#ifdef NT
#pragma pack(push, 1)
#endif

#include <nsfsearc.h>
#include <osmem.h>

#ifdef NT
#pragma pack(pop)
#endif

void doNsfFormulaCompile(const char *text) {
 FORMULAHANDLE hFormula = NULLHANDLE;
 STATUS compileStatus = NOERROR;
 WORD wLen = 0, wLine = 0, wColumn = 0, wOffset = 0, wOffsetLen = 0;
 std::cout << "Formula is '" << text << "'." << std::endl;
 STATUS status = NSFFormulaCompile(
       nullptr, 0,
       text, static_cast<WORD>(strlen(text)),
       &hFormula,
       &wLen,
       &compileStatus,
       &wLine,
       &wColumn,
       &wOffset,
       &wOffsetLen);
 if (ERR(status) != NOERROR) {
   logger::printStatusMessage(status);
   logger::printStatusMessage(compileStatus);
   std::cout << "Line=" << wLine
             << ", Column=" << wColumn
             << ", Offset=" << wOffset
             << ", OffsetLen=" << wOffsetLen
             << "\n===> "
             << std::string(text).substr(wOffset, wOffsetLen)
             << std::endl;
 } else {
   std::cout << "NSFFormulaCompile is successful.\n"
             << "Binary length=" << wLen
             << std::endl;
   OSMemFree(hFormula);
 }
}

void nsfFormulaCompileTest() {
 doNsfFormulaCompile("@All");
 doNsfFormulaCompile("123 * 45");
 doNsfFormulaCompile("@Text(@Hoge)");
}

// Formula is '@All'.
// NSFFormulaCompile is successful.
// Binary length=10
// Formula is '123 * 45'.
// NSFFormulaCompile is successful.
// Binary length=42
// Formula is '@Text(@Hoge)'.
// 式のエラー
// 不明な@関数です
// Line=0, Column=0, Offset=6, OffsetLen=5
// ===> @Hoge

関数nsfFormulaCompileTestを実行すると、コメントアウトのような出力になります。コンパイルに成功すると、バイナリ形式でのサイズが表示されます。失敗すると、関数、コンパイルそれぞれのエラーメッセージが表示され、行番号、列番号、オフセット位置、長さとエラー箇所が表示されます。

ちなみに、NSFFormulaCompileはLMBCS文字列を受け取りますが、1バイト文字のみのテキストであれば、LMBCS文字列とASCII文字列は同等なので、変換なしで利用できます。

まとめ

@式は、LotusScriptの登場によって使用機会は限定されましたが、C/C++からAPIを利用する場合、非常に大きなウェイトを占めます。私は特に文書検索で使用する機会が多々あります。また、@式は文書に対して評価することができるので、フィールドデータを@式で加工してからその値を受け取りたい場合などに使えます。その他にリッチテキスト内や設計文書などでも利用機会があるので、是非とも覚えておきたい関数の一つです。

注意: コードの利用においてチブル・システムズは一切の責任を負いません。自己責任でご利用をお願いいたします。

この記事が気に入ったらサポートをしてみませんか?