Notes C API探訪: NSFSearch(関数)(その3)
今回もNSFSearch関数ですが、ディレクトリを指定して、その中のNSFデータベースを取ってくるサンプルを紹介します。まずは、事前に準備しておく関数から。
nsfsearch::getSummaryString
NSFLocateSummaryValue関数のラップ関数ですが、取得できる型がTYPE_TEXTのみという仕様です。
テキスト取得ならNSFGetSummaryValueがありますが、バッファのサイズが予期できないので、あえてNSFLocateSummaryValueを使っています。
// ex_nsfsearch.hpp
namespace nsfsearch {
inline std::string getSummaryString(
ITEM_TABLE *pSummary,
const std::string &name
) {
char *pValue = nullptr;
WORD len = 0, type = 0;
if (NSFLocateSummaryValue(
pSummary,
name.c_str(),
&pValue,
&len,
&type
) && type == TYPE_TEXT) {
return std::string(pValue, len);
}
return std::string();
}
} // namespace nsfsearch
nsfdb::parseInfo
NSFDbInfoParse関数をラップしています。データベース情報バッファをwhatで指定したINFOPARSE_***の場所のデータを返します。
// ex_nsfdb.hpp
namespace nsfdb {
inline std::string parseInfo(const std::string &info, WORD what) {
char buffer[NSF_INFO_SIZE] = "";
NSFDbInfoParse(
const_cast<char*>(info.c_str()),
what,
buffer,
NSF_INFO_SIZE
);
return std::string(buffer);
}
} // namespace nsfdb
サンプルコード
まずは、NSFSearch関数から呼ばれるコールバック関数を説明します。
#include <iostream>
#include "logger.h"
#include "ex_osfile.hpp"
#include "ex_nsfdb.hpp"
#include "ex_nsfsearch.hpp"
#ifdef NT
#pragma pack(push, 1)
#endif
#include <nsfnote.h>
#include <stdnames.h>
#ifdef NT
#pragma pack(pop)
#endif
/**
* @brief NSFSearch関数用コールバック
* @param pMatchOrg SEARCH_MATCH構造体へのポインタ
* @param pSummary 名前付きサマリーバッファへのポインタ
*/
STATUS LNCALLBACK search2(void *, SEARCH_MATCH *pMatchOrg, ITEM_TABLE *pSummary) {
// SEARCH_MATCH構造体のコピー
SEARCH_MATCH match;
memcpy(&match, pMatchOrg, sizeof(SEARCH_MATCH));
// 検索にマッチしているか
if (!(match.SERetFlags & SE_FMATCH)) return NOERROR;
// ファイル検索専用フィールド名でパスを取得
std::string path = nsfsearch::getSummaryString(pSummary, DBDIR_PATH_ITEM);
// ファイル検索専用フィールド名でDBアイテムを取得
std::string info = nsfsearch::getSummaryString(pSummary, DBDIR_INFO_ITEM);
// DBアイテムからタイトルをパース
std::string title = nsfdb::parseInfo(info, INFOPARSE_TITLE);
// 結果を出力
std::cout << path << "(" << title << ")" << std::endl;
return NOERROR;
}
まず、お作法としてSEARCH_MATCH構造体を提供元からコピーします。
SEARCH_MATCH構造体のSERetFlagsメンバにSE_FMATCHフラグが立っていれば検索対象です。普通は、NSFSearch関数でSEARCH_ALL_VERSIONSを指定した時、マッチしなかった文書も含めた場合に、この文書はマッチしている/していないの区別を付けるためのものですが、今回はあえてやってみています。
あとは、名前付きサマリーバッファから情報を取得して、標準出力に書き出しています。
ここで湧き上がる疑問として、「文書にはフィールド名があるのはわかるけど、ファイル情報にフィールド名なんてあるの?」ってことです。これには、Notes C APIのヘッダーファイルに答えがあります。
// stdnames.h
/* Disk directory search item names and values */
#define DBDIR_PATH_ITEM "$Path" /* Path name */
#define DBDIR_TYPE_ITEM "$Type" /* Type item */
#define DBDIR_TYPE_ITEM_DIRECTORY "$DIR" /* Directory type name */
#define DBDIR_TYPE_ITEM_NOTEFILE "$NOTEFILE" /* Notefile type name */
#define DBDIR_TYPE_ITEM_OLDNOTEFILE "$OLDNOTEFILE"
#define DBDIR_INFO_ITEM "$Info" /* Info item */
#define DBDIR_LENGTH_ITEM "$Length"
#define DBDIR_MODIFIED_ITEM "$Modified"
#define DBDIR_PROPERTIES_ITEM "$Properties"
#define DBDIR_LINK_ITEM "$LinkInfo"
#define DBDIR_DIRECTORY_LINK "$DIRLINK" /* Directory Link */
#define DBDIR_DATABASE_LINK "$DBLINK" /* Database Link */
#define DBDIR_DBOPTIONS_ITEM "$DBOPTIONS" /* Database Options */
#define DBDIR_DBVERSIONS_ITEM "$DBVERSIONS" /* Database Major and Minor versions */
#define DBDIR_DBCREATED_ITEM "$DBCREATED" /* Database Created date */
#define DBDIR_LASTFIXUP_ITEM "$LASTFIXUP" /* Last database fixup time */
#define DBDIR_QUOTALIMIT_ITEM "$QUOTALIMIT" /* Database quota limit */
#define DBDIR_QUOTAWARNING_ITEM "$QUOTAWARNING" /* Database quota warning */
#define DBDIR_MAXDBSIZE_ITEM "$MAXDBSIZE" /* Database MAximum Size - 1Gb, 2GB, 3GB, 4GB */
#define DBDIR_PHYSICALPATH_ITEM "$PHYSICALPATH" /* Physical file path (OS level path) */
#define DBDIR_ISLOGGED_ITEM "$ISLOGGED" /* Is the db logged? */
#define DBDIR_LENGTH2_ITEM "$Length2" /* File Size as NSFDISKPOS */
#define DBDIR_DBOPTIONS2_ITEM "$DBOPTIONS2" /* Database Options[1] */
#define DBDIR_DBOPTIONS3_ITEM "$DBOPTIONS3" /* Database Options[2] */
#define DBDIR_DBOPTIONS4_ITEM "$DBOPTIONS4" /* Database Options[3] */
#define DBDIR_DATAMODIFIED_ITEM "$DATAMOD" /* Data Modified time */
#define DBDIR_NONDATAMODIFIED_ITEM "$NONDATAMOD" /* Non Data Modified time */
#define DBDIR_CURRENTUSAGE_ITEM "$CURRENTUSAGE" /* CurrentSpace Utilization */
#define DBDIR_DAOSSTATE_ITEM "$DAOSSTATE" /* DAOS state */
#define DBDIR_DAOSOBJCOUNT_ITEM "$DAOSOBJCOUNT" /* DAOS objects */
#define DBDIR_DAOSSTOREDBYTES_ITEM "$DAOSSTOREDBYTES" /* DAOS bytes */
#define DBDIR_DAOSSYNCPOINT_ITEM "$DAOSSYNCPOINT" /* DAOS sync point */
#define DBDIR_STORAGEPATH_ITEM "$STORAGEPATH" /* Raw file path (all links translated) */
#define DBDIR_REPLFLAGS_ITEM "$ReplFlags" /* Replica Flags */
#define DBDIR_DB2_DATABASE_LINK "$DB2LINK" /* DB2 Database Link */
#define DBDIR_LASTCOMPACT_ITEM "$LASTCOMPACT" /* last database compacttime */
ファイル情報には、既定の名前がついた値が用意されています。DBDIR_***というシンボルで定義された文字列がその名前で、NSFSearch関数ファイル検索時の名前付きサマリーバッファで使用できます。ファイルによって、どの名前が使用されるかまちまちですが、少なくともDBDIR_PATH_ITEM(パス名)のような、ファイルすべてに当てはまるものは必ず返ってきます。例えば対象がNSFデータベースなら、タイトルが含まれるDBDIR_INFO_ITEMがサマリーバッファに含まれるようになります。
次に、パスの構築から検索までの基本的な流れを実行する関数を定義します。
bool searchFiles(
const std::string &server,
const std::string &path,
WORD searchFlags
) {
// ネットパスを構築
auto netPath = osfile::constructPathNet(path, server);
if (!netPath) {
return false;
}
std::cout << "netPath=" << netPath.value() << std::endl;
// データベースをオープン
auto hDB = nsfdb::openDb(netPath.value());
if (!hDB) {
return false;
}
std::cout << "opened; " << netPath.value() << std::endl;
// 検索実行
if (!nsfsearch::search(
hDB.value(),
NULLHANDLE,
"",
SEARCH_SUMMARY | SEARCH_FILETYPE,
searchFlags,
nullptr,
search2,
nullptr,
nullptr
)) {
nsfdb::closeDb(hDB.value());
return false;
}
// 終了処理
nsfdb::closeDb(hDB.value());
return true;
}
searchFiles関数では、サーバ名とパスを指定すると、そこから検索可能で、フラグに当てはまるファイルを検索して処理します。
検索フラグには、ファイル情報ということでSEARCH_FILETYPEを必ず指定します。また、ファイル情報は文書ではないので、SEARCH_SUMMARYで名前付きサマリーバッファを取得するようにします。
なお、SEARCH_MATCH構造体にはNoteIDなども返ってきますが、正直これが何を表すのかはわかりません。もしかしたら、いったんDBに保存されないオンメモリの文書が作られて、そこから情報が供給されるのかもしれませんが、今回は無駄な戦いは避けます(爆)。
ちなみに、今回は@式は使わずにNULLHANDLEを指定しています(これは「@All」と同等の効果があります)。ファイル情報に検索式なんか使えないと普通思いますが、実は使えます。例えば、次のような検索式を作ったとします。
DBDIR_PATH_ITEM "=\"docs.nsf\""
// $Path="docs.nsf" となる
これは「パスがdocs.nsfというファイルを検索する」となり、NSFSearch関数ではこのファイルだけが抽出されてコールバックが呼ばれます。
最後にsearchFilesに検索したいサーバとディレクトリ、検索フラグを指定して呼び出します。
void nsfSearchFiles() {
if (!searchFiles("", "", FILE_DBANY)) {
return;
}
}
ファイル検索用のフラグには、以下のようなものがあります。
// osfile.h
/* File type flags (used with NSFSearch directory searching). */
#define FILE_ANY 0 /* Any file type */
#define FILE_DBREPL 1 /* Starting in V3, any DB that is a candidate for replication */
#define FILE_DBDESIGN 2 /* Databases that can be templates */
#define FILE_MAILBOX 3 /* BOX - Any .BOX (Mail.BOX, SMTP.Box...) */
#define FILE_DBANY 4 /* NS?, any NSF version */
#define FILE_FTANY 5 /* NT?, any NTF version */
#define FILE_MDMTYPE 6 /* MDM - modem command file */
#define FILE_DIRSONLY 7 /* directories only */
#define FILE_VPCTYPE 8 /* VPC - virtual port command file */
#define FILE_SCRTYPE 9 /* SCR - comm port script files */
#define FILE_ANYNOTEFILE 10 /* ANY Notes database (.NS?, .NT?, .BOX) */
#define FILE_UNIQUETEMP 11 /* DTF - Any .DTF. Used for container and sort temp files to give them a more
unique name than .TMP so we can delete *.DTF from the temp directory and
hopefully not blow away other application's temp files. */
#define FILE_MULTICLN 12 /* CLN - Any .cln file...multi user cleanup files*/
#define FILE_SMARTI 13 /* any smarticon file *.smi */
#define FILE_DBREP_REDIR 14 /* FILE_DBREPL plus database redirects */
#define FILE_TYPEMASK 0x00ff /* File type mask (for FILE_xxx codes above) */
#define FILE_SKIPDAOS 0x0100 /* Do not traverse DAOS repository */
#define FILE_SKIPJS 0x0200 /* Do not traverse HTTP's javascript directories */
#define FILE_DIRS 0x8000 /* List subdirectories as well as normal files */
#define FILE_NOUPDIRS 0x4000 /* Do NOT return ..'s */
#define FILE_RECURSE 0x2000 /* Recurse into subdirectories */
#define FILE_LINKSONLY 0x1000 /* All directories, linked files & directories */
下位2バイトはファイルの種類で一択です。上位2バイトはビット指定なので、複数合成することが可能です。
実行例
データベースのタイトルに含まれる漢字は、LMBCS文字列なので、図のように文字化けしています。
まとめ
前回と今回でファイル内の文書、ディレクトリ内のデータベースをそれぞれNSFSearchで検索してみました。Notesクライアントでビューを使って文書を見つけるような感覚で、Notes C APIではNSFSearch関数の利用頻度がとても高いと思うので、ぜひとも身につけたい関数です。
注意: コードの利用においてチブル・システムズは一切の責任を負いません。自己責任でご利用をお願いいたします。