見出し画像

Notes C API探訪: LIST(データ型)その1

LIST型は、いくつか存在するフィールド(アイテム)タイプの中で、複数個のデータを扱う配列型データのヘッダーとして機能します。代表的なのがテキストリストです。

typedef unsigned short USHORT;#include <global.h>
/*	List structure */
typedef struct {
  USHORT ListEntries;			/* list entries following */
               /* now come the list entries */
} LIST;

テキストリスト

テキストリストは、バイト単位の可変長文字列(LMBCS)を可変個数持つデータです。LIST型が表すデータに続いて、個々のデータの長さを表すUSHORT型がデータ数分、そして個々のデータが順番に続きます。以下に、LIST型データのメモリ構成について表にしてみました。

スクリーンショット 2021-07-11 9.53.39

LIST型にはメンバ変数ListEntriesが含まれます。直後にUSHORT型がListEntries分並び、そのあとにテキスト領域が並びます。
LIST::ListEntriesと各アイテムの長さはUSHORT型(unsidned short)なので、アイテム数、アイテムの長さともに65535までになります。
このままだと使い勝手の悪いLIST型ですが、このデータをハンドル化することで、LISTデータを操作するいくつかの関数を使えるようになります。

ListAllocate

ListAllocate関数は、LIST型のデータ領域を生成し、領域をロックしてハンドルとポインタを返します。

#include <textlist.h>
STATUS LNPUBLIC ListAllocate (
  WORD ListEntries,
  WORD TextSize,
  BOOL fPrefixDataType,
  DHANDLE far *rethList,
  void far *retpList,
  WORD far *retListSize);

ListEntriesは、あらかじめ確保するエントリーの数を指定します。
TextSizeは、あらかじめ確保するエントリーテキストのバイト数を指定します。1バイト、2バイト、3バイト、計3つのテキストを予約したい場合は6を指定します。
fPrefixDataTypeは、Notes/Dominoのデータタイププレフィックスを割り当てるメモリに追加するかを指定します(後述)。
rethListは、DHANDLE型データへのポインタを指定します。DHANDLE(Domino Handle)型は汎用のメモリハンドル値です。
retpListは、rethListハンドルデータのロック済みメモリへのポインタへのポインタです。利用先で所有権を譲渡しない限り、アンロックして自身でハンドルを解放する必要があります。
retListSizeは、この関数で取得した領域の全体サイズを返します。

データタイププレフィックス

データタイププレフィックスとは、Notes/Dominoが扱うデータの型を区別するために設けられたWORD型の数値です。Notes C APIの中では、TYPE_***として識別子が定義されています。一部を紹介します。

TYPE_TEXT: (単一)テキスト型
TYPE_TEXT_LIST: テキストリスト型
TYPE_NUMBER: (単一)数値型
TYPE_NUMBER_RANGE: 数値リスト型
TYPE_TIME: (単一)日時型
TYPE_TIME_RANGE: 日時リスト/日時ペアリスト型
TYPE_OBJECT: 添付ファイル/OLEなどのバイナリーデータ型

Notes/Dominoのフィールドでは、これらのWORD値がデータ領域の前に付随します。面倒に感じるかもしれませんが、特にフィールドとやり取りする場合は、Notes C APIではこのデータタイププレフィックスを意識する必要があります。

サンプルコード

DHANDLE hList = NULLHANDLE;
void *pList = nullptr;
WORD listSize = 0;
BOOL fPrefixDataType = TRUE;
STATUS status = ListAllocate(3, 6, fPrefixDataType, &hList, &pList, &listSize);
if (ERR(status) != NOERROR) {
  std::cerr << "ListAllocate error!" << std::endl;
  return;
}
std::cout << "List size: " << listSize << std::endl;
if (!addTextToList(hList, pList, fPrefixDataType, 0, "A")) return;
if (!addTextToList(hList, pList, fPrefixDataType, 1, "12")) return;
if (!addTextToList(hList, pList, fPrefixDataType, 2, "xyz")) return;
outputTextFromList(pList, fPrefixDataType, 0);
outputTextFromList(pList, fPrefixDataType, 1);
outputTextFromList(pList, fPrefixDataType, 2);
OSUnlockObject(hList);
OSMemFree(hList);
return;

bool addTextToList(DHANDLE hList, void *pList, BOOL fPrefixDataType, WORD numEntry, const std::string &text) {
  STATUS status = ListAddText(pList, fPrefixDataType, numEntry, text.c_str(), text.size());
  if (ERR(status) != NOERROR) {
    std::cerr << "ListAddText error!" << std::endl;
    OSUnlockObject(hList);
    OSMemFree(hList);
    return false;
  }
  return true;
}

void outputTextFromList(void *pList, BOOL fPrefixDataType, WORD numEntry) {
  char *pText = nullptr;
  WORD textLength = 0;
  STATUS status = ListGetText(pList, fPrefixDataType, numEntry, &pText, &textLength);
  if (ERR(status) != NOERROR) {
    std::cerr << "ListGetText error! << std::endl;
    return;
  }
  std::string text(pText, textLength);
  std::cout << numEntry << " text is '" << text << "'" << std::endl;
}
// List size: 16
// 0 text is 'A'
// 1 text is '12'
// 2 text is 'xyz'

サンプルでは、エントリー数3、テキスト全体のサイズ6としてリスト用メモリを確保し、"A"、"12"、"xyz"の各文字列を格納し、格納した文字列を取り出して出力しています。
結果が `List size: 16` となっています。ListAllocate関数が返したメモリ領域全体のサイズは、プレフィックス2バイト+LIST構造体2バイト+各エントリーサイズ2バイト×3+テキスト全体のサイズ6=16の算出と合致します。

ListAddText

ListAddText関数は、空のリスト領域にテキストを追加します。

#include <textlist.h>
STATUS LNPUBLIC ListAddText (
  void far *pList,
  BOOL fPrefixDataType,
  WORD EntryNumber,
  const char far *Text,
  WORD TextSize);

pListは、ロックされたLIST領域へのポインタです。
fPrefixDataTypeは、確保している領域にデータタイププレフィックスが含まれるかどうかを示します。
EntryNumberは、テキストを追加するエントリー番号です。
Textは追加するテキストへのポインタです。
TextSizeはテキストサイズです。
この関数は、エントリー数やテキスト領域を再割り当てしないので、ListAllocate関数で領域を確保した直後にリストデータを初期化するものと考えた方がいいでしょう。また、エントリーの位置も0番目から順に割り当てないと正しく設定されないので注意が必要です(逆に格納してみたら、取り出した文字列が崩れました)。

ListGetText

ListGetText関数は、LIST領域の指定したエントリーデータを取り出します。

#include <textlist.h>
STATUS LNPUBLIC ListGetText (
  const void far *pList,
  BOOL fPrefixDataType,
  WORD EntryNumber,
  char far * far *retTextPointer,
  WORD far *retTextLength);

pListは、ロックされたLIST領域へのポインタです。
fPrefixDataTypeは、確保している領域にデータタイププレフィックスが含まれるかどうかを示します。
EntryNumberは、取り出すテキストのエントリー番号です。
retTextPointerは取り出すテキストポインタへのポインタです。
retTextLengthは取り出すテキストサイズへのポインタです。

まとめ

LIST型は、主にテキストリスト(TYPE_TEXT_LIST)を処理するのに使いますが、リファレンスを見る限り以下のようなリストデータがあるようです。

TYPE_NOTEREF_LIST:  返答文書への参照リスト
TYPE_NOTELINK_LIST: 文書リンクのリスト
TYPE_SEAL_LIST: 暗号化のリスト
TYPE_SCHED_LIST: スケジュールリスト

テキストリストを扱う関数はもう少し存在しますので、次回、これらも紹介しようと思います。ここでは紹介できなかったOSLockObject、OSMemFreeについても改めて紹介する機会を設けたいと思います。

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

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