/*――――――――――――――――――――――――――――――――――――――//
    boldbe.c
//――――――――――――――――――――――――――――――――――――――*/

#include <windows.h>

#define  _USE_MATH_DEFINES
#include <math.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <bolalg.h>
#include <bolbas.h>
#define  OWN_USE
#include "boldbe.h"

#define  MODNAM  "BOLDBE"
#define  MODVER  OCTVAL(2,6,0,0)

//――――――――――――――――――――――――――――――――――――――//

  // エラーメッセージ
static CODI eeDBE[] = {
  { E_STA, "静的な表の容量は変更できない" },
  { E_RDO, "読取専用の表は編集できない" },
  { E_FIX, "固定長の表は行編集できない" },
  { E_CAL, "計算項目には値を設定できない" },
  { E_CMP, "同型の表でない" },
  { E_IRO, "行インデックスが不正" },
  { E_ICO, "列インデックスが不正" },
  { E_ITB, "表インデックスが不正" },
  { E_NIN, "この型の項目にはキー値の自動採番を指定できない" },
  { E_NOL, "サイトにログインしていない" },
  { E_DUL, "サイトに二重にログインしようとした" },
  { E_BSA, "この機能を実行する権限(サイト管理者権限)がない" },
  { E_BSD, "この機能を実行する権限(ＤＢ管理者権限)がない" },
  { E_RDW, "この機能を実行する権限(編集ユーザー権限)がない" },
  { E_DBN, "ＤＢ名が不正" },
  { E_DBT, "ＤＢタイトルが長すぎる" },
  { E_DBD, "ＤＢ説明が長すぎる" },
  { E_NOC, "ＤＢに接続していない" },
  { E_DUC, "ＤＢに二重に接続しようとした" },
  { E_LCK, "他のユーザーにロックされている表をロックしようとした" },
  { E_ORO, "読取専用の表を編集モードで開こうとした" },
  { E_ORW, "編集モードで開いている表を再度編集モードで開こうとした" },
  { E_CNF, "他のユーザーの編集内容と競合が発生した" },
  { E_NZR, "非ゼロ制約違反" },
  { E_UNI, "一意性制約違反" },
  { E_CHK, "チェック制約違反" },
  { E_KEY, "主キー制約違反" },
  { E_REF, "外部キー制約違反" },
  { E_NUS, "ユーザー名が必要" },
  { E_NPW, "パスワードが必要" },
  { E_MIS, "表定義情報がない" },
  { E_TBN, "表名が不正" },
  { E_TBT, "表タイトルが長すぎる" },
  { E_TBD, "表説明が長すぎる" },
  { E_CON, "列名が不正" },
  { E_COT, "列タイトルが長すぎる" },
  { E_COD, "列説明が長すぎる" },
  { E_NTP, "型情報がない" },
  { E_NFC, "計算項目にFCALコールバック関数へのポインタがない" },
  { E_NEN, "列挙型にENMS構造体へのポインタがない" },
  { E_NCO, "コード型にCODS構造体へのポインタがない" },
  { E_NSE, "集合型にENMS構造体へのポインタがない" },
  { E_ALN, "アライメント制約違反" },
  { E_RSZ, "行サイズが構造体サイズと一致しない" },
  { E_NKY, "主キー項目が定義されていない" },
  { E_NRF, "外部キー項目が定義されていない" },
  { E_CSZ, "外部参照項目のサイズが参照先の項目のサイズと一致しない" },
  { E_CKY, "計算項目は主キーにできない" },
  { E_RKY, "外部キーの参照先が主キー項目でない" },
  { E_NUN, "外部キーの参照先の主キーが単一キーでない" },
  { E_NOA, "バイトコードがロードされていない" },
};
static CODS emDBE = { eeDBE, _countof(eeDBE) };

rANY WINAPI I4BBox(I4B va)
{ // int値をintへのポインタに変換
  pANY pv = ualloc(4); *(pI4B)pv = va; return pv;
}

rANY WINAPI I8BBox(I8B va)
{ // INT64値をINT64へのポインタに変換
  pANY pv = ualloc(8); *(pI8B)pv = va; return pv;
}

rANY WINAPI F4BBox(F4B va)
{ // float値をfloatへのポインタに変換
  pANY pv = ualloc(4); *(pF4B)pv = va; return pv;
}

rANY WINAPI F8BBox(F8B va)
{ // double値をdoubleへのポインタに変換
  pANY pv = ualloc(8); *(pF8B)pv = va; return pv;
}

#define  TID(co)  ((pU1B)(co))[0]
#define  BTP(co)  ((pU1B)(co))[1]
#define  SIZ(co)  ((pU2B)(co))[1]
#define  WID(co)  ((pU1B)(co))[4]
#define  ALN(co)  ((pU1B)(co))[5]
#define  OFS(co)  ((pU2B)(co))[3]
#define  ATI(co)  ((pU2B)(co))[16]
#define  ACI(co)  ((pU2B)(co))[17]
#define  RTI(co)  ((pU2B)(co))[18]
#define  RCI(co)  ((pU2B)(co))[19]

#define  TIDOF(co)  (TID(co) &~CAL_BIT)
#define  ISCAL(co)  (!!(TID(co) & CAL_BIT))

BOOL LOCALF iszero(rBIN pv, I4B sz)
{ // 空値
  I4B i;

  for (i = 0; i < sz; i++) {
    if (pv[i] != 0) return FALSE;
  }
  return TRUE;
}

I4B  LOCALF defstrlen(rSTR st, I4B df)
{ // 文字列の長さ
  return st? strlen(st): df;
}

I4B  LOCALF defwidENM(rCOLI co)
{ // 文字列長の最大値
  I4B i, ln, wd = 0;
  rENMS ls = (rENMS)co->pa0;

  for (i = 0; i < ls->ni; i++) {
    if ((ln = strlen(ls->ps[i])) > wd) { wd = ln;}
  }
  return wd;
}

I4B  LOCALF defwidCOD(rCOLI co)
{ // 文字列長の最大値
  I4B ln, wd = 0;
  rCODS ls = (rCODS)co->pa0;
  rCODI pc, pe;

  for (pc = ls->pv, pe = pc + ls->ni; pc < pe; pc++) {
    if ((ln = strlen(pc->st)) > wd) { wd = ln;}
  }
  return wd;
}

I4B  LOCALF scnvalSET(rSTR st, rCOLI co)
{ // 文字列からフラグ値を生成
  I4B i, va = 0;
  rENMS ls = (rENMS)co->pa0;

  for (i = 0; i < ls->ni; i++) {
    if (ls->ps[i][0] != '\0' && strfind(st, ls->ps[i])) { va |= (1 << i);}
  }
  return va;
}

pSTR LOCALF prnvalSET(pSTR st, I4B va, rCOLI co)
{ // フラグ値から文字列を生成
  I4B i;
  rENMS ls = (rENMS)co->pa0;

  st[0] = '\0';
  for (i = 0; i < ls->ni; i++) {
    if (va & (1 << i)) { strcats(st, ls->ps[i]);}
  }
  return st;
}

I4B  LOCALF defwidSET(rCOLI co)
{ // 文字列長の合計
  I4B i, wd = 0;
  rENMS ls = (rENMS)co->pa0;

  for (i = 0; i < ls->ni; i++) {
    wd += strlen(ls->ps[i]);
  }
  return wd;
}

rCOLI LOCALF TableColumnInfo0(HTBL tb, I4B ic);
pANY LOCALF GetTableCellValue0(pANY pv, HTBL tb, I4B ir, I4B ic);
pSTR LOCALF PrintTableCellValue0(pSTR st, HTBL tb, I4B ir, I4B ic);

I4B  LOCALF scnvalALT(rSTR st, rCOLI co)
{ // 文字列を外部キー値に変換
  I4B ir, va, id = ATI(co), ic = ACI(co), ix = RTI(co), ik = RCI(co);
  HTBL tb = DBTable(id);

  if (id != ix) { ik = RCI(TableColumnInfo0(DBTable(ix), ik));}
  if ((ir = SearchAlt(tb, ic, st)) >= 0) {
    va = 0; GetTableCellValue0(&va, tb, ir, ik); return va;
  }
  va = ztoi(st); if (va == 0) return 0;
  if (SearchTableCellValue(tb, 0, ik, &va) >= 0) { return va;}
  return 0;
}

pSTR LOCALF prnvalALT(pSTR st, I4B va, rCOLI co)
{ // 外部キー値を文字列に変換
  I4B ir, id = ATI(co), ic = ACI(co), ix = RTI(co), ik = RCI(co);
  HTBL tb = DBTable(id);

  if (id != ix) { ik = RCI(TableColumnInfo0(DBTable(ix), ik));}
  if ((ir = SearchTableCellValue(tb, 0, ik, &va)) >= 0) {
    PrintTableCellValue0(st, tb, ir, ic);
  } else { st[0] = '\0';}
  return st;
}

  // 無効

pANY LOCALF fscnNOP(pANY pv, rSTR st, rCOLI co)
{ // 文字列から読込
  return pv;
}

pSTR LOCALF fprnNOP(pSTR st, rANY pv, rCOLI co)
{ // 文字列に書出
  st[0] = '\0'; return st;
}

I4B  LOCALF fcmpNOP(rANY p1, rANY p2, rCOLI co)
{ // 比較
  return (p1 > p2)? 1: (p1 < p2)? -1: 0;
}

uANY LOCALF flstNOP(I4B im, rCOLI co)
{ // リスト項目
  return (im < 0)? 0: (uANY)"";
}

  // 整数(char)

pANY LOCALF fscnI1B(pANY pv, rSTR st, rCOLI co)
{ // 文字列から読込
  *(pI1B)pv = (I1B)cztoi(st); return pv;
}

pSTR LOCALF fprnI1B(pSTR st, rANY pv, rCOLI co)
{ // 文字列に書出
  sprintfs(st, (rSTR)co->pa0, (I4B)*(rI1B)pv); return st;
}

I4B  LOCALF fcmpI1B(rANY p1, rANY p2, rCOLI co)
{ // 比較
  return *(rI1B)p1 - *(rI1B)p2;
}

  // 整数(BYTE)

pANY LOCALF fscnU1B(pANY pv, rSTR st, rCOLI co)
{ // 文字列から読込
  *(pU1B)pv = (U1B)cztoi(st); return pv;
}

pSTR LOCALF fprnU1B(pSTR st, rANY pv, rCOLI co)
{ // 文字列に書出
  sprintfs(st, (rSTR)co->pa0, (I4B)*(rU1B)pv); return st;
}

I4B  LOCALF fcmpU1B(rANY p1, rANY p2, rCOLI co)
{ // 比較
  return *(rU1B)p1 - *(rU1B)p2;
}

  // 整数(short)

pANY LOCALF fscnI2B(pANY pv, rSTR st, rCOLI co)
{ // 文字列から読込
  *(pI2B)pv = (I2B)cztoi(st); return pv;
}

pSTR LOCALF fprnI2B(pSTR st, rANY pv, rCOLI co)
{ // 文字列に書出
  sprintfs(st, (rSTR)co->pa0, (I4B)*(rI2B)pv); return st;
}

I4B  LOCALF fcmpI2B(rANY p1, rANY p2, rCOLI co)
{ // 比較
  return *(rI2B)p1 - *(rI2B)p2;
}

  // 整数(WORD)

pANY LOCALF fscnU2B(pANY pv, rSTR st, rCOLI co)
{ // 文字列から読込
  *(pU2B)pv = (U2B)cztoi(st); return pv;
}

pSTR LOCALF fprnU2B(pSTR st, rANY pv, rCOLI co)
{ // 文字列に書出
  sprintfs(st, (rSTR)co->pa0, (I4B)*(rU2B)pv); return st;
}

I4B  LOCALF fcmpU2B(rANY p1, rANY p2, rCOLI co)
{ // 比較
  return *(rU2B)p1 - *(rU2B)p2;
}

  // 整数(int)

pANY LOCALF fscnI4B(pANY pv, rSTR st, rCOLI co)
{ // 文字列から読込
  *(pI4B)pv = cztoi(st); return pv;
}

pSTR LOCALF fprnI4B(pSTR st, rANY pv, rCOLI co)
{ // 文字列に書出
  sprintfs(st, (rSTR)co->pa0, *(rI4B)pv); return st;
}

I4B  LOCALF fcmpI4B(rANY p1, rANY p2, rCOLI co)
{ // 比較
  return (*(rI4B)p1 > *(rI4B)p2)? 1: (*(rI4B)p1 < *(rI4B)p2)? -1: 0;
}

  // 整数(UINT)

pANY LOCALF fscnU4B(pANY pv, rSTR st, rCOLI co)
{ // 文字列から読込
  *(pU4B)pv = cztou(st); return pv;
}

pSTR LOCALF fprnU4B(pSTR st, rANY pv, rCOLI co)
{ // 文字列に書出
  sprintfs(st, (rSTR)co->pa0, *(rU4B)pv); return st;
}

I4B  LOCALF fcmpU4B(rANY p1, rANY p2, rCOLI co)
{ // 比較
  return (*(rU4B)p1 > *(rU4B)p2)? 1: (*(rU4B)p1 < *(rU4B)p2)? -1: 0;
}

  // 整数(INT64)

pANY LOCALF fscnI8B(pANY pv, rSTR st, rCOLI co)
{ // 文字列から読込
  *(pI8B)pv = cztoi64(st); return pv;
}

pSTR LOCALF fprnI8B(pSTR st, rANY pv, rCOLI co)
{ // 文字列に書出
  sprintfs(st, (rSTR)co->pa0, *(rI8B)pv); return st;
}

I4B  LOCALF fcmpI8B(rANY p1, rANY p2, rCOLI co)
{ // 比較
  return (*(rI8B)p1 > *(rI8B)p2)? 1: (*(rI8B)p1 < *(rI8B)p2)? -1: 0;
}

  // 整数(UINT64)

pANY LOCALF fscnU8B(pANY pv, rSTR st, rCOLI co)
{ // 文字列から読込
  *(pU8B)pv = cztou64(st); return pv;
}

pSTR LOCALF fprnU8B(pSTR st, rANY pv, rCOLI co)
{ // 文字列に書出
  sprintfs(st, (rSTR)co->pa0, *(rU8B)pv); return st;
}

I4B  LOCALF fcmpU8B(rANY p1, rANY p2, rCOLI co)
{ // 比較
  return (*(rU8B)p1 > *(rU8B)p2)? 1: (*(rU8B)p1 < *(rU8B)p2)? -1: 0;
}

  // 実数(float)

pANY LOCALF fscnF4B(pANY pv, rSTR st, rCOLI co)
{ // 文字列から読込
  *(pF4B)pv = (F4B)cztof(st); return pv;
}

pSTR LOCALF fprnF4B(pSTR st, rANY pv, rCOLI co)
{ // 文字列に書出
  sprintfs(st, (rSTR)co->pa0, (F8B)*(rF4B)pv); return st;
}

I4B  LOCALF fcmpF4B(rANY p1, rANY p2, rCOLI co)
{ // 比較
  return (*(rF4B)p1 > *(rF4B)p2)? 1: (*(rF4B)p1 < *(rF4B)p2)? -1: 0;
}

  // 実数(double)

pANY LOCALF fscnF8B(pANY pv, rSTR st, rCOLI co)
{ // 文字列から読込
  *(pF8B)pv = cztof(st); return pv;
}

pSTR LOCALF fprnF8B(pSTR st, rANY pv, rCOLI co)
{ // 文字列に書出
  sprintfs(st, (rSTR)co->pa0, *(rF8B)pv); return st;
}

I4B  LOCALF fcmpF8B(rANY p1, rANY p2, rCOLI co)
{ // 比較
  return (*(rF8B)p1 > *(rF8B)p2)? 1: (*(rF8B)p1 < *(rF8B)p2)? -1: 0;
}

  // 文字列(char[n])

pANY LOCALF fscnSTR(pANY pv, rSTR st, rCOLI co)
{ // 文字列から読込

  if (co->flg & CF_HCH) {
    st = cipher(st);
  }
  switch (co->flg & (CF_ACT|CF_DCT)) {
  case 0:      st = ctlspc(st); break;
  case CF_DCT: st = delctl(st); break;
  }
  if (co->flg & CF_HAN) {
    st = tohan(st);
  }
  if (co->flg & CF_DSP) {
    st = delspc(st);
  } else {
    switch (co->flg & (CF_LTR|CF_RTR)) {
    case CF_LTR: st = ltrim(st); break;
    case CF_RTR: st = rtrim(st); break;
    case CF_LTR|CF_RTR: st = btrim(st); break;
    }
  }
  if (co->flg & CF_ZEN) {
    st = tozen(st);
  }
  strcpyx(pv, st, SIZ(co) - 1);
  return pv;
}

pSTR LOCALF fprnSTR(pSTR st, rANY pv, rCOLI co)
{ // 文字列に書出
  return strcpys(st, pv);
}

I4B  LOCALF fcmpSTR(rANY p1, rANY p2, rCOLI co)
{ // 比較
  return strcmp(p1, p2);
}

  // バイト列(BYTE[n])

I4B  LOCALF fcmpBIN(rANY p1, rANY p2, rCOLI co)
{ // 比較
  return memcmp(p1, p2, SIZ(co));
}

  // 16進数(UINT)

pANY LOCALF fscnHEX(pANY pv, rSTR st, rCOLI co)
{ // 文字列から読込
  if (*st == '0' && (*(st+1) == 'X' || *(st+1) == 'x')) {
    st += 2;
  }
  *(pU4B)pv = strtoul(tohan(st), NULL, 16); return pv;
}

  // 通貨型(int)

pSTR LOCALF fprnM4B(pSTR st, rANY pv, rCOLI co)
{ // 文字列に書出
  csprintf(st, (rSTR)co->pa0, *(rI4B)pv); return st;
}

  // 通貨型(double)

pSTR LOCALF fprnM8B(pSTR st, rANY pv, rCOLI co)
{ // 文字列に書出
  csprintf(st, (rSTR)co->pa0, *(rF8B)pv); return st;
}

  // 日付型(UINT)

pANY LOCALF fscnYMD(pANY pv, rSTR st, rCOLI co)
{ // 文字列から読込
  *(pU4B)pv = ztod2(st, today()); return pv;
}

pSTR LOCALF fprnYMD(pSTR st, rANY pv, rCOLI co)
{ // 文字列に書出
  dprintf(st, (rSTR)co->pa0, *(rU4B)pv); return st;
}

  // 年月型(UINT)

pANY LOCALF fscnYMN(pANY pv, rSTR st, rCOLI co)
{ // 文字列から読込
  *(pU4B)pv = ztom(st); return pv;
}

pSTR LOCALF fprnYMN(pSTR st, rANY pv, rCOLI co)
{ // 文字列に書出
  dprintf(st, (rSTR)co->pa0, *(rU4B)pv); return st;
}

  // 時刻型(UINT)

pANY LOCALF fscnTIM(pANY pv, rSTR st, rCOLI co)
{ // 文字列から読込
  *(pU4B)pv = ztot(st); return pv;
}

pSTR LOCALF fprnTIM(pSTR st, rANY pv, rCOLI co)
{ // 文字列に書出
  tprintf(st, (rSTR)co->pa0, *(rU4B)pv); return st;
}

  // 日付時刻型(double)

pANY LOCALF fscnDTM(pANY pv, rSTR st, rCOLI co)
{ // 文字列から読込
  *(pF8B)pv = ztodt(st); return pv;
}

pSTR LOCALF fprnDTM(pSTR st, rANY pv, rCOLI co)
{ // 文字列に書出
  dtprintf(st, (rSTR)co->pa0, *(rF8B)pv); return st;
}

  // 列挙型(BYTE)

pANY LOCALF fscnE1B(pANY pv, rSTR st, rCOLI co)
{ // 文字列から読込
  *(pU1B)pv = (U1B)srchenm((rENMS)co->pa0, st); return pv;
}

pSTR LOCALF fprnE1B(pSTR st, rANY pv, rCOLI co)
{ // 文字列に書出
  return strcpys(st, enmstr((rENMS)co->pa0, *(rU1B)pv));
}

uANY LOCALF flstE1B(I4B im, rCOLI co)
{ // リスト項目
  rENMS ls = (rENMS)co->pa0; return (im < 0)? ls->ni: (im < ls->ni)? (uANY)ls->ps[im]: (uANY)"";
}

  // 列挙型(WORD)

pANY LOCALF fscnE2B(pANY pv, rSTR st, rCOLI co)
{ // 文字列から読込
  *(pU2B)pv = (U2B)srchenm((rENMS)co->pa0, st); return pv;
}

pSTR LOCALF fprnE2B(pSTR st, rANY pv, rCOLI co)
{ // 文字列に書出
  return strcpys(st, enmstr((rENMS)co->pa0, *(rU2B)pv));
}

  // 列挙型(UINT)

pANY LOCALF fscnE4B(pANY pv, rSTR st, rCOLI co)
{ // 文字列から読込
  *(pU4B)pv = (U4B)srchenm((rENMS)co->pa0, st); return pv;
}

pSTR LOCALF fprnE4B(pSTR st, rANY pv, rCOLI co)
{ // 文字列に書出
  return strcpys(st, enmstr((rENMS)co->pa0, *(rU4B)pv));
}

  // コード型(BYTE)

pANY LOCALF fscnC1B(pANY pv, rSTR st, rCOLI co)
{ // 文字列から読込
  *(pU1B)pv = (U1B)srchcod((rCODS)co->pa0, st); return pv;
}

pSTR LOCALF fprnC1B(pSTR st, rANY pv, rCOLI co)
{ // 文字列に書出
  return strcpys(st, codstr((rCODS)co->pa0, *(rU1B)pv));
}

uANY LOCALF flstC1B(I4B im, rCOLI co)
{ // リスト項目
  rCODS ls = (rCODS)co->pa0; return (im < 0)? ls->ni: (im < ls->ni)? (uANY)ls->pv[im].st: (uANY)"";
}

  // コード型(WORD)

pANY LOCALF fscnC2B(pANY pv, rSTR st, rCOLI co)
{ // 文字列から読込
  *(pU2B)pv = (U2B)srchcod((rCODS)co->pa0, st); return pv;
}

pSTR LOCALF fprnC2B(pSTR st, rANY pv, rCOLI co)
{ // 文字列に書出
  return strcpys(st, codstr((rCODS)co->pa0, *(rU2B)pv));
}

  // コード型(UINT)

pANY LOCALF fscnC4B(pANY pv, rSTR st, rCOLI co)
{ // 文字列から読込
  *(pU4B)pv = (U4B)srchcod((rCODS)co->pa0, st); return pv;
}

pSTR LOCALF fprnC4B(pSTR st, rANY pv, rCOLI co)
{ // 文字列に書出
  return strcpys(st, codstr((rCODS)co->pa0, *(rU4B)pv));
}

  // 集合型(BYTE)

pANY LOCALF fscnS1B(pANY pv, rSTR st, rCOLI co)
{ // 文字列から読込
  *(pU1B)pv = (U1B)scnvalSET(st, co); return pv;
}

pSTR LOCALF fprnS1B(pSTR st, rANY pv, rCOLI co)
{ // 文字列に書出
  return prnvalSET(st, *(rU1B)pv, co);
}

  // 集合型(WORD)

pANY LOCALF fscnS2B(pANY pv, rSTR st, rCOLI co)
{ // 文字列から読込
  *(pU2B)pv = (U2B)scnvalSET(st, co); return pv;
}

pSTR LOCALF fprnS2B(pSTR st, rANY pv, rCOLI co)
{ // 文字列に書出
  return prnvalSET(st, *(rU2B)pv, co);
}

  // 集合型(UINT)

pANY LOCALF fscnS4B(pANY pv, rSTR st, rCOLI co)
{ // 文字列から読込
  *(pU4B)pv = (U4B)scnvalSET(st, co); return pv;
}

pSTR LOCALF fprnS4B(pSTR st, rANY pv, rCOLI co)
{ // 文字列に書出
  return prnvalSET(st, *(rU4B)pv, co);
}

  // 代替キー(BYTE)

pANY LOCALF fscnA1B(pANY pv, rSTR st, rCOLI co)
{ // 文字列から読込
  *(pU1B)pv = (U1B)scnvalALT(st, co); return pv;
}

pSTR LOCALF fprnA1B(pSTR st, rANY pv, rCOLI co)
{ // 文字列に書出
  return prnvalALT(st, *(rU1B)pv, co);
}

uANY LOCALF flstA1B(I4B im, rCOLI co)
{ // リスト項目
  HTBL tb = DBTable(ATI(co));
  I4B ln = NTableRows(tb), ic = ACI(co);
  I1B bf[LBUF];

  return (im < 0)? ln + 1: (im < ln)? (uANY)stostr(PrintTableCellValue0(bf, tb, im, ic)): (uANY)"";
}

  // 代替キー(WORD)

pANY LOCALF fscnA2B(pANY pv, rSTR st, rCOLI co)
{ // 文字列から読込
  *(pU2B)pv = (U2B)scnvalALT(st, co); return pv;
}

pSTR LOCALF fprnA2B(pSTR st, rANY pv, rCOLI co)
{ // 文字列に書出
  return prnvalALT(st, *(rU2B)pv, co);
}

  // 代替キー(UINT)

pANY LOCALF fscnA4B(pANY pv, rSTR st, rCOLI co)
{ // 文字列から読込
  *(pU4B)pv = (U4B)scnvalALT(st, co); return pv;
}

pSTR LOCALF fprnA4B(pSTR st, rANY pv, rCOLI co)
{ // 文字列に書出
  return prnvalALT(st, *(rU4B)pv, co);
}

  // ascii文字列(char[n])

pANY LOCALF fscnASC(pANY pv, rSTR st, rCOLI co)
{ // 文字列から読込
  return strcpyx(pv, extasc(tohan(st)), SIZ(co) - 1);
}

#define  NUM(n)  ATR(n, ALN_RGT)

  // データ型
static TYPI TIE[128] = {
  { 0,                     0,       fscnNOP, fprnNOP, fcmpNOP, flstNOP, },               //  0
  { ITP(TID_I1B, TID_I1B), NUM( 4), fscnI1B, fprnI1B, fcmpI1B, flstNOP, (uANY)"%d",},    //  1
  { ITP(TID_U1B, TID_U1B), NUM( 4), fscnU1B, fprnU1B, fcmpU1B, flstNOP, (uANY)"%d", },   //  2
  { ITP(TID_I2B, TID_I2B), NUM( 6), fscnI2B, fprnI2B, fcmpI2B, flstNOP, (uANY)"%d", },   //  3
  { ITP(TID_U2B, TID_U2B), NUM( 6), fscnU2B, fprnU2B, fcmpU2B, flstNOP, (uANY)"%d", },   //  4
  { ITP(TID_I4B, TID_I4B), NUM(11), fscnI4B, fprnI4B, fcmpI4B, flstNOP, (uANY)"%d", },   //  5
  { ITP(TID_U4B, TID_U4B), NUM(11), fscnU4B, fprnU4B, fcmpU4B, flstNOP, (uANY)"%u", },   //  6
  { ITP(TID_I8B, TID_I8B), NUM(13), fscnI8B, fprnI8B, fcmpI8B, flstNOP, (uANY)"%lld", }, //  7
  { ITP(TID_U8B, TID_U8B), NUM(13), fscnU8B, fprnU8B, fcmpU8B, flstNOP, (uANY)"%llu", }, //  8
  { ITP(TID_F4B, TID_F4B), NUM(11), fscnF4B, fprnF4B, fcmpF4B, flstNOP, (uANY)"%.6G", }, //  9
  { ITP(TID_F8B, TID_F8B), NUM(11), fscnF8B, fprnF8B, fcmpF8B, flstNOP, (uANY)"%.15G", },// 10
  { ITP(TID_STR, TID_STR), 0,       fscnSTR, fprnSTR, fcmpSTR, flstNOP, },               // 11
  { ITP(TID_BIN, TID_BIN), 0,       fscnNOP, fprnNOP, fcmpBIN, flstNOP, },               // 12
  { ITP(TID_HEX, TID_U4B), NUM( 8), fscnHEX, fprnU4B, fcmpU4B, flstNOP, (uANY)"%X", },   // 13
  { ITP(TID_M4B, TID_I4B), NUM(13), fscnI4B, fprnM4B, fcmpI4B, flstNOP, (uANY)"%d", },   // 14
  { ITP(TID_M8B, TID_F8B), NUM(13), fscnF8B, fprnM8B, fcmpF8B, flstNOP, (uANY)"%.0f", }, // 15
  { ITP(TID_YMD, TID_U4B), 0,       fscnYMD, fprnYMD, fcmpU4B, flstNOP, (uANY)"yyyy/mm/dd", },
  { ITP(TID_YMN, TID_U4B), 0,       fscnYMN, fprnYMN, fcmpU4B, flstNOP, (uANY)"yyyy/mm", },
  { ITP(TID_TIM, TID_U4B), 0,       fscnTIM, fprnTIM, fcmpU4B, flstNOP, (uANY)"hh:mm:ss", },
  { ITP(TID_DTM, TID_F8B), 0,       fscnDTM, fprnDTM, fcmpF8B, flstNOP, (uANY)"yyyy/mm/dd hh:mm:ss", },
  { ITP(TID_E1B, TID_U1B), 0,       fscnE1B, fprnE1B, fcmpU1B, flstE1B, },               // 20
  { ITP(TID_E2B, TID_U2B), 0,       fscnE2B, fprnE2B, fcmpU2B, flstE1B, },               // 21
  { ITP(TID_E4B, TID_U4B), 0,       fscnE4B, fprnE4B, fcmpU4B, flstE1B, },
  { ITP(TID_C1B, TID_U1B), 0,       fscnC1B, fprnC1B, fcmpU1B, flstC1B, },
  { ITP(TID_C2B, TID_U2B), 0,       fscnC2B, fprnC2B, fcmpU2B, flstC1B, },
  { ITP(TID_C4B, TID_U4B), 0,       fscnC4B, fprnC4B, fcmpU4B, flstC1B, },               // 25
  { ITP(TID_S1B, TID_U1B), 0,       fscnS1B, fprnS1B, fcmpU1B, flstNOP, },
  { ITP(TID_S2B, TID_U2B), 0,       fscnS2B, fprnS2B, fcmpU2B, flstNOP, },
  { ITP(TID_S4B, TID_U4B), 0,       fscnS4B, fprnS4B, fcmpU4B, flstNOP, },
  { ITP(TID_A1B, TID_U1B), 0,       fscnA1B, fprnA1B, fcmpU1B, flstA1B, },
  { ITP(TID_A2B, TID_U2B), 0,       fscnA2B, fprnA2B, fcmpU2B, flstA1B, },               // 30
  { ITP(TID_A4B, TID_U4B), 0,       fscnA4B, fprnA4B, fcmpU4B, flstA1B, },
  { ITP(TID_ASC, TID_STR), 0,       fscnASC, fprnSTR, fcmpSTR, flstNOP, },
};

pANY LOCALF tp_fscn0(pANY pv, rSTR st, rCOLI co)
{ // 文字列から読込
  return TIE[TIDOF(co)].fscn(pv, st, co);
}

pSTR LOCALF tp_fprn0(pSTR st, rANY pv, rCOLI co)
{ // 文字列に書出
  return TIE[TIDOF(co)].fprn(st, pv, co);
}

I4B  LOCALF tp_fcmp0(rANY p1, rANY p2, rCOLI co)
{ // 比較
  return TIE[TIDOF(co)].fcmp(p1, p2, co);
}

uANY LOCALF tp_flst0(I4B im, rCOLI co)
{ // リスト項目
  return TIE[TIDOF(co)].flst(im, co);
}

pANY LOCALF co_fcal0(pANY pv, rANY pb, rCOLI co)
{ // 計算項目
  return co->fcal(pv, pb, co);
}

BOOL LOCALF co_fchk0(rANY pb, rCOLI co)
{ // チェック
  return co->fchk(pb, co);
}

  // 型関数
static FSCN tp_fscn = tp_fscn0;
static FPRN tp_fprn = tp_fprn0;
static FCMP tp_fcmp = tp_fcmp0;
static FLST tp_flst = tp_flst0;

  // 列関数
static FCAL co_fcal = co_fcal0;
static FCHK co_fchk = co_fchk0;

pANY LOCALF scnval(pANY pv, rSTR st, rCOLI co)
{ // 文字列から読込
  if (ISCAL(co)) { return pv;}
  return tp_fscn(pv, st, co);
}

pANY LOCALF cscnval(pANY pv, rSTR st, rCOLI co)
{ // 文字列から読込(計算項目にも適用)
  return tp_fscn(pv, st, co);
}

void LOCALF setval(pU1B pb, rANY pv, rCOLI co)
{ // 値の設定
  if (BTP(co) == TID_STR) {
    strcpyx(pb + OFS(co), pv, SIZ(co) - 1); return;
  }
  memcpy(pb + OFS(co), pv, SIZ(co));
}

pANY LOCALF getval(pANY pv, rANY pb, rCOLI co)
{ // 値の取得
  if (ISCAL(co)) { return co_fcal(pv, pb, co);}
  return memcpy(pv, (rBIN)pb + OFS(co), SIZ(co));
}

pSTR LOCALF prnval(pSTR st, rANY pv, rCOLI co)
{ // 文字列に書出
  U1B rv[LBUF];

  if (ISCAL(co)) { pv = co_fcal(rv, pv, co);}
  if ((co->flg & CF_HZR) && iszero(pv, SIZ(co))) { st[0] = '\0'; return st;}
  if ((co->flg & CF_HCH) && BTP(co) == TID_STR) { return strcpys(st, cipher((pSTR)pv));}
  return tp_fprn(st, pv, co);
}

pSTR LOCALF cprnval(pSTR st, rANY pv, rCOLI co)
{ // 文字列に書出(計算項目にも適用)
  COLI coe;

  if (ISCAL(co)) { coe = *co; TID(&coe) = TIDOF(co); co = &coe;}
  return tp_fprn(st, pv, co);
}

pSTR LOCALF vprnval(pSTR st, rANY pv, rCOLI co)
{ // 文字列に書出(書式無し)
  switch (TIDOF(co)) {
  case TID_HEX: sprintfs(st, "0x%X", *(rU4B)pv); break;
  case TID_YMD:
  case TID_YMN: dprintf(st, "'yyyy/mm/dd'", *(rU4B)pv); break;
  case TID_TIM: tprintf(st, "'hh:mm:ss'", *(rU4B)pv); break;
  case TID_DTM: dtprintf(st, "'yyyy/mm/dd hh:mm:ss'", *(rF8B)pv); break;
  default:
    switch (BTP(co)) {
    case TID_I1B: sprintfs(st, "%d", (I4B)*(rI1B)pv); break;
    case TID_U1B: sprintfs(st, "%d", (I4B)*(rU1B)pv); break;
    case TID_I2B: sprintfs(st, "%d", (I4B)*(rI2B)pv); break;
    case TID_U2B: sprintfs(st, "%d", (I4B)*(rU2B)pv); break;
    case TID_I4B: sprintfs(st, "%d", *(rI4B)pv); break;
    case TID_U4B: sprintfs(st, "%u", *(rU4B)pv); break;
    case TID_I8B: sprintfs(st, "%lldL", *(rI8B)pv); break;
    case TID_U8B: sprintfs(st, "%lluL", *(rU8B)pv); break;
    case TID_F4B: sprintfs(st, "%.6G", (F8B)*(rF4B)pv); break;
    case TID_F8B: sprintfs(st, "%.15G", *(rF8B)pv); break;
    case TID_STR: sprintfs(st, "'%s'", (rSTR)pv); break;
    default: st[0] = '\0'; break;
    }
    break;
  }
  if (st[0] == '\0') { sprintfs(st, "''");}
  return st;
}

pANY LOCALF clrval(pANY pv, rANY pb, rCOLI co)
{ // 初期化
  if (ISCAL(co)) { return pv;}
  return co->fcal? co_fcal(pv, pb, co): memset(pv, 0, SIZ(co));
}

I4B  LOCALF cmpval(rANY p1, rANY p2, rCOLI co)
{ // 比較
  U1B r1[LBUF], r2[LBUF];

  if (ISCAL(co)) { p1 = co_fcal(r1, p1, co); p2 = co_fcal(r2, p2, co);}
  return tp_fcmp(p1, p2, co);
}

I4B  LOCALF wcmpval(rANY pv, rANY wk, rCOLI co)
{ // 比較
  U1B rv[LBUF];

  if (ISCAL(co)) { pv = co_fcal(rv, pv, co);}
  return tp_fcmp(pv, wk, co);
}

BOOL LOCALF wmlkval(rANY pv, rANY wk, rCOLI co)
{ // 含む
  U1B rv[LBUF];

  if (ISCAL(co)) { pv = co_fcal(rv, pv, co);}
  switch (BTP(co)) {
  case TID_I1B: case TID_U1B:
    return (*(rU1B)pv & *(rU1B)wk) == *(rU1B)wk;
  case TID_I2B: case TID_U2B:
    return (*(rU2B)pv & *(rU2B)wk) == *(rU2B)wk;
  case TID_I4B: case TID_U4B:
    return (*(rU4B)pv & *(rU4B)wk) == *(rU4B)wk;
  case TID_I8B: case TID_U8B:
    return (*(rU8B)pv & *(rU8B)wk) == *(rU8B)wk;
  case TID_STR:
    return strmlike((rSTR)pv, (rSTR)wk);
  }
  return FALSE;
}

pANY LOCALF cpyval(pANY p1, rCOLI c1, rANY p2, rCOLI c2)
{ // 値のコピー
  I1B bf[LBUF];

  if (ISCAL(c1)) { return p1;}
  if (TID(c1) == TID(c2)) {
    memcpy(p1, p2, SIZ(c1));
  } else {
    scnval(p1, prnval(bf, p2, c2), c1);
  }
  return p1;
}

BOOL LOCALF chkval(rANY pb, rCOLI co)
{ // チェック
  if (ISCAL(co)) return TRUE;
  return co->fchk? co_fchk(pb, co): TRUE;
}

I4B  LOCALF defwid(rCOLI co)
{ // 表示幅
  I4B ln, wd;

  switch (TIDOF(co)) {
  case TID_STR: case TID_ASC:
    wd = (I4B)(128.0 * (1.0 - 127.0 / (SIZ(co) + 127.0))); break;
  case TID_BIN:
    return 0;
  case TID_YMD:
    wd = defstrlen((rSTR)co->pa0, 10); break;
  case TID_YMN:
    wd = defstrlen((rSTR)co->pa0, 7); break;
  case TID_TIM:
    wd = defstrlen((rSTR)co->pa0, 8); break;
  case TID_DTM:
    wd = 18; break;
  case TID_E1B: case TID_E2B: case TID_E4B:
    wd = defwidENM(co); break;
  case TID_C1B: case TID_C2B: case TID_C4B:
    wd = defwidCOD(co); break;
  case TID_S1B: case TID_S2B: case TID_S4B:
    wd = defwidSET(co); break;
  case TID_A1B: case TID_A2B: case TID_A4B:
    wd = TableColumnWidth(DBTable(ATI(co)), ACI(co)); break;
  default:
    wd = WID(&TIE[TIDOF(co)]); break;
  }
  if ((ln = strlen(co->tit)) > wd) { wd = ln;}
  return wd;
}

I4B  LOCALF defaln(rCOLI co)
{ // 既定の文字揃えコード
  return ALN(&TIE[TIDOF(co)]);
}

I4B  LOCALF colsiz(rCOLI co)
{ // サイズ
  rCOLI cx = (rCOLI)&TIE[TIDOF(co)];

  return (BTP(cx) == TID_STR || BTP(cx) == TID_BIN)? SIZ(co): ctpsiz(BTP(cx));
}

BOOL LOCALF chkenm(rCOLI co)
{ // ENMS構造体のチェック
  I4B i;
  rENMS ls = (rENMS)co->pa0;

  if (!ls->ps) return FALSE;
  for (i = 0; i < ls->ni; i++) {
    if (!ls->ps[i]) return FALSE;
  }
  return TRUE;
}

BOOL LOCALF chkcod(rCOLI co)
{ // CODS構造体のチェック
  rCODS ls = (rCODS)co->pa0;
  rCODI pc, pe;

  if (!ls->pv) return FALSE;
  for (pc = ls->pv, pe = pc + ls->ni; pc < pe; pc++) {
    if (!pc->st) return FALSE;
  }
  return TRUE;
}

pANY LOCALF fcalREF(pANY pv, rANY pb, rCOLI co)
{ // ビュー項目
  I4B ir;
  HTBL tx = DBTable(RTI(co));
  HBUF rx;

  memset(pv, 0, SIZ(co));
  rx = CreateRowBuf(tx); if (!rx) { return pv;}
  CopyKey(rx, MakeRowBuf(CHTBL(co), (pANY)pb));
  ir = SearchKey(tx, rx);
  DeleteRowBuf(rx);
  if (ir >= 0) {
    GetTableCellValue0(pv, tx, ir, RCI(co));
  }
  return pv;
}

BOOL LOCALF setcol(pCOLI co, rCOLI pc, I4B i)
{ // 列情報の設定
  *co = *pc;
  co->itp = TIE[TIDOF(co)].itp | (ISCAL(pc)? CAL_BIT: 0);
  SIZ(co) = colsiz(pc);
  if (!co->nam || co->nam[0] == '\0') { co->nam = stostr(format("_%03d", i + 1));}
  else if (strlen(co->nam) >= 16 || !isidn(co->nam)) { return (BOOL)ierr(E_CON);}
  if (!co->tit || co->tit[0] == '\0') { co->tit = co->nam;}
  else if (strlen(co->tit) >= 32) { return (BOOL)ierr(E_COT);}
  if (!co->dsc || co->dsc[0] == '\0') { co->dsc = co->tit;}
  else if (strlen(co->dsc) >= 64) { return (BOOL)ierr(E_COD);}
  if (TIDOF(co) == 0) { return (BOOL)ierr(E_NTP);}
  if (ISCAL(co) && !co->fcal) {
    if (co->flg & CF_REF) { co->fcal = fcalREF;} else { return (BOOL)ierr(E_NFC);}
  }
  if (!co->pa0) { co->pa0 = TIE[TIDOF(co)].pa0;}
  if (!co->pa1) { co->pa1 = TIE[TIDOF(co)].pa1;}
  if (!co->pa2) { co->pa2 = TIE[TIDOF(co)].pa2;}
  switch (TIDOF(co)) {
  case TID_E1B: case TID_E2B: case TID_E4B:
    if (!co->pa0) { return (BOOL)ierr(E_NEN);}
    if (!chkenm(co)) { return (BOOL)ierr(E_DAT);}
    break;
  case TID_C1B: case TID_C2B: case TID_C4B:
    if (!co->pa0) { return (BOOL)ierr(E_NCO);}
    if (!chkcod(co)) { return (BOOL)ierr(E_DAT);}
    break;
  case TID_S1B: case TID_S2B: case TID_S4B:
    if (!co->pa0) { return (BOOL)ierr(E_NSE);}
    if (!chkenm(co)) { return (BOOL)ierr(E_DAT);}
    break;
  }
  if (WID(co) == 0) { WID(co) = defwid(co);} else if (WID(co) == WID_FRC) { WID(co) = WID_HID;}
  if (ALN(co) == 0) { ALN(co) = defaln(co);} else if (ALN(co) == ALN_FRC) { ALN(co) = ALN_LFT;}
  if (ISCAL(co) || WID(co) == WID_HID) { co->flg |= CF_DED;}
  return TRUE;
}

void LOCALF setovrflg(pI4B pf, I4B flg, BOOL ov)
{ // フラグの設定
  if (ov) { *pf |= flg;} else { *pf &=~flg;}
}

void WINAPI override_tp_fscn(FSCN fscn)
{ // 型関数(文字列から読込)の設定
  tp_fscn = fscn;
}

void WINAPI override_tp_fprn(FPRN fprn)
{ // 型関数(文字列に書出)の設定
  tp_fprn = fprn;
}

void WINAPI override_tp_fcmp(FCMP fcmp)
{ // 型関数(比較)の設定
  tp_fcmp = fcmp;
}

void WINAPI override_tp_flst(FLST flst)
{ // 型関数(リスト項目)の設定
  tp_flst = flst;
}

BOOL WINAPI RegisterColumnTypeX(rTYPI tp, BOOL ov)
{ // 型の登録
  I4B id, bt, flg;

  id = TID(tp); if (id <= 0 || id >= _countof(TIE)) { return (BOOL)ierr(E_DAT);}
  bt = BTP(tp); if (bt <= 0 || bt >= _countof(TIE) || TIE[bt].itp == 0) { return (BOOL)ierr(E_DAT);}
  TIE[id] = *tp;
  flg = TIE[bt].flg;
  if (TIE[id].fscn) { setovrflg(&flg, CF_OSC, ov);} else { TIE[id].fscn = TIE[bt].fscn;}
  if (TIE[id].fprn) { setovrflg(&flg, CF_OPR, ov);} else { TIE[id].fprn = TIE[bt].fprn;}
  if (TIE[id].fcmp) { setovrflg(&flg, CF_OCM, ov);} else { TIE[id].fcmp = TIE[bt].fcmp;}
  if (TIE[id].flst) { setovrflg(&flg, CF_OLS, ov);} else { TIE[id].flst = TIE[bt].flst;}
  TIE[id].flg = flg;
  if (bt > TID_BIN) { bt = BTP(&TIE[bt]);}
  BTP(&TIE[id]) = bt;
  return TRUE;
}

BOOL WINAPI RegisterColumnType(rTYPI tp)
{ // 型の登録
  return RegisterColumnTypeX(tp, FALSE);
}

rTYPI WINAPI ColumnType(rCOLI co)
{ // 登録型
  return &TIE[TIDOF(co)];
}

void WINAPI override_co_fcal(FCAL fcal)
{ // 列関数(計算項目)の設定
  co_fcal = fcal;
}

void WINAPI override_co_fchk(FCHK fchk)
{ // 列関数(チェック)の設定
  co_fchk = fchk;
}

pANY WINAPI ColumnScan(pANY pv, rSTR st, rCOLI co)
{ // 文字列から読込
  COLI coe;

  if (!setcol(&coe, co, 0)) { return pv;}
  return scnval(pv, st, &coe);
}

pSTR WINAPI ColumnPrint(pSTR st, rANY pv, rCOLI co)
{ // 文字列に書出
  COLI coe;

  if (!setcol(&coe, co, 0) || ISCAL(co)) { return st;}
  return prnval(st, pv, &coe);
}

uANY WINAPI ColumnList(I4B im, rCOLI co)
{ // リスト項目
  return tp_flst(im, co);
}

rANY WINAPI VPtr(rANY pb, rCOLI co)
{ // 項目のアドレス
  return (rBIN)pb + OFS(co);
}

//――――――――――――――――――――――――――――――――――――――//

BOOL LOCALF tb_ftrg0(HTBL tb, I4B msg, I4B ir, pANY pb)
{ // トリガ関数呼び出し
  return tb->ftrg(tb, msg, ir, pb);
}

  // トリガ関数
static FTRG tb_ftrg = tb_ftrg0;

void WINAPI override_tb_ftrg(FTRG ftrg)
{ // トリガ関数の設定
  tb_ftrg = ftrg;
}

HTBL WINAPI CHTBL(rCOLI co)
{ // 表ハンドル
  return (HTBL)co->pa3;
}

#define  UCAP  256

rSTR LOCALF deftblimp(HTBL tb, rSTR nam)
{ // 既定の表ファイル名
  return nam? stostr(nam): addext(tb->nam, (tb->flg & TF_CYP)? ".BTC": ".BTB");
}

HTBL WINAPI CreateTableX(pANY pv, I4B len, I4B cap, rTBLI ti)
{ // 表作成
  I4B i, nc, ofs, mem, aln, flg;
  HTBL tb;
  HBLK mb;
  pCOLS cx;
  pCOLI co, ci;

  if (cap <= 0) { cap = UCAP;}
  if (len > cap) { cap = len;}
  nc = ti->cs->nc;
  tb = halloc(sizeof(TBLE) + sizeof(BLKE) + sizeof(COLS) + nc * sizeof(COLI), FALSE);
  if (!tb) { return ierr(E_MEM);}
  mb = (pANY)((pBIN)tb + sizeof(TBLE));
  cx = (pANY)((pBIN)mb + sizeof(BLKE));
  co = (pANY)((pBIN)cx + sizeof(COLS));
  flg = ti->flg;
  ofs = 0;
  mem = 1;
  for (i = 0, ci = co; i < nc; i++, ci++) {
    if (!setcol(ci, ti->cs->co + i, i)) { hfree(tb); return NULL;}
    if (ISCAL(ci)) {
      OFS(ci) = 0;
    } else {
      OFS(ci) = ofs;
      aln = (BTP(ci) <= TID_F8B)? ctpsiz(BTP(ci)): 1;
      if (ofs % aln != 0 && !(flg & TF_NOA)) { hfree(tb); return ierr(E_ALN);}
      if (aln > mem) { mem = aln;}
      ofs += SIZ(ci);
    }
    ci->pa3 = (uANY)tb;
  }
  if (ofs % mem != 0 && !(flg & TF_NOA)) { hfree(tb); return ierr(E_ALN);}
  if (ti->rsz != 0 && ofs != ti->rsz) { hfree(tb); return ierr(E_RSZ);}
  if (flg & TF_IMP) { flg |= TF_RDO;}
  if (!pv) {
    pv = halloc(cap * ofs, FALSE); if (!pv) { hfree(tb); return ierr(E_MEM);}
  } else {
    flg |= TF_STA;
  }
  tb->mb = BuildArray(mb, pv, len, cap, ofs);
  cx->co = co;
  cx->nc = nc;
  tb->cs = cx;
  tb->vr = tb->vc = NULL;
  tb->otb = NULL;
  tb->nam = ti->nam? ti->nam: "NONAME";
  tb->tit = ti->tit? ti->tit: tb->nam;
  tb->dsc = ti->dsc? ti->dsc: tb->tit;
  tb->flg = flg;
  tb->ftrg= ti->ftrg;
  tb->imp = deftblimp(tb, ti->imp);
  tb->ext = ti->ext;
  return tb;
}

HTBL WINAPI CreateTable(I4B cap, rTBLI ti)
{ // 表作成
  return CreateTableX(NULL, 0, cap, ti);
}

void WINAPI DeleteTable(HTBL tb)
{ // 表の削除
  if (!tb) return;
  if (!(tb->flg & (TF_STA|TF_STB|TF_VIW))) { hfree(TablePtr(tb));}
  if (tb->flg & TF_VIW) { hfree(tb->vr->pi);}
  if (tb->flg & TF_TMP) return;
  hfree(tb);
}

I4B  WINAPI NTableKeys(HTBL tb)
{ // 主キーの数
  I4B n = 0, nc = tb->cs->nc;
  rCOLI co = tb->cs->co, ci, ce;

  for (ci = co, ce = co + nc; ci < ce; ci++) {
    if (ci->flg & CF_KEY) { n++;}
  }
  return n;
}

I4B  WINAPI NTableRefs(HTBL tb, pI4B pi)
{ // 外部キー制約項目の数
  I4B n = 0, nc = tb->cs->nc;
  rCOLI co = tb->cs->co, ci, ce;

  for (ci = co, ce = co + nc; ci < ce; ci++) {
    if (!ISCAL(ci) && (ci->flg & CF_REF)) {
      if (pi) { pi[n] = RTI(ci);}
      n++;
    }
  }
  return n;
}

HTBL WINAPI CreateCompatibleTable(HTBL tb, I4B cap)
{ // 同型表作成
  pANY pv;
  HTBL tc;
  HBLK mb;

  if (cap <= 0) { cap = UCAP;}
  tc = halloc(sizeof(TBLE) + sizeof(BLKE), FALSE); if (!tc) { return ierr(E_MEM);}
  mb = (pANY)((pBIN)tc + sizeof(TBLE));
  pv = halloc(cap * TableRowSize(tb), FALSE); if (!pv) { hfree(tc); return ierr(E_MEM);}
  *tc = *tb;
  tc->mb = BuildArray(mb, pv, 0, cap, TableRowSize(tb));
  tc->flg = tb->flg &~(TF_STA|TF_STB|TF_VIW);
  return tc;
}

BOOL WINAPI IsCompatible(HTBL tb, HTBL tx)
{ // 表が同型
  I4B of1, of2, ni, nj;
  rCOLS cs = tb->cs, cx = tx->cs;
  rCOLI ci, cj, ce, cf;

  if (cs == cx) return TRUE;
  ni = of1 = 0;
  for (ci = cs->co, ce = ci + cs->nc; ci < ce; ci++) {
    if (ISCAL(ci)) continue;
    ni++;
    of2 = 0;
    for (cj = cx->co, cf = cj + cx->nc; cj < cf; cj++) {
      if (ISCAL(cj)) continue;
      if (of1 == of2 && ci->itp == cj->itp && !strcmp(ci->nam, cj->nam)) goto _10;
      of2 += SIZ(cj);
    }
    return FALSE;
   _10:
    of1 += SIZ(ci);
  }
  nj = 0;
  for (cj = cx->co, cf = cj + cx->nc; cj < cf; cj++) {
    if (ISCAL(cj)) continue;
    nj++;
  }
  return ni == nj;
}

HTBL WINAPI DuplicateTable(HTBL tb)
{ // 表の複製
  HTBL tc;

  tc = CreateCompatibleTable(tb, Capacity(tb->mb)); if (!tc) return NULL;
  CopyArray(tc->mb, tb->mb);
  return tc;
}

I4B  WINAPI TableRowSize(HTBL tb)
{ // 行のサイズ
  return ItemSize(tb->mb);
}

I4B  WINAPI NTableRows(HTBL tb)
{ // 行数
  return Len(tb->mb);
}

pANY WINAPI TablePtr(HTBL tb)
{ // 表データの先頭アドレス
  return Ptr(tb->mb);
}

pANY WINAPI Row(HTBL tb, I4B ir)
{ // 行のアドレス
  return Item(tb->mb, ir);
}

pANY WINAPI TableRow(HTBL tb, I4B ir)
{ // 行のアドレス
  if (ir < 0 || ir >= NTableRows(tb)) { ierr(E_IRO); return valloc(TableRowSize(tb));}
  return Row(tb, ir);
}

I4B  WINAPI TableRowIndex(HTBL tb, rANY pb)
{ // 行のアドレスから行インデックスを求める
  return ((pBIN)pb - (pBIN)TablePtr(tb)) / TableRowSize(tb);
}

I4B  WINAPI TableCapacity(HTBL tb)
{ // 最大行数
  return Capacity(tb->mb);
}

BOOL LOCALF ChangeTableCapacity0(HTBL tb, I4B cap)
{ // 最大行数の変更
  BLKE blk;

  if (cap < NTableRows(tb)) { return (BOOL)ierr(E_PAR);}
  if (tb->flg & TF_STA) { return (BOOL)ierr(E_STA);}
  cap = nbound(cap, UCAP);
  if (tb->flg & TF_VIW) {
    BuildArray(&blk, tb->vr->pi, tb->vr->ni, TableCapacity(tb), sizeof(I4B));
    if (!ChangeCapacity(&blk, cap)) return FALSE;
    tb->vr->pi = (pI4B)Ptr(&blk);
  }
  return ChangeCapacity(tb->mb, cap);
}

BOOL WINAPI ChangeTableCapacity(HTBL tb, I4B cap)
{ // 最大行数の変更
  if (tb->flg & TF_RDO) { return (BOOL)ierr(E_RDO);}
  if (tb->flg & TF_FIX) { return (BOOL)ierr(E_FIX);}
  return ChangeTableCapacity0(tb, cap);
}

rSTR WINAPI TableName(HTBL tb)
{ // 表名
  return tb->nam;
}

void WINAPI SetTableTitle(HTBL tb, rSTR tit)
{ // 表タイトルの設定
  tb->tit = tit? tit: tb->nam;
}

rSTR WINAPI TableTitle(HTBL tb)
{ // 表タイトル
  return tb->tit;
}

void WINAPI SetTableDescription(HTBL tb, rSTR dsc)
{ // 表説明の設定
  tb->dsc = dsc? dsc: tb->tit;
}

rSTR WINAPI TableDescription(HTBL tb)
{ // 表説明
  return tb->dsc;
}

void WINAPI SetTableFlags(HTBL tb, I4B flg)
{ // 表属性の設定
  tb->flg = flg;
}

I4B  WINAPI TableFlags(HTBL tb)
{ // 表属性
  return tb->flg;
}

void WINAPI SetTableFileName(HTBL tb, rSTR nam)
{ // 表ファイル名の設定
  tb->imp = deftblimp(tb, nam);
}

rSTR WINAPI TableFileName(HTBL tb)
{ // 表ファイル名
  return tb->imp;
}

void WINAPI SetTableExtra(HTBL tb, uANY pa)
{ // 表の付加情報の設定
  tb->ext = pa;
}

uANY WINAPI TableExtra(HTBL tb)
{ // 表の付加情報
  return tb->ext;
}

I4B  LOCALF srchval(HTBL tb, I4B ir, rANY pb, rCOLI co)
{ // 一意性チェック
  I4B ln = NTableRows(tb), sz = TableRowSize(tb);
  rBIN pc, p0, pi, pe;

  for (pc = p0 = TablePtr(tb), pi = p0 + ir * sz, pe = p0 + ln * sz; pc < pe; pc += sz) {
    if (!memcmp(pc + OFS(co), (pBIN)pb + OFS(co), SIZ(co)) && pc != pi) {
      return (pc - p0) / sz;
    }
  }
  return -1;
}

I4B  LOCALF srchkey(HTBL tb, I4B ir, rANY pb)
{ // 主キーの一意性チェック
  I4B ln = NTableRows(tb), nc = NTableColumns(tb), sz = TableRowSize(tb);
  rBIN pc, p0, pi, pe;
  rCOLI co = tb->cs->co, ci, ce;

  for (pc = p0 = TablePtr(tb), pi = p0 + ir * sz, pe = p0 + ln * sz; pc < pe; pc += sz) {
    for (ci = co, ce = co + nc; ci < ce; ci++) {
      if (ci->flg & CF_KEY) {
        if (memcmp(pc + OFS(ci), (pBIN)pb + OFS(ci), SIZ(ci))) goto _10;
      }
    }
    if (pc != pi) { return (pc - p0) / sz;}
   _10:;
  }
  return -1;
}

I4B  LOCALF srchref(HTBL tb, I4B id, rANY pb)
{ // 外部キーによるサーチ
  I4B ir;
  HTBL tx;
  HBUF rx;

  tx = DBTable(id);
  rx = CreateRowBuf(tx); if (!rx) return -1;
  CopyKey(rx, MakeRowBuf(tb, (pANY)pb));
  ir = SearchKey(tx, rx);
  DeleteRowBuf(rx);
  return ir;
}

BOOL LOCALF zeroref(HTBL tb, I4B id, rANY pb)
{ // 外部キーに空値がある
  I4B nc = tb->cs->nc;
  rCOLI co = tb->cs->co, ci, ce;

  for (ci = co, ce = co + nc; ci < ce; ci++) {
    if (!ISCAL(ci) && (ci->flg & CF_REF) && RTI(ci) == id) {
      if (iszero((pBIN)pb + OFS(ci), SIZ(ci))) return TRUE;
    }
  }
  return FALSE;
}

#define  terr(ec, ir, ic)  serr(ec, TableName(tb), ir, ic)

BOOL WINAPI DefaultTableTrigger(HTBL tb, I4B msg, I4B ir, pANY pb)
{ // 既定のトリガ関数
  I4B i, nc, nt, id[64];
  rCOLI co, ci;

  switch (LOU2B(msg)) {
  case TRGM_BEFOREUPDATEOF:
    i = HIU2B(msg);
    co = &tb->cs->co[HIU2B(msg)];
    if (!chkval(pb, co)) { return (BOOL)terr(E_CHK, ir, i);}
    if (co->flg & CF_NZR) {
      if (iszero((pBIN)pb + OFS(co), SIZ(co))) { return (BOOL)terr(E_NZR, ir, i);}
    }
    if (co->flg & CF_UNI) {
      if (srchval(tb, ir, pb, co) >= 0) { return (BOOL)terr(E_UNI, ir, i);}
    }
    if (co->flg & CF_KEY && NTableKeys(tb) == 1) {
      if (srchkey(tb, ir, pb) >= 0) { return (BOOL)terr(E_KEY, ir, i);}
    }
    if (!ISCAL(co) && co->flg & CF_REF) {
      if (srchref(tb, RTI(co), pb) < 0 && !zeroref(tb, RTI(co), pb)) { return (BOOL)terr(E_REF, ir, i);}
    }
    break;
  case TRGM_BEFOREUPDATE:
    nc = tb->cs->nc; co = tb->cs->co;
    for (i = 0, ci = co; i < nc; i++, ci++) {
      if (!chkval(pb, ci)) { return (BOOL)terr(E_CHK, ir, i);}
      if (ci->flg & CF_NZR) {
        if (iszero((pBIN)pb + OFS(ci), SIZ(ci))) { return (BOOL)terr(E_NZR, ir, i);}
      }
      if (ci->flg & CF_UNI) {
        if (srchval(tb, ir, pb, ci) >= 0) { return (BOOL)terr(E_UNI, ir, i);}
      }
    }
    if (NTableKeys(tb)) {
      if (srchkey(tb, ir, pb) >= 0) { return (BOOL)terr(E_KEY, ir, -1);}
    }
    if ((nt = NTableRefs(tb, id)) > 0) {
      for (i = 0; i < nt; i++) {
        if (srchref(tb, id[i], pb) < 0 && !zeroref(tb, id[i], pb)) { return (BOOL)terr(E_REF, ir, -1);}
      }
    }
    break;
  case TRGM_DEFAULT:
    nc = tb->cs->nc; co = tb->cs->co;
    for (i = 0, ci = co; i < nc; i++, ci++) {
      clrval((pBIN)pb + OFS(ci), pb, ci);
    }
    break;
  }
  return TRUE;
}

BOOL WINAPI TableTrigger(HTBL tb, I4B msg, I4B ir, pANY pb)
{ // トリガ関数呼び出し
  switch (msg) {
  case TRGM_DEFAULT:
    memset(pb, 0, TableRowSize(tb)); break;
  }
  if (tb->flg & TF_DTR) return TRUE;
  if (tb->ftrg) { return tb_ftrg(tb, msg, ir, pb);}
  return DefaultTableTrigger(tb, msg, ir, pb);
}

BOOL WINAPI EnableTableTrigger(HTBL tb)
{ // トリガ有効化
  I4B bk = !(tb->flg & TF_DTR); tb->flg &=~TF_DTR; return bk;
}

BOOL WINAPI DisableTableTrigger(HTBL tb)
{ // トリガ無効化
  I4B bk = !(tb->flg & TF_DTR); tb->flg |= TF_DTR; return bk;
}

I4B  WINAPI NTableColumns(HTBL tb)
{ // 列数
  return tb->cs->nc;
}

rCOLI LOCALF TableColumnInfo0(HTBL tb, I4B ic)
{ // 列情報
  return tb->cs->co + ic;
}

rCOLI WINAPI TableColumnInfo(HTBL tb, I4B ic)
{ // 列情報
  if (ic < 0 || ic >= NTableColumns(tb)) { ierr(E_ICO); return valloc(sizeof(COLI));}
  return TableColumnInfo0(tb, ic);
}

void WINAPI SetTableColumnWidth(HTBL tb, I4B ic, I4B wd)
{ // 列幅の設定
  if (ic < 0 || ic >= NTableColumns(tb)) { ierr(E_ICO); return;}
  WID(TableColumnInfo0(tb, ic)) = (U1B)wd;
}

I4B  WINAPI TableColumnWidth(HTBL tb, I4B ic)
{ // 列幅
  if (ic < 0 || ic >= NTableColumns(tb)) { return (I4B)ierr(E_ICO);}
  return WID(TableColumnInfo0(tb, ic));
}

void WINAPI SetTableColumnTextAlign(HTBL tb, I4B ic, I4B al)
{ // 列の文字揃えコードの設定
  if (ic < 0 || ic >= NTableColumns(tb)) { ierr(E_ICO); return;}
  ALN(TableColumnInfo0(tb, ic)) = (U1B)al;
}

I4B  WINAPI TableColumnTextAlign(HTBL tb, I4B ic)
{ // 列の文字揃えコード
  if (ic < 0 || ic >= NTableColumns(tb)) { return (I4B)ierr(E_ICO);}
  return ALN(TableColumnInfo0(tb, ic));
}

I4B  WINAPI TableColumnOffset(HTBL tb, I4B ic)
{ // 列のオフセット
  if (ic < 0 || ic >= NTableColumns(tb)) { return (I4B)ierr(E_ICO);}
  return OFS(TableColumnInfo0(tb, ic));
}

rSTR WINAPI TableColumnName(HTBL tb, I4B ic)
{ // 列名
  if (ic < 0 || ic >= NTableColumns(tb)) { ierr(E_ICO); return "";}
  return TableColumnInfo0(tb, ic)->nam;
}

I4B  WINAPI TableColumnIndex(HTBL tb, rSTR nam)
{ // 列名から列インデックスを求める
  I4B i, nc = tb->cs->nc;
  rCOLI co = tb->cs->co;

  for (i = 0; i < nc; i++) {
    if (!strcmp(co[i].nam, nam)) { return i;}
  }
  return -1;
}

void WINAPI SetTableColumnTitle(HTBL tb, I4B ic, rSTR tit)
{ // 列タイトルの設定
  rCOLI co;

  if (ic < 0 || ic >= NTableColumns(tb)) { ierr(E_ICO); return;}
  co = TableColumnInfo0(tb, ic);
  ((pCOLI)co)->tit = tit? tit: co->nam;
}

rSTR WINAPI TableColumnTitle(HTBL tb, I4B ic)
{ // 列タイトル
  if (ic < 0 || ic >= NTableColumns(tb)) { ierr(E_ICO); return "";}
  return TableColumnInfo0(tb, ic)->tit;
}

void WINAPI SetTableColumnDescription(HTBL tb, I4B ic, rSTR dsc)
{ // 列説明の設定
  rCOLI co;

  if (ic < 0 || ic >= NTableColumns(tb)) { ierr(E_ICO); return;}
  co = TableColumnInfo0(tb, ic);
  ((pCOLI)co)->dsc = dsc? dsc: co->tit;
}

rSTR WINAPI TableColumnDescription(HTBL tb, I4B ic)
{ // 列説明
  if (ic < 0 || ic >= NTableColumns(tb)) { ierr(E_ICO); return "";}
  return TableColumnInfo0(tb, ic)->dsc;
}

void WINAPI SetTableColumnFlags(HTBL tb, I4B ic, I4B flg)
{ // 列属性の設定
  if (ic < 0 || ic >= NTableColumns(tb)) { ierr(E_ICO); return;}
  ((pCOLI)TableColumnInfo0(tb, ic))->flg = flg;
}

I4B  WINAPI TableColumnFlags(HTBL tb, I4B ic)
{ // 列属性
  if (ic < 0 || ic >= NTableColumns(tb)) { return (I4B)ierr(E_ICO);}
  return TableColumnInfo0(tb, ic)->flg;
}

void WINAPI SetTableColumnExtra(HTBL tb, I4B ic, uANY pa)
{ // 列の付加情報の設定
  if (ic < 0 || ic >= NTableColumns(tb)) { ierr(E_ICO); return;}
  ((pCOLI)TableColumnInfo0(tb, ic))->pa2 = pa;
}

uANY WINAPI TableColumnExtra(HTBL tb, I4B ic)
{ // 列の付加情報
  if (ic < 0 || ic >= NTableColumns(tb)) { return (uANY)ierr(E_ICO);}
  return TableColumnInfo0(tb, ic)->pa2;
}

BOOL LOCALF SetTableCellValue0(HTBL tb, I4B ir, I4B ic, rANY pv)
{ // 値の設定
  pANY pb, bk;

  memcpy(bk = ualloc(TableRowSize(tb)), pb = Row(tb, ir), TableRowSize(tb));
  setval(pb, pv, TableColumnInfo0(tb, ic));
  if (!TableTrigger(tb, MKU4B(TRGM_BEFOREUPDATEOF, ic), ir, pb)) {
    memcpy(pb, bk, TableRowSize(tb)); return FALSE;
  }
  TableTrigger(tb, MKU4B(TRGM_AFTERUPDATEOF, ic), ir, pb);
  return TRUE;
}

BOOL WINAPI SetTableCellValue(HTBL tb, I4B ir, I4B ic, rANY pv)
{ // 値の設定
  if (tb->flg & TF_RDO) { return (BOOL)ierr(E_RDO);}
  if (ir < 0 || ir >= NTableRows(tb)) { return (BOOL)ierr(E_IRO);}
  if (ic < 0 || ic >= NTableColumns(tb)) { return (BOOL)ierr(E_ICO);}
  if (ISCAL(TableColumnInfo0(tb, ic))) { return (BOOL)ierr(E_CAL);}
  return SetTableCellValue0(tb, ir, ic, pv);
}

pANY LOCALF GetTableCellValue0(pANY pv, HTBL tb, I4B ir, I4B ic)
{ // 値の取得
  return getval(pv, Row(tb, ir), TableColumnInfo0(tb, ic));
}

pANY WINAPI GetTableCellValue(pANY pv, HTBL tb, I4B ir, I4B ic)
{ // 値の取得
  if (ir < 0 || ir >= NTableRows(tb)) { ierr(E_IRO); return pv;}
  if (ic < 0 || ic >= NTableColumns(tb)) { ierr(E_ICO); return pv;}
  return GetTableCellValue0(pv, tb, ir, ic);
}

BOOL LOCALF ScanTableCellValue0(HTBL tb, I4B ir, I4B ic, rSTR st)
{ // 文字列から読込
  U1B wk[LBUF];

  scnval(wk, st, TableColumnInfo0(tb, ic));
  return SetTableCellValue0(tb, ir, ic, wk);
}

BOOL WINAPI ScanTableCellValue(HTBL tb, I4B ir, I4B ic, rSTR st)
{ // 文字列から読込
  if (tb->flg & TF_RDO) { return (BOOL)ierr(E_RDO);}
  if (ir < 0 || ir >= NTableRows(tb)) { return (BOOL)ierr(E_IRO);}
  if (ic < 0 || ic >= NTableColumns(tb)) { return (BOOL)ierr(E_ICO);}
  if (ISCAL(TableColumnInfo0(tb, ic))) { return (BOOL)ierr(E_CAL);}
  return ScanTableCellValue0(tb, ir, ic, st);
}

pSTR LOCALF PrintTableCellValue0(pSTR st, HTBL tb, I4B ir, I4B ic)
{ // 文字列に書出
  rCOLI co = TableColumnInfo0(tb, ic);

  return prnval(st, (pBIN)Row(tb, ir) + OFS(co), co);
}

pSTR WINAPI PrintTableCellValue(pSTR st, HTBL tb, I4B ir, I4B ic)
{ // 文字列に書出
  if (ir < 0 || ir >= NTableRows(tb)) { ierr(E_IRO); st[0] = '\0'; return st;}
  if (ic < 0 || ic >= NTableColumns(tb)) { ierr(E_ICO); st[0] = '\0'; return st;}
  return PrintTableCellValue0(st, tb, ir, ic);
}

BOOL WINAPI ClearTableRow(HTBL tb, I4B ir)
{ // 行のクリア
  return ClearTableRows(tb, ir, 1);
}

BOOL WINAPI ClearTableRows(HTBL tb, I4B ir, I4B nr)
{ // 範囲のクリア
  I4B i, ln = NTableRows(tb), sz = TableRowSize(tb), re = TRUE;
  pANY pb, bk;

  if (tb->flg & TF_RDO) { return (BOOL)ierr(E_RDO);}
  if (ir + nr > ln) { nr = ln - ir;}
  if (ir < 0 || ir > ln || nr < 0) { return (BOOL)ierr(E_IRO);}
  bk = ualloc(sz);
  for (i = ir; i < ir + nr; i++) {
    memcpy(bk, pb = Row(tb, i), sz);
    TableTrigger(tb, TRGM_DEFAULT, i, pb);
    if (!TableTrigger(tb, TRGM_BEFOREUPDATE, i, pb)) {
      memcpy(pb, bk, sz); re = FALSE;
    } else {
      TableTrigger(tb, TRGM_AFTERUPDATE, i, pb);
    }
  }
  return re;
}

#define  InsertTableRow0(tb, ir)  InsertTableRows0(tb, ir, 1)

BOOL LOCALF InsertTableRows0(HTBL tb, I4B ir, I4B nr)
{ // 範囲の挿入
  I4B i, ln = NTableRows(tb);

  if (ln + nr > TableCapacity(tb)) {
    if (!ChangeTableCapacity0(tb, ln + nr)) return FALSE;
  }
  if (ir < ln) {
    memmove(Row(tb, ir + nr), Row(tb, ir), (ln - ir) * TableRowSize(tb));
  }
  AddLen(tb->mb, nr);
  for (i = ir; i < ir + nr; i++) {
    TableTrigger(tb, TRGM_DEFAULT, i, Row(tb, i));
  }
  return TRUE;
}

BOOL WINAPI InsertTableRow(HTBL tb, I4B ir)
{ // 行の挿入
  return InsertTableRows(tb, ir, 1);
}

BOOL WINAPI InsertTableRows(HTBL tb, I4B ir, I4B nr)
{ // 範囲の挿入
  I4B ln = NTableRows(tb);

  if (tb->flg & TF_RDO) { return (BOOL)ierr(E_RDO);}
  if (tb->flg & TF_FIX) { return (BOOL)ierr(E_FIX);}
  if (ir < 0 || ir > ln || nr < 0) { return (BOOL)ierr(E_IRO);}
  return InsertTableRows0(tb, ir, nr);
}

#define  DeleteTableRow0(tb, ir)  DeleteTableRows0(tb, ir, 1);

void LOCALF DeleteTableRows0(HTBL tb, I4B ir, I4B nr)
{ // 範囲の削除
  I4B ln = NTableRows(tb);

  if (ir + nr < ln) {
    memmove(Row(tb, ir), Row(tb, ir + nr), (ln - ir - nr) * TableRowSize(tb));
  }
  AddLen(tb->mb, -nr);
}

BOOL WINAPI DeleteTableRow(HTBL tb, I4B ir)
{ // 行の削除
  return DeleteTableRows(tb, ir, 1);
}

BOOL WINAPI DeleteTableRows(HTBL tb, I4B ir, I4B nr)
{ // 範囲の削除
  I4B i, ln = NTableRows(tb);

  if (tb->flg & TF_RDO) { return (BOOL)ierr(E_RDO);}
  if (tb->flg & TF_FIX) { return (BOOL)ierr(E_FIX);}
  if (ir == ln && nr >= 0) return TRUE;
  if (ir + nr > ln) { nr = ln - ir;}
  if (ir < 0 || ir > ln || nr < 0) { return (BOOL)ierr(E_IRO);}
  for (i = ir; i < ir + nr; i++) {
    if (!TableTrigger(tb, TRGM_BEFOREDELETE, i, Row(tb, i))) return FALSE;
  }
  DeleteTableRows0(tb, ir, nr);
  return TRUE;
}

BOOL LOCALF AddTableRow0(HTBL tb)
{ // 行の追加
  return InsertTableRow0(tb, NTableRows(tb));
}

BOOL WINAPI AddTableRow(HTBL tb)
{ // 行の追加
  if (tb->flg & TF_RDO) { return (BOOL)ierr(E_RDO);}
  if (tb->flg & TF_FIX) { return (BOOL)ierr(E_FIX);}
  return AddTableRow0(tb);
}

pANY LOCALF NewTableRow0(HTBL tb)
{ // 追加行
  return AddTableRow0(tb)? Row(tb, NTableRows(tb) - 1): valloc(TableRowSize(tb));
}

pANY WINAPI NewTableRow(HTBL tb)
{ // 追加行
  return AddTableRow(tb)? Row(tb, NTableRows(tb) - 1): valloc(TableRowSize(tb));
}

HTBL WINAPI CopyTable(HTBL tb, HTBL tx)
{ // 表のコピー
  if (!IsCompatible(tb, tx)) { ierr(E_CMP); return tb;}
  if (tb->flg & TF_RDO) { ierr(E_RDO); return tb;}
  if (tb->flg & TF_FIX && NTableRows(tb) != NTableRows(tx)) { ierr(E_FIX); return tb;}
  if (NTableRows(tx) > TableCapacity(tb)) {
    if (!ChangeTableCapacity0(tb, NTableRows(tx))) { return tb;}
  }
  CopyArray(tb->mb, tx->mb);
  return tb;
}

HTBL WINAPI MergeTableX(HTBL tb, HTBL tx)
{ // 表のマージ
  I4B i, ln, sz;

  if (!IsCompatible(tb, tx)) { ierr(E_CMP); return tb;}
  if (tb->flg & TF_RDO) { ierr(E_RDO); return tb;}
  if (tb->flg & TF_FIX) { ierr(E_FIX); return tb;}
  ln = NTableRows(tx); sz = TableRowSize(tx);
  for (i = 0; i < ln; i++) {
    memcpy(NewTableRow0(tb), Row(tx, i), sz);
  }
  return tb;
}

I4B  WINAPI CompareTable(HTBL tb, HTBL tx)
{ // 表の比較
  return CompareArray(tb->mb, tx->mb);
}

I4B  WINAPI SearchTableRowX(HTBL tb, I4B i0, FSEL fsel, uANY pa)
{ // サーチ
  if (i0 < 0 || i0 > NTableRows(tb)) { ierr(E_IRO); return -1;}
  return SearchItem(tb->mb, i0, fsel, pa);
}

I4B  WINAPI CountTableRowsX(HTBL tb, FSEL fsel, uANY pa)
{ // カウント
  return CountItems(tb->mb, fsel, pa);
}

I4B  WINAPI SelectTableRowsX(HTBL tb, FSEL fsel, uANY pa)
{ // 絞り込み
  if (tb->flg & TF_RDO) { ierr(E_RDO); return NTableRows(tb);}
  if (tb->flg & TF_FIX) { ierr(E_FIX); return NTableRows(tb);}
  return SelectItems(tb->mb, fsel, pa);
}

I4B  LOCALF InvSelectTableRowsX(HTBL tb, FSEL fsel, uANY pa)
{ // 絞り込み(条件反転)
  return InvSelectItems(tb->mb, fsel, pa);
}

HTBL WINAPI SelectCopyTableX(HTBL tb, HTBL tx, FSEL fsel, uANY pa)
{ // 絞り込みコピー
  I4B i, ln, sz;

  if (!IsCompatible(tb, tx)) { ierr(E_CMP); return tb;}
  if (tb->flg & TF_RDO) { ierr(E_RDO); return tb;}
  if (tb->flg & TF_FIX) { ierr(E_FIX); return tb;}
  if (!fsel) { fsel = fselALL;}
  DeleteTableRows0(tb, 0, NTableRows(tb));
  ln = NTableRows(tx); sz = TableRowSize(tx);
  for (i = 0; i < ln; i++) {
    if (fsel(Row(tx, i), pa)) {
      memcpy(NewTableRow0(tb), Row(tx, i), sz);
    }
  }
  return tb;
}

HTBL WINAPI SelectMergeTableX(HTBL tb, HTBL tx, FSEL fsel, uANY pa)
{ // 絞り込みマージ(置換)
  I4B i, ln, sz;

  if (!IsCompatible(tb, tx)) { ierr(E_CMP); return tb;}
  if (tb->flg & TF_RDO) { ierr(E_RDO); return tb;}
  if (tb->flg & TF_FIX) { ierr(E_FIX); return tb;}
  if (!fsel) { fsel = fselALL;}
  InvSelectTableRowsX(tb, fsel, pa);
  ln = NTableRows(tx); sz = TableRowSize(tx);
  for (i = 0; i < ln; i++) {
    if (fsel(Row(tx, i), pa)) {
      memcpy(NewTableRow0(tb), Row(tx, i), sz);
    }
  }
  return tb;
}

I4B  WINAPI AggregateTableX(HTBL tb, FSEL fsel, uANY ps, FAGG fagg, uANY pa)
{ // 集計
  I4B i, n, ln = NTableRows(tb);

  if (!fsel) { fsel = fselALL;}
  if (!fagg) { fagg = (FAGG)fselALL;}
  for (n = i = 0; i < ln; i++) {
    if (fsel(Row(tb, i), ps) && fagg(Row(tb, i), pa)) { n++;}
  }
  return n;
}

void WINAPI SortTableRowsX(HTBL tb, FSRT fsrt, uANY pa)
{ // 並べ替え
  if (tb->flg & TF_RDO) { ierr(E_RDO); return;}
  SortItems(tb->mb, fsrt, pa);
}

I4B  WINAPI SearchTableCellValue(HTBL tb, I4B i0, I4B ic, rANY pv)
{ // 値のサーチ
  I4B i, ln = NTableRows(tb);
  rCOLI co;
  U1B rv[LBUF];

  if (i0 < 0 || i0 > ln) { ierr(E_IRO); return -1;}
  if (ic < 0 || ic >= NTableColumns(tb)) { ierr(E_ICO); return -1;}
  co = TableColumnInfo0(tb, ic);
  for (i = i0; i < ln; i++) {
    if (!memcmp(getval(rv, Row(tb, i), co), pv, SIZ(co))) { return i;}
  }
  return -1;
}

I4B  WINAPI SearchTableCellText(HTBL tb, I4B i0, I4B ic, rSTR st, I4B flg)
{ // 文字列のサーチ
  I4B i, ln = NTableRows(tb);
  rCOLI co;
  I1B bf[LBUF];

  if (i0 < 0 || i0 > ln) { ierr(E_IRO); return -1;}
  if (ic < 0 || ic >= NTableColumns(tb)) { ierr(E_ICO); return -1;}
  co = TableColumnInfo0(tb, ic);
  for (i = i0; i < ln; i++) {
    if (strfindx(prnval(bf, (pBIN)Row(tb, i) + OFS(co), co), st, flg)) { return i;}
  }
  return -1;
}

I4B  WINAPI SearchAlt(HTBL tb, I4B ic, rSTR st)
{ // 代理キーによるサーチ
  I4B ir, ln = NTableRows(tb), flg;

  flg = STX_UPR|STX_ZEN|STX_DSP|STX_ALL;
  ir = SearchTableCellText(tb, 0, ic, st, flg);
  if (ir >= 0) {
    if (ir < ln - 1 && SearchTableCellText(tb, ir + 1, ic, st, flg) >= 0) return -1;
  } else {
    flg = STX_UPR|STX_ZEN|STX_DSP;
    ir = SearchTableCellText(tb, 0, ic, st, flg);
    if (ir >= 0) {
      if (ir < ln - 1 && SearchTableCellText(tb, ir + 1, ic, st, flg) >= 0) return -1;
    }
  }
  return ir;
}

BOOL WINAPI CheckTable(HTBL tb)
{ // 表データのチェック
  I4B i, n, ln = NTableRows(tb);

  for (n = i = 0; i < ln; i++) {
    if (!TableTrigger(tb, TRGM_BEFOREUPDATE, i, Row(tb, i))) { n++;}
  }
  return n == 0;
}

#define  NTRY  5
#define  ITRY  1000

BOOL LOCALF loadplane(HTBL tb)
{ // 読込
  I4B ln, sz, nt = NTRY, re = FALSE;
  HFIL hf;

 _00:
  hf = open_file(tb->imp, OP_RDO);
  if (!hf) {
    if (--nt > 0) { wait_millisec(ITRY); goto _00;} else { return (BOOL)ferr(E_FIR, tb->imp);}
  }
  sz = get_file_size(hf); if (sz == INVALID_FILE_SIZE) { ferr(E_FIR, tb->imp); goto _10;}
  if ((ln = sz / TableRowSize(tb)) > TableCapacity(tb)) {
    if (!ChangeTableCapacity0(tb, ln)) goto _10;
  }
  if (!read_file(hf, TablePtr(tb), sz)) { ferr(E_FIR, tb->imp); goto _10;}
  SetLen(tb->mb, ln);
  re = TRUE;
 _10: close_file(hf);
  return re;
}

BOOL LOCALF saveplane(HTBL tb)
{ // 保存
  I4B sz, nt = NTRY, re = FALSE;
  HFIL hf;

 _00:
  hf = open_file(tb->imp, OP_WRI);
  if (!hf) {
    if (--nt > 0) { wait_millisec(ITRY); goto _00;} else { return (BOOL)ferr(E_FIW, tb->imp);}
  }
  sz = NTableRows(tb) * TableRowSize(tb);
  if (!write_file(hf, TablePtr(tb), sz)) { ferr(E_FIW, tb->imp); goto _10;}
  re = TRUE;
 _10: close_file(hf);
  return re;
}

  // 乱数
static U1B  RND[256] = {
  0xe1, 0x76, 0x08, 0x70, 0xb2, 0x10, 0xd7, 0xef, 0x2f, 0x66, 0x32, 0x8b, 0x18, 0x38, 0xd8, 0x03,
  0x2c, 0x45, 0x8b, 0x17, 0x2d, 0x4f, 0x0a, 0x86, 0xda, 0x15, 0x15, 0x12, 0xf3, 0x57, 0x6b, 0x7a,
  0x37, 0xd4, 0xce, 0x7e, 0x68, 0x4e, 0xfd, 0xdd, 0x45, 0x84, 0xb8, 0x59, 0x8e, 0x36, 0xbe, 0xb1,
  0x02, 0x23, 0xd1, 0xa5, 0x63, 0x0d, 0xb0, 0xf4, 0x70, 0xb3, 0x1b, 0x60, 0xe9, 0xd5, 0xd1, 0xa8,
  0x8d, 0x32, 0x94, 0x8c, 0x1e, 0x8c, 0x23, 0xcb, 0x5b, 0xa2, 0x3e, 0x27, 0x04, 0x34, 0xa4, 0x5f,
  0xd8, 0x01, 0x17, 0x33, 0x99, 0xcb, 0x56, 0x62, 0x06, 0x51, 0x21, 0xae, 0xdf, 0x53, 0x37, 0xd6,
  0xe3, 0x90, 0x5a, 0x9a, 0xd4, 0xca, 0x49, 0xb9, 0x71, 0xc0, 0xc4, 0xf5, 0x7a, 0x32, 0x8a, 0x0d,
  0xae, 0xdf, 0x5d, 0xc1, 0xcf, 0x89, 0xfc, 0xd0, 0x9c, 0xef, 0x27, 0xfc, 0xd5, 0xd1, 0x9d, 0x04,
  0x39, 0xee, 0x20, 0xa8, 0x8a, 0x08, 0x6f, 0xa7, 0x87, 0xde, 0x4a, 0xc3, 0xf0, 0x30, 0x70, 0xbb,
  0x84, 0xbd, 0xa3, 0x4f, 0x05, 0x47, 0xa2, 0x3e, 0x32, 0x8d, 0x2d, 0x4a, 0xcb, 0x4f, 0x03, 0x32,
  0x8f, 0x4c, 0xe6, 0xb6, 0x40, 0x46, 0x95, 0x95, 0x9d, 0xfc, 0xd0, 0x91, 0x66, 0x2e, 0x56, 0x69,
  0x5a, 0x9b, 0xe9, 0xdd, 0x3b, 0x05, 0x48, 0xac, 0xc8, 0x2b, 0x33, 0x98, 0xc1, 0xcd, 0x69, 0x60,
  0xe5, 0xaa, 0xac, 0xc4, 0xf6, 0x84, 0xbb, 0x83, 0xb3, 0x1a, 0x56, 0x5f, 0xdc, 0x2c, 0x3c, 0x17,
  0x30, 0x79, 0x2f, 0x6b, 0x71, 0xc3, 0xee, 0x1a, 0x5e, 0xc9, 0x39, 0xe6, 0xb7, 0x4b, 0xcf, 0x8e,
  0x3b, 0x08, 0x72, 0xd2, 0xac, 0xc2, 0xe1, 0x71, 0xc9, 0x38, 0xdc, 0x2d, 0x52, 0x2a, 0x22, 0xc5,
  0x06, 0x57, 0x75, 0xf9, 0xa7, 0x81, 0x94, 0x88, 0xf4, 0x67, 0x3f, 0x34, 0xad, 0xc9, 0x35, 0xbc,
};

void LOCALF encrypt(pU1B pb, I4B sz)
{ // 暗号化
  I4B i;

  for (i = 0; i < sz; i++) {
    pb[i] ^= RND[i % 256];
  }
}

BOOL LOCALF loadcrypt(HTBL tb)
{ // 復号化して読込
  I4B re;

  re = loadplane(tb);
  if (re) { encrypt(TablePtr(tb), NTableRows(tb) * TableRowSize(tb));}
  return re;
}

BOOL LOCALF savecrypt(HTBL tb)
{ // 暗号化して保存
  I4B re, sz = NTableRows(tb) * TableRowSize(tb);

  encrypt(TablePtr(tb), sz);
  re = saveplane(tb);
  encrypt(TablePtr(tb), sz);
  return re;
}

BOOL WINAPI LoadBTB(HTBL tb)
{ // 読込
  I4B re;

  if (tb->flg & TF_CYP) {
    re = loadcrypt(tb);
  } else {
    re = loadplane(tb);
  }
  return re;
}

BOOL WINAPI SaveBTB(HTBL tb)
{ // 保存
  I4B re;

  if (tb->flg & TF_CYP) {
    re = savecrypt(tb);
  } else {
    re = saveplane(tb);
  }
  return re;
}

BOOL WINAPI OpenBTB(HTBL tb)
{ // 開く
  I4B ln, sz, nt = NTRY;
  HFIL hf;

 _00:
  hf = open_file(tb->imp, OP_RDW);
  if (!hf) {
    if (--nt > 0) { wait_millisec(ITRY); goto _00;} else return FALSE;
  }
  sz = get_file_size(hf); if (sz == INVALID_FILE_SIZE) goto _10;
  if ((ln = sz / TableRowSize(tb)) > TableCapacity(tb)) {
    if (!ChangeTableCapacity0(tb, ln)) goto _10;
  }
  read_file(hf, TablePtr(tb), sz);
  SetLen(tb->mb, ln);
  tb->otb = (HTBL)hf;
  return TRUE;

 _10:
  close_file(hf);
  return FALSE;
}

BOOL WINAPI CloseBTB(HTBL tb, BOOL sv)
{ // 閉じる
  HFIL hf = (HFIL)tb->otb;

  if (!hf) return FALSE;
  if (sv) {
    set_file_ptr(hf, 0, FILE_BEGIN);
    write_file(hf, TablePtr(tb), NTableRows(tb) * TableRowSize(tb));
    set_end_of_file(hf);
  }
  tb->otb = NULL;
  close_file(hf);
  return TRUE;
}

void WINAPI OverrideTableTrigger(HTBL tb, FTRG ftrg)
{ // トリガ関数の差し替え
  tb->ftrg = ftrg; tb->flg &=~TF_OTR;
}

#define  LIDN  32

I4B  LOCALF fspcBOL(rSTR *pp, pBIN bf, uANY pa)
{ // 空白
  rSTR pt = *pp;

  while (isspc(pt)) { pt++;}
  *pp = pt;
  return 0;
}

I4B  LOCALF fcnsBOL(rSTR *pp, pBIN bf, uANY pa)
{ // 定数
  I4B b, cd;
  rSTR pb, pt = *pp, px;

  if (isdig(pt)) {
    b = 10; cd = TKN_U4B;
    if (*pt == '0' && (*(pt+1) == 'X' || *(pt+1) == 'x')) {
      pt += 2;
      pb = pt;
      while (isxdig(pt)) { pt++;}
      if (pt == pb) return 0;
      b = 16;
    } else {
      pb = pt;
      do { pt++;} while (isdig(pt));
      if (*pt == '.') {
        do { pt++;} while (isdig(pt));
        cd = TKN_F8B;
      }
      if (*pt == 'E' || *pt == 'e') {
        pt++;
        if (*pt == '+' || *pt == '-') { pt++;}
        px = pt;
        while (isdig(pt)) { pt++;}
        if (pt == px) return 0;
        cd = TKN_F8B;
      }
    }
    if (cd == TKN_U4B) {
      if (*pt == 'L' || *pt == 'l') {
        pt++;
        cd = TKN_U8B;
      }
    }
    if (pt - pb >= LBUF) return 0;
    spncpy(bf, pb, pt);
    switch (cd) {
    case TKN_U4B: *(pU4B)bf = strtoul(bf, NULL, b); break;
    case TKN_U8B: *(pU8B)bf = _strtoui64(bf, NULL, b); break;
    case TKN_F8B: *(pF8B)bf = atof(bf); break;
    }
  } else return 0;
  *pp = pt;
  return cd;
}

I4B  LOCALF fstrBOL(rSTR *pp, pBIN bf, uANY pa)
{ // 文字列
  I4B b;
  rSTR pb, pt = *pp;

  if (*pt == '\'' || *pt == '\"') { b = *pt++;} else return 0;
  pb = pt;
  while (*pt != b) {
    if (iszen(pt)) { ((pU2B)pt)++;}
    else if (isprn(pt)) { pt++;}
    else return 0;
  }
  if (pt - pb >= LBUF) return 0;
  spncpy(bf, pb, pt);
  pt++;
  *pp = pt;
  return TKN_STR;
}

enum {
  BOP_LPA = TKN_OPR,
            BOP_RPA,  BOP_CMA,  BOP_MNS,  BOP_AST,  BOP_LEQ,  BOP_LNE,  BOP_LLT,
  BOP_LLE,  BOP_LGT,  BOP_LGE,
  BKW_LAN = TKN_KWD,
            BKW_LOR,  BKW_MLK,  BKW_NML,  BKW_DSN,  BKW_ZRL,  BKW_ZRF,  BKW_PAL,
  BKW_PAF,  BKW_SUM,  BKW_AVG,  BKW_MAX,  BKW_MIN,  BKW_COU,  BKW_GRP,  BKW_AS_,
  BKW_DEC,  BKW_CMA,
};
  // キーワード(演算子、区切子を含む)
static CODI diBOL[] = {
  { BOP_LPA,  "("        }, { BOP_RPA,  ")"        }, { BOP_CMA,  ","        }, { BOP_MNS,  "-"        },
  { BOP_AST,  "*"        }, { BOP_LEQ,  "="        }, { BOP_LNE,  "<>"       }, { BOP_LLT,  "<"        },
  { BOP_LLE,  "<="       }, { BOP_LGT,  ">"        }, { BOP_LGE,  ">="       }, { BOP_LEQ,  "=="       },
  { BOP_LNE,  "!="       },
  { BKW_LAN,  "&&"       }, { BKW_LOR,  "||"       }, { BKW_LAN,  "and"      }, { BKW_LOR,  "or"       },
  { BKW_MLK,  "mlike"    }, { BKW_NML,  "notmlike" }, { BKW_DSN,  "desc"     }, { BKW_ZRL,  "zerolast" },
  { BKW_ZRF,  "zerofirst"}, { BKW_PAL,  "parenlast"}, { BKW_PAF,  "parenfirst"},{ BKW_SUM,  "sum"      },
  { BKW_AVG,  "avg"      }, { BKW_MAX,  "max"      }, { BKW_MIN,  "min"      }, { BKW_COU,  "count"    },
  { BKW_GRP,  "groupby"  }, { BKW_AS_,  "as"       }, { BKW_DEC,  "dec"      }, { BKW_CMA,  "cdec"     },
};
static CODS dsBOL = { diBOL, _countof(diBOL) };

I4B  LOCALF fkwdBOL(rSTR *pp, pU1B bf, uANY pa)
{ // キーワード、識別子
  I4B cd;
  rSTR pt = *pp;

  if (isalpx(pt)) {
    do { pt++;} while (isalnx(pt));
    if (pt - *pp >= LIDN) return 0;
    spncpy(bf, *pp, pt);
    cd = srchcod0(&dsBOL, bf); if (cd < TKN_KWD) { cd = TKN_IDN;}
  } else {
    cd = srchopr(&dsBOL, pt); if (cd < 0) return 0;
    pt += strlen(codstr(&dsBOL, cd));
  }
  *pp = pt;
  return cd;
}

  // 字句解析情報
static LEXI xiBOL = { fspcBOL, fcnsBOL, fstrBOL, fkwdBOL, NULL, 0 };

#define  TID_ICO  (TID_LIB + 1)

pANY LOCALF fscnICO(pI4B pv, rSTR st, rCOLI co)
{ // 文字列から読込
  I4B i, nx = ((HTBL)co->pa2)->cs->nc;
  rCOLI cx = ((HTBL)co->pa2)->cs->co;

  *pv = -1;
  for (i = 0; i < nx; i++) {
    if (strcmp(cx[i].tit, st) == 0) { *pv = i; break;}
  }
  return pv;
}

pSTR LOCALF fprnICO(pSTR st, rI4B pv, rCOLI co)
{ // 文字列に書出
  I4B nx = ((HTBL)co->pa2)->cs->nc;
  rCOLI cx = ((HTBL)co->pa2)->cs->co;

  return strcpys(st, (*pv >= 0 && *pv < nx)? cx[*pv].tit: "");
}

uANY LOCALF flstICO(I4B im, rCOLI co)
{ // リスト項目
  I4B nx = ((HTBL)co->pa2)->cs->nc;
  rCOLI cx = ((HTBL)co->pa2)->cs->co;

  return (im < 0)? nx + 1: (im == 0)? (uANY)"(なし)": (im <= nx)? (uANY)cx[im-1].tit: (uANY)"";
}

static TYPI tpICO = { ITP(TID_ICO, TID_I4B), 0, fscnICO, fprnICO, NULL, flstICO, };

static COLI ciARR[] = {
  { TID_ICO, 16, "ic",  "列タイトル",   NULL, CF_DDL, },
};
static COLS csARR = { ciARR, _countof(ciARR) };
static TBLI tiARR = { &csARR, NULL, "BOLARR", };

HTBL WINAPI CreateARRTable(I4B cap, HTBL tb)
{ // 列インデックスリスト作成
  HTBL ta;

  if (cap < tb->cs->nc) { cap = tb->cs->nc;}
  ta = CreateTable(cap, &tiARR); if (!ta) return NULL;
  SetTableColumnExtra(ta, 0, (uANY)tb);
  return ta;
}

BOOL LOCALF scnarr(pIDXS pa, HTBL tb, rSTR st)
{ // 列名リスト読込
  I4B i, n, ic, nc = tb->cs->nc;
  rCOLI co = tb->cs->co;

  n = 0;
  start(st);
  switch (token()) {
  case TKN_END:
    for (i = 0; i < nc; i++) {
      if (WID(&co[i]) && !ISCAL(&co[i])) { pa->pi[n++] = i;}
    }
    break;
  case BOP_AST:
    for (i = 0; i < nc; i++) {
      pa->pi[n++] = i;
    }
    break;
  case TKN_IDN:
    goto _20;
  }
  goto _40;
 _10:
  if (token_is(TKN_IDN)) { _20:
    if ((ic = TableColumnIndex(tb, buf())) >= 0) {
      for (i = 0; i < n; i++) {
        if (pa->pi[i] == ic) goto _30;
      }
      pa->pi[n++] = ic;
    } _30:
    if (token_is(BOP_CMA)) goto _10;
  } _40:
  pa->ni = n;
  return n > 0;
}

BOOL WINAPI ScanARRTable(HTBL ta, rSTR arr)
{ // 列名リスト読込
  I4B i, j, k, nc, nv, re;
  pI4B vi;
  HTBL tb = (HTBL)ta->cs->co[0].pa2;

  if (!arr) { arr = "";}
  re = scnarr((pIDXS)ta->mb, tb, arr);
  nc = tb->cs->nc;
  vi = (pI4B)TablePtr(ta);
  k = nv = NTableRows(ta);
  for (i = 0; i < nc; i++) {
    for (j = 0; j < nv; j++) {
      if (vi[j] == i) goto _10;
    }
    vi[k++] = i;
   _10:;
  }
  return re;
}

pSTR WINAPI PrintARRTable(pSTR arr, HTBL ta)
{ // 列名リスト書出
  I4B i, ni = NTableRows(ta);
  pSTR pt;
  rI4B vi = (pI4B)TablePtr(ta);
  rCOLI cx = ((HTBL)ta->cs->co[0].pa2)->cs->co;

  *(pt = arr) = '\0';
  for (i = 0; i < ni; i++) {
    pt += sprintfs(pt, "%s", cx[vi[i]].nam);
    if (i < ni - 1) { pt += sprintfs(pt, ", ");}
  }
  return arr;
}

void WINAPI InsertARRTableRow(HTBL ta, I4B i1, I4B i2)
{ // 項目の追加
  I4B ic, ni = NTableRows(ta), nc = ((HTBL)ta->cs->co[0].pa2)->cs->nc;
  pI4B vi = (pI4B)TablePtr(ta);

  if (i1 < 0 || i1 > ni || i2 < 0 || i2 >= nc - ni) { ierr(E_IRO); return;}
  ic = vi[ni + i2];
  memmove(vi + i1 + 1, vi + i1, (ni + i2 - i1) * sizeof(I4B));
  vi[i1] = ic;
  AddLen(ta->mb, 1);
}

I4B  WINAPI DeleteARRTableRow(HTBL ta, I4B i1)
{ // 項目の除外
  I4B k, ic, ni = NTableRows(ta), nc = ((HTBL)ta->cs->co[0].pa2)->cs->nc;
  pI4B vi = (pI4B)TablePtr(ta);

  if (i1 < 0 || i1 >= ni) { return (I4B)ierr(E_IRO);}
  ic = vi[i1];
  for (k = ni; k < nc && vi[k] < ic; k++) {}
  memmove(vi + i1, vi + i1 + 1, (k - 1 - i1) * sizeof(I4B));
  vi[k-1] = ic;
  AddLen(ta->mb, -1);
  return k - ni;
}

  // 絞り込み条件項目
typedef struct {
  U1B   rp;
  U1B   lo;
  U1B   lp;
  U1B   cm;
  I4B   ic;
  I1B   wk[504];
} CNDE;
typedef CNDE *pCNDE;
  // 絞り込み条件
typedef struct {
  pCNDE ce;
  I4B   ni;
} CNDM;
typedef CNDM *pCNDM;

#define  TID_LOP  MKU4B(TID_LIB + 2, 3)

pANY LOCALF fscnLOP(pANY pv, rSTR st, rCOLI co)
{ // 文字列から読込
  ((pCNDE)pv)->rp = strfind(st, ")))")? 3: strfind(st, "))")? 2: strfind(st, ")")? 1: 0;
  ((pCNDE)pv)->lo = strfind(st, "and")? 1: strfind(st, "or")? 2: 0;
  ((pCNDE)pv)->lp = strfind(st, "(((")? 3: strfind(st, "((")? 2: strfind(st, "(")? 1: 0;
  return pv;
}

pSTR LOCALF fprnLOP(pSTR st, rANY pv, rCOLI co)
{ // 文字列に書出
  I4B i, rp = ((pCNDE)pv)->rp, lo = ((pCNDE)pv)->lo, lp = ((pCNDE)pv)->lp;
  pSTR pt;

  *(pt = st) = '\0';
  for (i = 0; i < rp; i++) {
    pt += sprintfs(pt, ")");
  }
  if (rp == 0 && lo != 0) { pt += sprintfs(pt, " ");}
  if (lo == 1) { pt += sprintfs(pt, "and");} else if (lo == 2) { pt += sprintfs(pt, "or");}
  for (i = 0; i < lp; i++) {
    pt += sprintfs(pt, "(");
  }
  if (lp == 0 && lo != 0) { pt += sprintfs(pt, " ");}
  return st;
}

static rSTR SLOP[] = {
  "", " and ", " or ", "(", ")", " and(", ")and ", ")and(", "((", "))",
  " and((", "))and ", ")and((", "))and(", "))and((", "(((", ")))"
};

uANY LOCALF flstLOP(I4B im, rCOLI co)
{ // リスト項目
  return (im < 0)? _countof(SLOP): (im < _countof(SLOP))? (uANY)SLOP[im]: (uANY)"";
}

void LOCALF fixcnd(HTBL tc)
{ // 絞り込み条件の整形
  I4B i, f, n, ln = NTableRows(tc);
  pCNDE pb;

  f = 1;
  for (n = i = 0; i < ln; i++) {
    pb = (pCNDE)Row(tc, i);
    if (i == ln - 1) {
      pb->lo = pb->lp = 0; pb->ic = -1;
    } else if (i == ln - 2) {
      pb->lp = 0;
    }
    if (f) {
      if (pb->ic >= 0) {
        if (pb->rp > n) { pb->rp = n; n = 0;} else { n -= pb->rp;}
        if (i > 0) {
          if (pb->lo == 0) { pb->lo = 1;}
        } else { pb->lo = 0;}
        if (pb->cm == 0) { pb->cm = 1;}
        n += pb->lp;
      } else {
        if (pb->lo == 0) { pb->rp = n;} else { (pb + 1)->rp = n - pb->lp;}
        pb->cm = 0; pb->ic = -1; memset(pb->wk, 0, sizeof(pb->wk));
        f = 0;
      }
    } else {
      pb->rp = pb->lo = pb->lp = pb->cm = 0; pb->ic = -1; memset(pb->wk, 0, sizeof(pb->wk));
    }
  }
}

BOOL LOCALF ftrgCND(HTBL tb, I4B msg, I4B ir, pCNDE pb)
{ // 絞り込み条件トリガ関数
  switch (msg) {
  case TRGM_DEFAULT:
    pb->ic = -1;
    return TRUE;
  case MKU4B(TRGM_AFTERUPDATEOF, 0):
    if (pb->ic >= 0) { fixcnd(tb);} else if (ir > 0 && (pb - 1)->ic < 0) { memset(pb, 0, 3);}
    return TRUE;
  case MKU4B(TRGM_AFTERUPDATEOF, 1):
    if (pb->ic >= 0) { fixcnd(tb);} else { pb->cm = 0;}
    return TRUE;
  case MKU4B(TRGM_AFTERUPDATEOF, 2):
    memset(pb->wk, 0, sizeof(pb->wk)); fixcnd(tb);
    return TRUE;
  }
  return DefaultTableTrigger(tb, msg, ir, (pANY)pb);
}

static TYPI tpLOP = { ITP(TID_LOP, TID_BIN), 0, fscnLOP, fprnLOP, NULL, flstLOP, };

static rSTR BCMP[] = { "", "=", "<>", "<", "<=", ">", ">=", "mlike", "notmlike" };
static rSTR SCMP[] = { "", "＝", "≠", "＜", "≦", "＞", "≧", "含む", "含まない" };
static ENMS esCMP = { SCMP, _countof(SCMP) };

#define  C8  ATR(8, ALN_CEN)
#define  C6  ATR(6, ALN_CEN)

static COLI ciCND[] = {
  { TID_LOP, C8, "lx",  "and/or",       NULL, CF_DDL, },
  { TID_E1B, C6, "cm",  "比較",         NULL, CF_DDL, NULL, NULL, (uANY)&esCMP, },
  { TID_ICO, 16, "ic",  "列タイトル",   NULL, CF_DDL, },
  { STR(504),22, "wk",  "値",           },
};
static COLS csCND = { ciCND, _countof(ciCND) };
static TBLI tiCND = { &csCND, NULL, "BOLCND", NULL, NULL, 0, (FTRG)ftrgCND, };

HTBL WINAPI CreateCNDTable(I4B cap, HTBL tb)
{ // 絞り込み条件作成
  HTBL tc;

  tc = CreateTable(cap, &tiCND); if (!tc) return NULL;
  SetTableColumnExtra(tc, 2, (uANY)tb);
  return tc;
}

I4B  LOCALF sicnv(rSTR ss)
{ // 文字列を整数に変換
  if      (strmatch(ss, "####/##/##")) { return ztod(ss);}
  else if (strmatch(ss, "##:##:##"))   { return ztot(ss);}
  return cztoi(ss);
}

F8B  LOCALF sfcnv(rSTR ss)
{ // 文字列を実数に変換
  if (strmatch(ss, "####/##/## ##:##:##")) { return ztodt(ss);}
  return cztof(ss);
}

BOOL LOCALF scncnd(pCNDM pc, HTBL tb, rSTR st)
{ // 絞り込み条件読込
  I4B n, ic, sg;
  rCOLI co;
  U1B wk[8];

  n = 0;
  memset(&pc->ce[0], 0, sizeof(CNDE));
  pc->ce[0].ic = -1;
  start(st);
  if (token_is(TKN_END)) goto _30;
 _10:
  switch (token()) {
  case BOP_LPA: pc->ce[n].lp++; goto _10;
  case TKN_IDN: break;
  default: goto _30;
  }
  if ((ic = TableColumnIndex(tb, buf())) >= 0) {
    pc->ce[n].ic = ic;
    co = TableColumnInfo0(tb, ic);
  } else goto _30;
  switch (token()) {
  case BOP_LEQ: pc->ce[n].cm = 1; break;
  case BOP_LNE: pc->ce[n].cm = 2; break;
  case BOP_LLT: pc->ce[n].cm = 3; break;
  case BOP_LLE: pc->ce[n].cm = 4; break;
  case BOP_LGT: pc->ce[n].cm = 5; break;
  case BOP_LGE: pc->ce[n].cm = 6; break;
  case BKW_MLK: pc->ce[n].cm = 7; break;
  case BKW_NML: pc->ce[n].cm = 8; break;
  default: goto _30;
  }
  if (BTP(co) <= TID_F8B) {
    sg = 1;
    if (token_is(BOP_MNS)) { sg = -1;}
  }
  switch (BTP(co)) {
  case TID_I1B: case TID_U1B:
  case TID_I2B: case TID_U2B:
  case TID_I4B:
    switch (token()) {
    case TKN_U4B: *(pI4B)wk = *(rU4B)buf() * sg; break;
    default: goto _30;
    }
    cprnval(pc->ce[n].wk, wk, co); break;
  case TID_U4B:
    switch (token()) {
    case TKN_U4B: *(pU4B)wk = *(rU4B)buf() * sg; break;
    case TKN_STR: *(pU4B)wk = sicnv(buf()); break;
    default: goto _30;
    }
    cprnval(pc->ce[n].wk, wk, co); break;
  case TID_I8B: case TID_U8B:
    switch (token()) {
    case TKN_U4B: *(pU8B)wk = *(rU4B)buf() * sg; break;
    case TKN_U8B: *(pU8B)wk = *(rU8B)buf() * sg; break;
    default: goto _30;
    }
    cprnval(pc->ce[n].wk, wk, co); break;
  case TID_F4B:
    switch (token()) {
    case TKN_U4B: *(pF4B)wk = (F4B)(*(rU4B)buf() * sg); break;
    case TKN_F8B: *(pF4B)wk = (F4B)(*(rF8B)buf() * sg); break;
    default: goto _30;
    }
    cprnval(pc->ce[n].wk, wk, co); break;
  case TID_F8B:
    switch (token()) {
    case TKN_U4B: *(pF8B)wk = *(rU4B)buf() * sg; break;
    case TKN_F8B: *(pF8B)wk = *(rF8B)buf() * sg; break;
    case TKN_STR: *(pF8B)wk = sfcnv(buf()); break;
    default: goto _30;
    }
    cprnval(pc->ce[n].wk, wk, co); break;
  default: // TID_STR, TID_BIN
    switch (token()) {
    case TKN_STR: break;
    default: goto _30;
    }
    cprnval(pc->ce[n].wk, buf(), co); break;
  }
  n++;
  memset(&pc->ce[n], 0, sizeof(CNDE));
  pc->ce[n].ic = -1;
 _20:
  switch (token()) {
  case BOP_RPA: pc->ce[n].rp++; goto _20;
  case TKN_END: goto _30;
  case BKW_LAN: pc->ce[n].lo = 1; break;
  case BKW_LOR: pc->ce[n].lo = 2; break;
  default: goto _30;
  }
  goto _10;
 _30:
  pc->ni = n;
  return n > 0;
}

BOOL WINAPI ScanCNDTable(HTBL tc, rSTR cnd)
{ // 絞り込み条件読込
  I4B re;
  HTBL tb = (HTBL)tc->cs->co[2].pa2;

  if (!cnd) { cnd = "";}
  SetLen(tc->mb, 0);
  InsertTableRows(tc, 0, TableCapacity(tc));
  re = scncnd((pCNDM)tc->mb, tb, cnd);
  SetLen(tc->mb, TableCapacity(tc));
  fixcnd(tc);
  return re;
}

pSTR WINAPI PrintCNDTable(pSTR cnd, HTBL tc)
{ // 絞り込み条件書出
  I4B i, ni = NTableRows(tc);
  pSTR pt;
  rCOLI cx = ((HTBL)tc->cs->co[2].pa2)->cs->co;
  CNDE dat;
  I1B bf[LBUF];

  fixcnd(tc);
  *(pt = cnd) = '\0';
  for (i = 0; i < ni; i++) {
    dat = *(pCNDE)Row(tc, i);
    if (dat.ic < 0) { dat.lo = dat.lp = 0;}
    pt += strlen(prnval(pt, &dat.rp, &tc->cs->co[0])); if (dat.ic < 0) break;
    pt += sprintfs(pt, "%s", cx[dat.ic].nam);
    pt += sprintfs(pt, " %s ", BCMP[dat.cm]);
    pt += strlen(vprnval(pt, cscnval(bf, dat.wk, &cx[dat.ic]), &cx[dat.ic]));
  }
  return cnd;
}

#define  SRT_ASN  0x00
#define  SRT_DSN  0x01
#define  SRT_ZRL  0x02
#define  SRT_ZRF  0x04
#define  SRT_PAL  0x08
#define  SRT_PAF  0x10

  // 並べ替え条件項目
typedef struct {
  I4B   ic;
  I4B   flg;
} SRTE;
typedef SRTE *pSRTE;
  // 並べ替え条件
typedef struct {
  pSRTE se;
  I4B   ni;
} SRTM;
typedef SRTM *pSRTM;

void LOCALF fixsrt(HTBL ts)
{ // 並べ替え条件の整形
  I4B i, f, ln = NTableRows(ts);
  pSRTE pb;

  f = 1;
  for (i = 0; i < ln; i++) {
    pb = (pSRTE)Row(ts, i);
    if (f) {
      if (pb->ic >= 0) {
        if (pb->flg == -1) { pb->flg = 0;}
      } else {
        pb->flg = -1;
        f = 0;
      }
    } else {
      pb->ic = pb->flg = -1;
    }
  }
}

BOOL LOCALF ftrgSRT(HTBL tb, I4B msg, I4B ir, pSRTE pb)
{ // 並べ替え条件トリガ関数
  switch (msg) {
  case TRGM_DEFAULT:
    pb->ic = pb->flg = -1;
    return TRUE;
  case MKU4B(TRGM_AFTERUPDATEOF, 0):
    fixsrt(tb);
    return TRUE;
  case MKU4B(TRGM_AFTERUPDATEOF, 1):
    if (pb->ic >= 0) { fixsrt(tb);} else { pb->flg = -1;}
    return TRUE;
  }
  return DefaultTableTrigger(tb, msg, ir, (pANY)pb);
}

static CODI diVOP[] = {
  { -1,                      "" },
  {  0,                      "昇順" },
  { SRT_DSN,                 "降順" },
  { SRT_ZRL,                 "昇順、ただし空欄は最後" },
  { SRT_DSN|SRT_ZRF,         "降順、ただし空欄は最初" },
  { SRT_PAL,                 "昇順、ただし括弧は最後" },
  { SRT_DSN|SRT_PAF,         "降順、ただし括弧は最初"  },
  { SRT_ZRL|SRT_PAL,         "昇順、ただし空欄と括弧は最後" },
  { SRT_DSN|SRT_ZRF|SRT_PAF, "降順、ただし空欄と括弧は最初" },
};
static CODS dsVOP = { diVOP, _countof(diVOP) };

static COLI ciSRT[] = {
  { TID_ICO, 16, "ic",  "列タイトル",   NULL, CF_DDL, },
  { TID_C4B, 28, "flg", "並べ替え順序", NULL, CF_DDL, NULL, NULL, (uANY)&dsVOP, },
};
static COLS csSRT = { ciSRT, _countof(ciSRT) };
static TBLI tiSRT = { &csSRT, NULL, "BOLSRT", NULL, NULL, 0, (FTRG)ftrgSRT, };

HTBL WINAPI CreateSRTTable(I4B cap, HTBL tb)
{ // 並べ替え条件作成
  HTBL ts;

  ts = CreateTable(cap, &tiSRT); if (!ts) return NULL;
  SetTableColumnExtra(ts, 0, (uANY)tb);
  return ts;
}

BOOL LOCALF scnsrt(pSRTM ps, HTBL tb, rSTR st)
{ // 並べ替え条件読込
  I4B n, ic;

  n = 0;
  start(st);
  if (token_is(TKN_END)) goto _20;
 _10:
  if (token_is(TKN_IDN)) {
    if ((ic = TableColumnIndex(tb, buf())) >= 0) {
      ps->se[n].ic = ic;
      ps->se[n].flg = 0;
    } else goto _20;
  } else goto _20;
  if (token_is(BKW_DSN)) {
    ps->se[n].flg |= SRT_DSN;
    if (token_is(BKW_ZRF)) { ps->se[n].flg |= SRT_ZRF;}
    if (token_is(BKW_PAF)) { ps->se[n].flg |= SRT_PAF;}
  } else {
    if (token_is(BKW_ZRL)) { ps->se[n].flg |= SRT_ZRL;}
    if (token_is(BKW_PAL)) { ps->se[n].flg |= SRT_PAL;}
  }
  n++;
  switch (token()) {
  case TKN_END: goto _20;
  case BOP_CMA: break;
  default: goto _20;
  }
  goto _10;
 _20:
  ps->ni = n;
  return n > 0;
}

BOOL WINAPI ScanSRTTable(HTBL ts, rSTR srt)
{ // 並べ替え条件読込
  I4B re;
  HTBL tb = (HTBL)ts->cs->co[0].pa2;

  if (!srt) { srt = "";}
  SetLen(ts->mb, 0);
  InsertTableRows(ts, 0, TableCapacity(ts));
  re = scnsrt((pSRTM)ts->mb, tb, srt);
  SetLen(ts->mb, TableCapacity(ts));
  fixsrt(ts);
  return re;
}

pSTR WINAPI PrintSRTTable(pSTR srt, HTBL ts)
{ // 並べ替え条件書出
  I4B i, ni = NTableRows(ts);
  pSTR pt;
  pSRTE pb;
  rCOLI cx = ((HTBL)ts->cs->co[0].pa2)->cs->co;

  fixsrt(ts);
  *(pt = srt) = '\0';
  for (i = 0; i < ni; i++) {
    pb = (pSRTE)Row(ts, i); if (pb->ic < 0) break;
    pt += sprintfs(pt, "%s", cx[pb->ic].nam);
    if (pb->flg & SRT_DSN) { pt += sprintfs(pt, " %s", "desc");}
    if (pb->flg & SRT_ZRL) { pt += sprintfs(pt, " %s", "zerolast");}
    if (pb->flg & SRT_ZRF) { pt += sprintfs(pt, " %s", "zerofirst");}
    if (pb->flg & SRT_PAL) { pt += sprintfs(pt, " %s", "parenlast");}
    if (pb->flg & SRT_PAF) { pt += sprintfs(pt, " %s", "parenfirst");}
    if (i < ni - 1 && (pb + 1)->ic >= 0) { pt += sprintfs(pt, ", ");}
  }
  return srt;
}

#define  FMT_DEC  1
#define  FMT_CMA  2

  // 集計項目
typedef struct {
  I4B   ic;
  U1B   sw;
  U1B   sb, wd, sc;
  I1B   unt[24];
  I1B   tit[32];
} GRPE;
typedef GRPE *pGRPE;
  // 集計項目リスト
typedef struct {
  pGRPE ge;
  I4B   ni;
} GRPM;
typedef GRPM *pGRPM;

static CODI diAGG[] = {
  { 0,       "" },
  { AGG_SUM, "合計" },
  { AGG_AVG, "平均" },
  { AGG_MAX, "最大値" },
  { AGG_MIN, "最小値" },
  { AGG_COU, "個数" },
  { AGG_GRP, "集計単位" },
};
static CODS dsAGG = { diAGG, _countof(diAGG) };

#define  TID_FMT  MKU4B(TID_LIB + 3, offsetof(GRPE, tit) - offsetof(GRPE, sb))

BOOL LOCALF scndec(pU1B pv)
{ // 代替書式読込
  U1B sb, wd, sc;
  I1B unt[24];

  memset(pv, 0, offsetof(GRPE, tit) - offsetof(GRPE, sb));
  if      (token_is(BKW_DEC)) { sb = FMT_DEC;}
  else if (token_is(BKW_CMA)) { sb = FMT_CMA;}
  else return FALSE;
  wd = sc = 0; unt[0] = '\0';
  if (!token_is(BOP_LPA)) goto _30;
  if (token_is(TKN_U4B)) {
    wd = (U1B)*(rU4B)buf(); if (wd > 30) { wd = 30;}
  } else goto _10;
  if (!token_is(BOP_CMA)) goto _20;
  if (token_is(TKN_U4B)) {
    sc = (U1B)*(rU4B)buf(); if (sc > 15) { sc = 15;}
  } else goto _10;
  if (!token_is(BOP_CMA)) goto _20;
 _10:
  if (token_is(TKN_STR)) {
    if (strlen(buf()) < sizeof(unt)) { strcpys(unt, buf());} else return FALSE;
  } else return FALSE;
 _20:
  if (!token_is(BOP_RPA)) return FALSE;
 _30:
  pv[0] = sb; pv[1] = wd; pv[2] = sc;
  strcpyx(&pv[3], unt, sizeof(unt) - 1);
  return TRUE;
}

rSTR LOCALF decfmt(I4B id, pGRPE pb)
{ // 書式文字列
  I1B bf[LBUF];

  switch (id) {
  case TID_I4B: strcpys(bf, "%d"); break;
  case TID_U4B: strcpys(bf, "%u"); break;
  case TID_I8B: strcpys(bf, "%lld"); break;
  case TID_U8B: strcpys(bf, "%llu"); break;
  case TID_F8B: strcpys(bf, pb->sc? format("%%.%df", pb->sc): "%.15G"); break;
  case TID_M4B: strcpys(bf, "%d"); break;
  case TID_M8B: strcpys(bf, pb->sc? format("%%.%df", pb->sc): "%.0f"); break;
  default: bf[0] = '\0'; break;
  }
  if (pb->unt[0]) {
    strcats(bf, strrepl(pb->unt, "%", "%%"));
  }
  return stostr(bf);
}

pANY LOCALF fscnFMT(pANY pv, rSTR st, rCOLI co)
{ // 文字列から読込
  start(st);
  scndec(pv);
  return pv;
}

pSTR LOCALF fprnFMT(pSTR st, rANY pv, rCOLI co)
{ // 文字列に書出
  U1B wd, sc;
  pSTR pt;
  rSTR unt;

  *(pt = st) = '\0';
  switch (((pU1B)pv)[0]) {
  case FMT_DEC: pt += sprintfs(pt, "dec"); break;
  case FMT_CMA: pt += sprintfs(pt, "cdec"); break;
  default: return st;
  }
  wd = ((pU1B)pv)[1]; sc = ((pU1B)pv)[2];
  unt = (rSTR)&((pU1B)pv)[3];
  if (wd > 0 || sc > 0 || unt[0]) {
    pt += sprintfs(pt, "(");
    if (wd > 0 || sc > 0) {
      pt += sprintfs(pt, "%d", (I4B)wd);
      if (sc > 0 || unt[0]) { pt += sprintfs(pt, ", ");}
    }
    if (sc > 0) {
      pt += sprintfs(pt, "%d", (I4B)sc);
      if (unt[0]) { pt += sprintfs(pt, ", ");}
    }
    if (unt[0]) {
      pt += sprintfs(pt, "'%s'", unt);
    }
    pt += sprintfs(pt, ")");
  }
  return st;
}

void LOCALF fixgrp(HTBL tg)
{ // 集計項目リストの整形
  I4B i, f, ln = NTableRows(tg);
  pGRPE pb;

  f = 1;
  for (i = 0; i < ln; i++) {
    pb = (pGRPE)Row(tg, i);
    if (f) {
      if (pb->ic >= 0) {
        if (pb->sw < AGG_SUM || pb->sw > AGG_COU) {
          memset(&pb->sb, 0, offsetof(GRPE, tit) - offsetof(GRPE, sb));
        }
      } else {
        memset(&pb->sw, 0, sizeof(GRPE) - offsetof(GRPE, sw));
        f = 0;
      }
    } else {
      pb->ic = -1; memset(&pb->sw, 0, sizeof(GRPE) - offsetof(GRPE, sw));
    }
  }
}

BOOL LOCALF ftrgGRP(HTBL tb, I4B msg, I4B ir, pGRPE pb)
{ // 集計項目リストトリガ関数
  switch (msg) {
  case TRGM_DEFAULT:
    pb->ic = -1;
    return TRUE;
  case MKU4B(TRGM_AFTERUPDATEOF, 0):
    fixgrp(tb);
    return TRUE;
  case MKU4B(TRGM_AFTERUPDATEOF, 1):
  case MKU4B(TRGM_AFTERUPDATEOF, 2):
  case MKU4B(TRGM_AFTERUPDATEOF, 3):
    if (pb->ic >= 0) { fixgrp(tb);} else { memset(&pb->sw, 0, sizeof(GRPE) - offsetof(GRPE, sw));}
    return TRUE;
  }
  return DefaultTableTrigger(tb, msg, ir, (pANY)pb);
}

static TYPI tpFMT = { ITP(TID_FMT, TID_BIN), 0, fscnFMT, fprnFMT, };

static COLI ciGRP[] = {
  { TID_ICO, 16, "ic",  "列タイトル",   NULL, CF_DDL, },
  { TID_C1B,  8, "sw",  "集計方法",     NULL, CF_DDL, NULL, NULL, (uANY)&dsAGG, },
  { TID_FMT, 22, "fmt", "代替書式",     },
  { STR(32), 16, "tit", "代替タイトル", },
};
static COLS csGRP = { ciGRP, _countof(ciGRP) };
static TBLI tiGRP = { &csGRP, NULL, "BOLGRP", NULL, NULL, 0, (FTRG)ftrgGRP, };

HTBL WINAPI CreateGRPTable(I4B cap, HTBL tb)
{ // 集計項目リスト作成
  HTBL tg;

  tg = CreateTable(cap, &tiGRP); if (!tg) return NULL;
  SetTableColumnExtra(tg, 0, (uANY)tb);
  return tg;
}

BOOL LOCALF scngrp(pGRPM pg, HTBL tb, rSTR st)
{ // 集計項目リスト読込
  I4B n, ic, sw;

  n = 0;
  start(st);
  if (token_is(TKN_END)) goto _50;
 _10:
  switch (token()) {
  case BKW_SUM: sw = AGG_SUM; goto _20;
  case BKW_AVG: sw = AGG_AVG; goto _20;
  case BKW_MAX: sw = AGG_MAX; goto _20;
  case BKW_MIN: sw = AGG_MIN; goto _20;
  case BKW_COU: sw = AGG_COU; _20:
    if (!token_is(BOP_LPA)) goto _50;
    if (!token_is(TKN_IDN)) goto _50;
    if ((ic = TableColumnIndex(tb, buf())) >= 0) {
      if (!token_is(BOP_RPA)) goto _50;
    } else goto _50;
    goto _40;
  case BKW_GRP: sw = AGG_GRP;
    if (!token_is(TKN_IDN)) goto _50;
    goto _30;
  case TKN_IDN: sw = 0; _30:
    if ((ic = TableColumnIndex(tb, buf())) >= 0) { _40:
      pg->ge[n].ic = ic;
      pg->ge[n].sw = sw;
      memset(&pg->ge[n].sb, 0, offsetof(GRPE, tit) - offsetof(GRPE, sb));
    } else goto _50;
    break;
  default:
    goto _50;
  }
  if (token_is(BKW_AS_)) {
    if (!token_is(TKN_STR)) goto _50;
    strcpyx(pg->ge[n].tit, buf(), sizeof(pg->ge->tit) - 1);
  }
  scndec(&pg->ge[n].sb);
  n++;
  switch (token()) {
  case TKN_END: goto _50;
  case BOP_CMA: break;
  default: goto _50;
  }
  goto _10;
 _50:
  pg->ni = n;
  return n > 0;
}

BOOL WINAPI ScanGRPTable(HTBL tg, rSTR grp)
{ // 集計項目リスト読込
  I4B re;
  HTBL tb = (HTBL)tg->cs->co[0].pa2;

  if (!grp) { grp = "";}
  SetLen(tg->mb, 0);
  InsertTableRows(tg, 0, TableCapacity(tg));
  re = scngrp((pGRPM)tg->mb, tb, grp);
  SetLen(tg->mb, TableCapacity(tg));
  fixgrp(tg);
  return re;
}

pSTR WINAPI PrintGRPTable(pSTR grp, HTBL tg)
{ // 集計項目リスト書出
  I4B i, ni = NTableRows(tg);
  pSTR pt;
  pGRPE pb;
  rCOLI cx = ((HTBL)tg->cs->co[0].pa2)->cs->co;
  I1B bf[LBUF];

  fixgrp(tg);
  *(pt = grp) = '\0';
  for (i = 0; i < ni; i++) {
    pb = (pGRPE)Row(tg, i); if (pb->ic < 0) break;
    switch (pb->sw) {
    case AGG_SUM: pt += sprintfs(pt, "%s(", "sum"); break;
    case AGG_AVG: pt += sprintfs(pt, "%s(", "avg"); break;
    case AGG_MAX: pt += sprintfs(pt, "%s(", "max"); break;
    case AGG_MIN: pt += sprintfs(pt, "%s(", "min"); break;
    case AGG_COU: pt += sprintfs(pt, "%s(", "count"); break;
    case AGG_GRP: pt += sprintfs(pt, "%s ", "groupby"); break;
    }
    pt += sprintfs(pt, "%s", cx[pb->ic].nam);
    if (pb->sw >= AGG_SUM && pb->sw <= AGG_COU) { pt += sprintfs(pt, ")");}
    if (pb->tit[0] != '\0') { pt += sprintfs(pt, " as '%s'", pb->tit);}
    if (pb->sb) { pt += sprintfs(pt, " %s", fprnFMT(bf, &pb->sb, NULL));}
    if (i < ni - 1 && (pb + 1)->ic >= 0) { pt += sprintfs(pt, ", ");}
  }
  return grp;
}

  // 絞り込み条件解析情報
typedef struct {
  I4B   ir;
  I4B   ic;
  rBIN  pb;
  pCNDM pc;
  rANY  bf;
  HTBL  tb;
} PRSB;

static PRSB BPB;

void LOCALF b_start(rANY pb, HTBL tc)
{ // 解析開始
  BPB.ir = 0;
  BPB.ic = 0;
  BPB.pb = (pU1B)pb;
  BPB.pc = (pCNDM)tc->mb;
  BPB.bf = "";
  BPB.tb = (HTBL)tc->cs->co[2].pa2;
}

I4B  LOCALF b_len(I4B i)
{ // 行の長さ
  pCNDE pb = &BPB.pc->ce[i]; return pb->rp + (pb->ic >= 0) * ((i > 0) + pb->lp + 3);
}

#define  TKN_ICO  24
#define  TKN_BIN  25

I4B  LOCALF b_token(void)
{ // トークン
  I4B i, j, cd = TKN_ERR;
  pCNDE pb;

  i = BPB.ir; j = BPB.ic;
  if (i >= BPB.pc->ni || j >= b_len(i)) { return TKN_END;}
  pb = &BPB.pc->ce[i];
  if (j < pb->rp) {
    cd = BOP_RPA;
  } else if (i > 0 && j == pb->rp) {
    switch (pb->lo) {
    case 1: cd = BKW_LAN; break;
    case 2: cd = BKW_LOR; break;
    }
  } else if (j >= pb->rp && j < pb->rp + (i > 0) + pb->lp) {
    cd = BOP_LPA;
  } else if (j == pb->rp + (i > 0) + pb->lp) {
    BPB.bf = &pb->ic;
    cd = TKN_ICO;
  } else if (j == pb->rp + (i > 0) + pb->lp + 1) {
    BPB.bf = pb->wk;
    cd = TKN_BIN;
  } else if (j == pb->rp + (i > 0) + pb->lp + 2) {
    switch (pb->cm) {
    case 1: cd = BOP_LEQ; break;
    case 2: cd = BOP_LNE; break;
    case 3: cd = BOP_LLT; break;
    case 4: cd = BOP_LLE; break;
    case 5: cd = BOP_LGT; break;
    case 6: cd = BOP_LGE; break;
    case 7: cd = BKW_MLK; break;
    case 8: cd = BKW_NML; break;
    }
  }
  if (cd != TKN_ERR) {
    j++; if (j >= b_len(i)) { i++; j = 0;}
    BPB.ir = i; BPB.ic = j;
  }
  return cd;
}

BOOL LOCALF b_token_is(I4B cd)
{ // トークン(先読み)
  I4B i, j, re;

  i = BPB.ir; j = BPB.ic;
  re = (b_token() == cd);
  if (!re) { BPB.ir = i; BPB.ic = j;}
  return re;
}

BOOL LOCALF b_lor_expr(void);

BOOL LOCALF b_cmp_expr(void)
{ // 比較式
  I4B ic, re = TRUE;
  rCOLI co;
  I1B bf[LBUF];

  switch (b_token()) {
  case TKN_ICO:
    ic = *(pI4B)BPB.bf;
    co = &BPB.tb->cs->co[ic];
    if (!b_token_is(TKN_BIN)) break;
    cscnval(bf, BPB.bf, co);
    switch (b_token()) {
    case BOP_LEQ: re = wcmpval(BPB.pb + OFS(co), bf, co) == 0; break;
    case BOP_LNE: re = wcmpval(BPB.pb + OFS(co), bf, co) != 0; break;
    case BOP_LLT: re = wcmpval(BPB.pb + OFS(co), bf, co) < 0; break;
    case BOP_LLE: re = wcmpval(BPB.pb + OFS(co), bf, co) <= 0; break;
    case BOP_LGT: re = wcmpval(BPB.pb + OFS(co), bf, co) > 0; break;
    case BOP_LGE: re = wcmpval(BPB.pb + OFS(co), bf, co) >= 0; break;
    case BKW_MLK: re = wmlkval(BPB.pb + OFS(co), bf, co) != 0; break;
    case BKW_NML: re = wmlkval(BPB.pb + OFS(co), bf, co) == 0; break;
    }
    break;
  case BOP_LPA:
    re = b_lor_expr();
    if (!b_token_is(BOP_RPA)) break;
    break;
  }
  return re;
}

BOOL LOCALF b_lan_expr(void)
{ // 論理的AND式
  if (!b_cmp_expr()) return FALSE;
  while (b_token_is(BKW_LAN)) {
    if (!b_cmp_expr()) return FALSE;
  }
  return TRUE;
}

BOOL LOCALF b_lor_expr(void)
{ // 論理的OR式
  if (b_lan_expr()) return TRUE;
  while (b_token_is(BKW_LOR)) {
    if (b_lan_expr()) return TRUE;
  }
  return FALSE;
}

BOOL LOCALF fselCND(rANY pb, uANY tc)
{ // 絞り込み条件による選択関数
  b_start(pb, (HTBL)tc); return b_lor_expr();
}

  // 集計用データ
typedef struct {
  rCOLI co;
  I4B   iv;
  I8B   lv;
  F8B   dv;
  I4B   cn;
} AGGP;

BOOL LOCALF faggSUM(rANY pb, AGGP *pa)
{ // 合計関数
  rANY pv;
  rCOLI co = pa->co;
  U1B rv[LBUF];

  pv = (pBIN)pb + OFS(co);
  if (ISCAL(co)) { pv = co_fcal(rv, pb, co);}
  if (iszero(pv, SIZ(co))) return FALSE;
  switch (BTP(co)) {
  case TID_I1B: pa->dv += (F8B)*(rI1B)pv; break;
  case TID_U1B: pa->dv += (F8B)*(rU1B)pv; break;
  case TID_I2B: pa->dv += (F8B)*(rI2B)pv; break;
  case TID_U2B: pa->dv += (F8B)*(rU2B)pv; break;
  case TID_I4B: pa->dv += (F8B)*(rI4B)pv; break;
  case TID_U4B: pa->dv += (F8B)*(rU4B)pv; break;
  case TID_I8B: pa->dv += (F8B)*(rI8B)pv; break;
  case TID_U8B: pa->dv += (F8B)*(rU8B)pv; break;
  case TID_F4B: pa->dv += (F8B)*(rF4B)pv; break;
  case TID_F8B: pa->dv += *(rF8B)pv; break;
  }
  pa->cn++;
  return TRUE;
}

BOOL LOCALF faggMAX(rANY pb, AGGP *pa)
{ // 最大値検索関数
  rANY pv;
  rCOLI co = pa->co;
  I4B iv; I8B lv; F8B dv;
  U1B rv[LBUF];

  pv = (pBIN)pb + OFS(co);
  if (ISCAL(co)) { pv = co_fcal(rv, pb, co);}
  if (iszero(pv, SIZ(co))) return FALSE;
  switch (BTP(co)) {
  case TID_I1B: iv = (I4B)*(rI1B)pv; goto _10;
  case TID_U1B: iv = (I4B)*(rU1B)pv; goto _10;
  case TID_I2B: iv = (I4B)*(rI2B)pv; goto _10;
  case TID_U2B: iv = (I4B)*(rU2B)pv; goto _10;
  case TID_I4B: iv = *(rI4B)pv; _10:
    if (pa->cn == 0 || iv > pa->iv) { pa->iv = iv;}
    break;
  case TID_U4B: iv = *(rU4B)pv;
    if (pa->cn == 0 || (U4B)iv > (U4B)pa->iv) { pa->iv = iv;}
    break;
  case TID_I8B: lv = *(rI8B)pv;
    if (pa->cn == 0 || lv > pa->lv) { pa->lv = lv;}
    break;
  case TID_U8B: lv = *(rU8B)pv;
    if (pa->cn == 0 || (U8B)lv > (U8B)pa->lv) { pa->lv = lv;}
    break;
  case TID_F4B: dv = (F8B)*(rF4B)pv; goto _20;
  case TID_F8B: dv = *(rF8B)pv; _20:
    if (pa->cn == 0 || dv > pa->dv) { pa->dv = dv;}
    break;
  }
  pa->cn++;
  return TRUE;
}

BOOL LOCALF faggMIN(rANY pb, AGGP *pa)
{ // 最小値検索関数
  rANY pv;
  rCOLI co = pa->co;
  I4B iv; I8B lv; F8B dv;
  U1B rv[LBUF];

  pv = (pBIN)pb + OFS(co);
  if (ISCAL(co)) { pv = co_fcal(rv, pb, co);}
  if (iszero(pv, SIZ(co))) return FALSE;
  switch (BTP(co)) {
  case TID_I1B: iv = (I4B)*(rI1B)pv; goto _10;
  case TID_U1B: iv = (I4B)*(rU1B)pv; goto _10;
  case TID_I2B: iv = (I4B)*(rI2B)pv; goto _10;
  case TID_U2B: iv = (I4B)*(rU2B)pv; goto _10;
  case TID_I4B: iv = *(rI4B)pv; _10:
    if (pa->cn == 0 || iv < pa->iv) { pa->iv = iv;}
    break;
  case TID_U4B: iv = *(rU4B)pv;
    if (pa->cn == 0 || (U4B)iv < (U4B)pa->iv) { pa->iv = iv;}
    break;
  case TID_I8B: lv = *(rI8B)pv;
    if (pa->cn == 0 || lv < pa->lv) { pa->lv = lv;}
    break;
  case TID_U8B: lv = *(rU8B)pv;
    if (pa->cn == 0 || (U8B)lv < (U8B)pa->lv) { pa->lv = lv;}
    break;
  case TID_F4B: dv = (F8B)*(rF4B)pv; goto _20;
  case TID_F8B: dv = *(rF8B)pv; _20:
    if (pa->cn == 0 || dv < pa->dv) { pa->dv = dv;}
    break;
  }
  pa->cn++;
  return TRUE;
}

BOOL LOCALF faggCOU(rANY pb, AGGP *pa)
{ // 個数集計関数
  rANY pv;
  rCOLI co = pa->co;
  U1B rv[LBUF];

  pv = (pBIN)pb + OFS(co);
  if (ISCAL(co)) { pv = co_fcal(rv, pb, co);}
  if (iszero(pv, SIZ(co))) return FALSE;
  pa->cn++;
  return TRUE;
}

I4B  LOCALF xcmpval(rANY p1, rANY p2, rCOLI co, I4B flg)
{ // 比較
  I4B re;
  U1B r1[LBUF], r2[LBUF];

  if (ISCAL(co)) { p1 = co_fcal(r1, p1, co); p2 = co_fcal(r2, p2, co);}
  if (flg & (SRT_ZRL|SRT_ZRF)) {
    re = iszero(p1, SIZ(co)) - iszero(p2, SIZ(co));
    if (flg & SRT_ZRF) { re = -re;}
    if (re) { return re;}
  }
  if ((flg & (SRT_PAL|SRT_PAF)) && BTP(co) == TID_STR) {
    re = (((rSTR)p1)[0] == '(') - (((rSTR)p2)[0] == '(');
    if (flg & SRT_PAF) { re = -re;}
    if (re) { return re;}
  }
  re = tp_fcmp(p1, p2, co);
  if (flg & SRT_DSN) { re = -re;}
  return re;
}

I4B  LOCALF fsrtSRT(rANY p1, rANY p2, uANY pa)
{ // 並べ替え比較関数
  I4B i, re, ni = NTableRows((HTBL)pa);
  HTBL tb = (HTBL)((HTBL)pa)->cs->co[0].pa2;
  rCOLI co;
  pSRTE pb;

  for (i = 0; i < ni; i++) {
    pb = (pSRTE)Row((HTBL)pa, i); if (pb->ic < 0) break;
    co = &tb->cs->co[pb->ic];
    re = xcmpval((pBIN)p1 + OFS(co), (pBIN)p2 + OFS(co), co, pb->flg);
    if (re) { return re;}
  }
  return 0;
}

//――――――――――――――――――――――――――――――――――――――//

HBUF WINAPI CreateRowBufX(pANY pv, rTBLI ti)
{ // 行バッファ作成
  HTBL rb;

  rb = CreateTableX(pv, 0, 1, ti); if (!rb) return NULL;
  if (!pv) { memset(TablePtr((HTBL)rb), 0, TableRowSize(rb));}
  SetLen(rb->mb, 1);
  rb->flg |= TF_FIX;
  rb->otb = rb;
  return (HBUF)rb;
}

HBUF WINAPI CreateRowBuf(HTBL tb)
{ // 行バッファ作成
  pANY pv;
  HTBL rb;
  HBLK mb;

  rb = halloc(sizeof(TBLE) + sizeof(BLKE) + TableRowSize(tb), FALSE); if (!rb) { return ierr(E_MEM);}
  mb = (pANY)((pBIN)rb + sizeof(TBLE));
  pv = (pANY)((pBIN)mb + sizeof(BLKE));
  memset(pv, 0, TableRowSize(tb));
  *rb = *tb;
  rb->mb = BuildArray(mb, pv, 1, 1, TableRowSize(tb));
  rb->otb = tb;
  rb->flg = (tb->flg | (TF_FIX|TF_STB)) &~TF_VIW;
  return (HBUF)rb;
}

void WINAPI DeleteRowBuf(HBUF rb)
{ // 行バッファの削除
  DeleteTable((HTBL)rb);
}

HBUF WINAPI DuplicateRowBuf(HBUF rb)
{ // 行バッファの複製
  HBUF rd;

  rd = CreateRowBuf(rb->otb); if (!rd) return NULL;
  memcpy(TablePtr((HTBL)rd), TablePtr((HTBL)rb), TableRowSize((HTBL)rb));
  return rd;
}

HTBL WINAPI RowBufHTBL(HBUF rb)
{ // 元の表
  return rb->otb;
}

pANY WINAPI RowBufPtr(HBUF rb)
{ // バッファのアドレス
  return TablePtr((HTBL)rb);
}

HBUF WINAPI MakeRowBuf(HTBL tb, pANY pb)
{ // 行アドレスを一時的に行バッファとして扱う
  HTBL rb;
  HBLK mb;

  rb = ualloc(sizeof(TBLE) + sizeof(BLKE));
  mb = (pANY)((pBIN)rb + sizeof(TBLE));
  *rb = *tb;
  rb->mb = BuildArray(mb, pb, 1, 1, TableRowSize(tb));
  rb->otb = tb;
  rb->flg = tb->flg | (TF_FIX|TF_STB|TF_TMP);
  return (HBUF)rb;
}

HBUF WINAPI TableRowBuf(HTBL tb, I4B ir)
{ // 表中の行を一時的に行バッファとして扱う
  return MakeRowBuf(tb, TableRow(tb, ir));
}

HBUF WINAPI NewTableRowBuf(HTBL tb)
{ // 追加行を一時的に行バッファとして扱う
  return MakeRowBuf(tb, NewTableRow(tb));
}

void LOCALF SetRowBufCellValue0(HBUF rb, I4B ic, rANY pv)
{ // 値の設定
  setval(TablePtr((HTBL)rb), pv, TableColumnInfo0((HTBL)rb, ic));
}

BOOL WINAPI SetRowBufCellValue(HBUF rb, I4B ic, rANY pv)
{ // 値の設定
  if (rb->flg & TF_RDO) { return (BOOL)ierr(E_RDO);}
  if (ic < 0 || ic >= NTableColumns((HTBL)rb)) { return (BOOL)ierr(E_ICO);}
  if (ISCAL(TableColumnInfo0((HTBL)rb, ic))) { return (BOOL)ierr(E_CAL);}
  SetRowBufCellValue0(rb, ic, pv);
  return TRUE;
}

pANY LOCALF GetRowBufCellValue0(pANY pv, HBUF rb, I4B ic)
{ // 値の取得
  return getval(pv, TablePtr((HTBL)rb), TableColumnInfo0((HTBL)rb, ic));
}

pANY WINAPI GetRowBufCellValue(pANY pv, HBUF rb, I4B ic)
{ // 値の取得
  if (ic < 0 || ic >= NTableColumns((HTBL)rb)) { ierr(E_ICO); return pv;}
  return GetRowBufCellValue0(pv, rb, ic);
}

void LOCALF ScanRowBufCellValue0(HBUF rb, I4B ic, rSTR st)
{ // 文字列から読込
  U1B wk[LBUF];

  scnval(wk, st, TableColumnInfo0((HTBL)rb, ic));
  setval(TablePtr((HTBL)rb), wk, TableColumnInfo0((HTBL)rb, ic));
}

BOOL WINAPI ScanRowBufCellValue(HBUF rb, I4B ic, rSTR st)
{ // 文字列から読込
  if (rb->flg & TF_RDO) { return (BOOL)ierr(E_RDO);}
  if (ic < 0 || ic >= NTableColumns((HTBL)rb)) { return (BOOL)ierr(E_ICO);}
  if (ISCAL(TableColumnInfo0((HTBL)rb, ic))) { return (BOOL)ierr(E_CAL);}
  ScanRowBufCellValue0(rb, ic, st);
  return TRUE;
}

pSTR LOCALF PrintRowBufCellValue0(pSTR st, HBUF rb, I4B ic)
{ // 文字列に書出
  rCOLI co = TableColumnInfo0((HTBL)rb, ic);

  return prnval(st, (pBIN)TablePtr((HTBL)rb) + OFS(co), co);
}

pSTR WINAPI PrintRowBufCellValue(pSTR st, HBUF rb, I4B ic)
{ // 文字列に書出
  if (ic < 0 || ic >= NTableColumns((HTBL)rb)) { ierr(E_ICO); st[0] = '\0'; return st;}
  return PrintRowBufCellValue0(st, rb, ic);
}

void LOCALF ClearRowBuf0(HBUF rb)
{ // 行バッファのクリア
  TableTrigger((HTBL)rb, TRGM_DEFAULT, 0, TablePtr((HTBL)rb));
}

BOOL WINAPI ClearRowBuf(HBUF rb)
{ // 行バッファのクリア
  if (rb->flg & TF_RDO) { return (BOOL)ierr(E_RDO);}
  ClearRowBuf0(rb);
  return TRUE;
}

HBUF LOCALF CopyRowBuf0(HBUF rb, HBUF rx)
{ // 行バッファから行バッファへのコピー
  memcpy(TablePtr((HTBL)rb), TablePtr((HTBL)rx), TableRowSize((HTBL)rx)); return rb;
}

HBUF WINAPI CopyRowBuf(HBUF rb, HBUF rx)
{ // 行バッファから行バッファへのコピー
  if (!IsCompatible((HTBL)rb, (HTBL)rx)) { ierr(E_CMP); return rb;}
  if (rb->flg & TF_RDO) { ierr(E_RDO); return rb;}
  return CopyRowBuf0(rb, rx);
}

BOOL LOCALF SetTableRow0(HTBL tb, I4B ir, HBUF rb)
{ // 行の設定
  I4B sz = TableRowSize(tb);
  pANY pb, bk;

  memcpy(bk = ualloc(sz), pb = Row(tb, ir), sz);
  memcpy(pb, TablePtr((HTBL)rb), sz);
  if (!TableTrigger(tb, TRGM_BEFOREUPDATE, ir, pb)) {
    memcpy(pb, bk, sz); return FALSE;
  }
  TableTrigger(tb, TRGM_AFTERUPDATE, ir, pb);
  return TRUE;
}

BOOL WINAPI SetTableRow(HTBL tb, I4B ir, HBUF rb)
{ // 行の設定
  if (!IsCompatible(tb, (HTBL)rb)) { return (BOOL)ierr(E_CMP);}
  if (tb->flg & TF_RDO) { return (BOOL)ierr(E_RDO);}
  return SetTableRow0(tb, ir, rb);
}

HBUF LOCALF GetTableRow0(HBUF rb, HTBL tb, I4B ir)
{ // 行の取得
  memcpy(TablePtr((HTBL)rb), Row(tb, ir), TableRowSize(tb)); return rb;
}

HBUF WINAPI GetTableRow(HBUF rb, HTBL tb, I4B ir)
{ // 行の取得
  if (!IsCompatible((HTBL)rb, tb)) { ierr(E_CMP); return rb;}
  if (rb->flg & TF_RDO) { ierr(E_RDO); return rb;}
  return GetTableRow0(rb, tb, ir);
}

BOOL LOCALF SetNewTableRow0(HTBL tb, HBUF rb)
{ // 行の追加
  return AddTableRow0(tb)? SetTableRow0(tb, NTableRows(tb) - 1, rb): FALSE;
}

BOOL WINAPI SetNewTableRow(HTBL tb, HBUF rb)
{ // 行の追加
  if (!IsCompatible(tb, (HTBL)rb)) { return (BOOL)ierr(E_CMP);}
  if (tb->flg & TF_RDO) { return (BOOL)ierr(E_RDO);}
  if (tb->flg & TF_FIX) { return (BOOL)ierr(E_FIX);}
  return SetNewTableRow0(tb, rb);
}

HBUF WINAPI CopyValues(HBUF rb, HBUF rx)
{ // 値のコピー
  I4B i, nx = rx->cs->nc;
  rCOLI co = rb->cs->co, cx = rx->cs->co, ci, cj, cf;

  if (rb->flg & TF_RDO) { ierr(E_RDO); return rb;}
  for (cj = cx, cf = cx + nx; cj < cf; cj++) {
    if ((i = TableColumnIndex((HTBL)rb, cj->nam)) >= 0) {
      ci = &co[i];
      if (!ISCAL(ci)) {
        cpyval((pBIN)TablePtr((HTBL)rb) + OFS(ci), ci, (pBIN)TablePtr((HTBL)rx) + OFS(cj), cj);
      }
    }
  }
  return rb;
}

HBUF WINAPI CopyKey(HBUF rb, HBUF rx)
{ // 外部キーのコピー
  I4B nx = rx->cs->nc;
  rCOLI co = rb->cs->co, cx = rx->cs->co, cj, cf;

  if (rb->flg & TF_RDO) { ierr(E_RDO); return rb;}
  for (cj = cx, cf = cx + nx; cj < cf; cj++) {
    if (!ISCAL(cj) && (cj->flg & CF_REF) && DBTable(RTI(cj)) == rb->otb) {
      memcpy((pBIN)TablePtr((HTBL)rb) + OFS(&co[RCI(cj)]), (pBIN)TablePtr((HTBL)rx) + OFS(cj), SIZ(cj));
    }
  }
  return rb;
}

I4B  WINAPI CompareRowBuf(HBUF rb, HBUF rx)
{ // 行バッファの比較
  return CompareArray(rb->mb, rx->mb);
}

I4B  WINAPI SearchKey(HTBL tb, HBUF rb)
{ // 主キーによるサーチ
  I4B ln = NTableRows(tb), nc = NTableColumns(tb), sz = TableRowSize(tb);
  rBIN pc, p0, pe, bf = TablePtr((HTBL)rb);
  rCOLI co = tb->cs->co, ci, ce;

  if (!IsCompatible(tb, (HTBL)rb)) { ierr(E_CMP); return -1;}
  if (NTableKeys(tb) == 0) return -1;
  for (pc = p0 = TablePtr(tb), pe = pc + ln * sz; pc < pe; pc += sz) {
    for (ci = co, ce = co + nc; ci < ce; ci++) {
      if (ci->flg & CF_KEY) {
        if (memcmp(pc + OFS(ci), bf + OFS(ci), SIZ(ci))) goto _10;
      }
    }
    return (pc - p0) / sz;
   _10:;
  }
  return -1;
}

HTBL WINAPI MergeTable(HTBL tb, HTBL tx)
{ // 表のマージ
  I4B i, j, ln, sz;
  HBUF rb;

  if (!IsCompatible(tb, tx)) { ierr(E_CMP); return tb;}
  if (tb->flg & TF_RDO) { ierr(E_RDO); return tb;}
  if (tb->flg & TF_FIX) { ierr(E_FIX); return tb;}
  rb = CreateRowBuf(tb); if (!rb) { return tb;}
  ln = NTableRows(tx); sz = TableRowSize(tx);
  for (i = 0; i < ln; i++) {
    GetTableRow0(rb, tx, i);
    if ((j = SearchKey(tb, rb)) >= 0) {
      memcpy(Row(tb, j), Row(tx, i), sz);
    } else {
      memcpy(NewTableRow0(tb), Row(tx, i), sz);
    }
  }
  DeleteRowBuf(rb);
  return tb;
}

I4B  WINAPI UniqueKey(HTBL tb, I4B ic, U4B h0, U4B hs)
{ // キー値の自動採番
  I4B i, ln = NTableRows(tb);
  U4B va, v0;
  rCOLI co;

  if (ic < 0 || ic >= NTableColumns(tb)) { return (I4B)ierr(E_ICO);}
  co = TableColumnInfo0(tb, ic);
  if (BTP(co) > TID_U4B) { return (I4B)ierr(E_NIN);}
  if (hs <= h0 + 1) { return (I4B)ierr(E_PAR);}
  va = v0 = h0 + hash(format("%s%d", CurUser(), get_tick_count()), hs - h0);
 _10:
  for (i = 0; i < ln; i++) {
    if (!memcmp((pBIN)Row(tb, i) + OFS(co), &va, SIZ(co))) {
      va++;
      if (va == hs) { va = h0;}
      if (va == v0) return 0;
      goto _10;
    }
  }
  return va;
}

I4B  WINAPI SearchTableRow(HTBL tb, I4B i0, rSTR cnd)
{ // 絞り込み条件によるサーチ
  I4B re;
  HTBL tc;

  tc = CreateCNDTable(VIWCAP, tb); if (!tc) return -1;
  ScanCNDTable(tc, cnd);
  re = SearchTableRowX(tb, i0, fselCND, (uANY)tc);
  DeleteTable(tc);
  return re;
}

I4B  WINAPI CountTableRows(HTBL tb, rSTR cnd)
{ // 絞り込み条件によるカウント
  I4B re;
  HTBL tc;

  tc = CreateCNDTable(VIWCAP, tb); if (!tc) return 0;
  ScanCNDTable(tc, cnd);
  re = CountTableRowsX(tb, fselCND, (uANY)tc);
  DeleteTable(tc);
  return re;
}

I4B  WINAPI SelectTableRows(HTBL tb, rSTR cnd)
{ // 絞り込み条件による絞り込み
  I4B re;
  HTBL tc;

  tc = CreateCNDTable(VIWCAP, tb); if (!tc) { return NTableRows(tb);}
  ScanCNDTable(tc, cnd);
  re = SelectTableRowsX(tb, fselCND, (uANY)tc);
  DeleteTable(tc);
  return re;
}

HTBL WINAPI SelectCopyTable(HTBL tb, HTBL tx, rSTR cnd)
{ // 絞り込みコピー
  HTBL tc;

  tc = CreateCNDTable(VIWCAP, tb); if (!tc) { return tb;}
  ScanCNDTable(tc, cnd);
  SelectCopyTableX(tb, tx, fselCND, (uANY)tc);
  DeleteTable(tc);
  return tb;
}

HTBL WINAPI SelectMergeTable(HTBL tb, HTBL tx, rSTR cnd)
{ // 絞り込みマージ(置換)
  HTBL tc;

  tc = CreateCNDTable(VIWCAP, tb); if (!tc) { return tb;}
  ScanCNDTable(tc, cnd);
  SelectMergeTableX(tb, tx, fselCND, (uANY)tc);
  DeleteTable(tc);
  return tb;
}

F8B  WINAPI AggregateTable(HTBL tb, I4B ic, I4B sw, rSTR cnd)
{ // 集計
  HTBL tc;
  FAGG fagg;
  F8B dv;
  AGGP apa;

  if (ic < 0 || ic >= NTableColumns(tb)) { ierr(E_ICO); return 0.0;}
  tc = CreateCNDTable(VIWCAP, tb); if (!tc) { return 0.0;}
  memset(&apa, 0, sizeof(AGGP));
  ScanCNDTable(tc, cnd);
  apa.co = TableColumnInfo0(tb, ic);
  switch (sw) {
  case AGG_SUM:
  case AGG_AVG: fagg = (FAGG)faggSUM; break;
  case AGG_MAX: fagg = (FAGG)faggMAX; break;
  case AGG_MIN: fagg = (FAGG)faggMIN; break;
  default:      fagg = (FAGG)faggCOU; break;
  }
  AggregateTableX(tb, fselCND, (uANY)tc, fagg, (uANY)&apa);
  switch (sw) {
  case AGG_SUM: dv = apa.dv; break;
  case AGG_AVG: dv = (apa.cn > 0)? apa.dv / apa.cn: 0.0; break;
  case AGG_MAX:
  case AGG_MIN:
    switch (BTP(apa.co)) {
    case TID_I1B: case TID_U1B:
    case TID_I2B: case TID_U2B:
    case TID_I4B: case TID_U4B: dv = (F8B)apa.iv; break;
    case TID_I8B: case TID_U8B: dv = (F8B)apa.lv; break;
    case TID_F4B: case TID_F8B: dv = apa.dv; break;
    }
    break;
  default: dv = (F8B)apa.cn; break;
  }
  DeleteTable(tc);
  return dv;
}

void WINAPI SortTableRows(HTBL tb, rSTR srt)
{ // 並べ替え
  HTBL ts;

  ts = CreateSRTTable(VIWCAP, tb); if (!ts) return;
  ScanSRTTable(ts, srt);
  SortTableRowsX(tb, fsrtSRT, (uANY)ts);
  DeleteTable(ts);
}

HTBL WINAPI CreateSummaryV(HTBL tb, rSTR grp, rSTR cnd, rSTR srt)
{ // 集計表作成
  HTBL tr;
  HVIW vw;

  vw = CreateView(tb, "*", cnd, srt); if (!vw) return NULL;
  tr = CreateSummary(vw, grp);
  DeleteView(vw);
  return tr;
}

#define  OPR_UPDATE  1
#define  OPR_INSERT  2
#define  OPR_DELETE  3

HTBL LOCALF CreateDIFTable(HTBL tb, HTBL tx)
{ // 差分表作成
  I4B i, j, ln = NTableRows(tb), lx = NTableRows(tx), nc = NTableColumns(tb);
  rCOLI co = tb->cs->co;
  pBIN pb;
  HTBL df;
  HBUF rb;
  static TBLI tbi;
  static COLI cx[] = { { TID_I4B,  0, "_opr", }, { TID_I4B,  0, "_dmy", } };

  if (!IsCompatible(tb, tx)) { return ierr(E_CMP);}
  tbi.cs = halloc(sizeof(COLS) + (nc + 2) * sizeof(COLI), FALSE); if (!tbi.cs) { return ierr(E_MEM);}
  tbi.cs->co = (pANY)((pBIN)tbi.cs + sizeof(COLS));
  tbi.cs->nc = nc + 2;
  tbi.cs->co[0] = cx[0];
  tbi.cs->co[1] = cx[1];
  for (i = 0; i < nc; i++) {
    tbi.cs->co[2 + i] = co[i];
  }
  rb = CreateRowBuf(tb); if (!rb) { df = NULL; goto _20;}
  df = CreateTable(0, &tbi); if (!df) goto _10;
  if (CompareTable(tb, tx) == 0) goto _10;
  for (i = 0; i < ln; i++) {
    GetTableRow0(rb, tb, i);
    if ((j = SearchKey(tx, rb)) >= 0) {
      if (CompareRowBuf(rb, TableRowBuf(tx, j))) {
        *(pI4B)(pb = NewTableRow0(df)) = OPR_UPDATE;
        memcpy(pb + 2 * sizeof(I4B), TablePtr((HTBL)rb), TableRowSize((HTBL)rb));
      }
    } else {
      *(pI4B)(pb = NewTableRow0(df)) = OPR_INSERT;
      memcpy(pb + 2 * sizeof(I4B), TablePtr((HTBL)rb), TableRowSize((HTBL)rb));
    }
  }
  for (i = 0; i < lx; i++) {
    GetTableRow0(rb, tx, i);
    if ((j = SearchKey(tb, rb)) < 0) {
      *(pI4B)(pb = NewTableRow0(df)) = OPR_DELETE;
      memcpy(pb + 2 * sizeof(I4B), TablePtr((HTBL)rb), TableRowSize((HTBL)rb));
    }
  }
 _10: DeleteRowBuf(rb);
 _20: hfree(tbi.cs);
  return df;
}

HTBL LOCALF MergeDIFTable(HTBL tb, HTBL df)
{ // 表と差分表のマージ
  I4B i, j, ln = NTableRows(df);
  HBUF rb;

  rb = CreateRowBuf(tb); if (!rb) { return tb;}
  for (i = 0; i < ln; i++) {
    memcpy(TablePtr((HTBL)rb), (pBIN)Row(df, i) + 2 * sizeof(I4B), TableRowSize((HTBL)rb));
    switch (*(pI4B)Row(df, i)) {
    case OPR_UPDATE:
      if ((j = SearchKey(tb, rb)) >= 0) {
        memcpy(Row(tb, j), (pBIN)Row(df, i) + 2 * sizeof(I4B), TableRowSize(tb));
      }
      break;
    case OPR_INSERT:
      if ((j = SearchKey(tb, rb)) < 0) {
        memcpy(NewTableRow0(tb), (pBIN)Row(df, i) + 2 * sizeof(I4B), TableRowSize(tb));
      }
      break;
    case OPR_DELETE:
      if ((j = SearchKey(tb, rb)) >= 0) {
        DeleteTableRow0(tb, j);
      }
      break;
    }
  }
  DeleteRowBuf(rb);
  return tb;
}

HTBL LOCALF DIFTableTrigger(HTBL tb, HTBL tx, HTBL df)
{ // 差分表によるトリガ
  I4B i, j, k, ln = NTableRows(df);
  HBUF rb;

  rb = CreateRowBuf(tb); if (!rb) { return tb;}
  for (i = 0; i < ln; i++) {
    memcpy(TablePtr((HTBL)rb), (pBIN)Row(df, i) + 2 * sizeof(I4B), TableRowSize((HTBL)rb));
    switch (*(pI4B)Row(df, i)) {
    case OPR_UPDATE:
      if ((j = SearchKey(tb, rb)) >= 0 && (k = SearchKey(tx, rb)) >= 0) {
        TableTrigger(tb, TRGM_UPDATERECORD, j, Row(tx, k));
      }
      break;
    case OPR_INSERT:
      if ((j = SearchKey(tb, rb)) >= 0) {
        TableTrigger(tb, TRGM_INSERTRECORD, j, Row(tb, j));
      }
      break;
    case OPR_DELETE:
      if ((k = SearchKey(tx, rb)) >= 0) {
        TableTrigger(tb, TRGM_DELETERECORD, 0, Row(tx, k));
      }
      break;
    }
  }
  DeleteRowBuf(rb);
  return tb;
}

BOOL WINAPI IsConflict(HTBL tb, HTBL tx)
{ // 競合のチェック
  I4B i, j, ln = NTableRows(tb), re = TRUE;
  HBUF rb;

  if (!IsCompatible(tb, tx)) { ierr(E_CMP); return TRUE;}
  rb = CreateRowBuf(tb); if (!rb) return TRUE;
  for (i = 0; i < ln; i++) {
    GetTableRow0(rb, tb, i);
    if ((j = SearchKey(tx, rb)) >= 0) {
      if (memcmp(Row(tx, j), TablePtr((HTBL)rb), TableRowSize((HTBL)rb))) goto _10;
    }
  }
  re = FALSE;
 _10: DeleteRowBuf(rb);
  return re;
}

BOOL WINAPI IsDependent(HTBL tb, I4B i1, I4B i2, rANY p1, rANY p2)
{ // 従属関係のチェック
  I4B i, ln = NTableRows(tb);
  rCOLI c1, c2;

  if (i1 < 0 || i1 >= tb->cs->nc || i2 < 0 || i2 >= tb->cs->nc) { return (BOOL)ierr(E_ICO);}
  c1 = &tb->cs->co[i1]; c2 = &tb->cs->co[i2];
  if (i1 == i2 || SIZ(c1) != SIZ(c2)) { return (BOOL)ierr(E_PAR);}
  for (i = 0; i < ln; i++) {
    if (!memcmp((pBIN)Row(tb, i) + OFS(c1), p1, SIZ(c1))) {
      if (!memcmp((pBIN)Row(tb, i) + OFS(c2), p2, SIZ(c1))) return TRUE;
    }
  }
  for (i = 0; i < ln; i++) {
    if (!memcmp((pBIN)Row(tb, i) + OFS(c1), p1, SIZ(c1))) {
      if (IsDependent(tb, i1, i2, (pBIN)Row(tb, i) + OFS(c2), p2)) return TRUE;
    }
  }
  return FALSE;
}

  // 表示形式セット項目
static rSTR SVUD[] = { "システム", "ユーザー" };
static ENMS esVUD = { SVUD, _countof(SVUD) };

static COLI ciVIW[] = {
  { STR(32),  0, "nam", "表示形式名",   NULL, CF_KEY, },
  { TID_E1B,  0, "ud",  "定義",         NULL, 0, NULL, NULL, (uANY)&esVUD, },
  { TID_U1B,  0, "us",  "選択",         },
  { TID_U2B,  0, "fc",  "固定列数",     },
  { STR(510), 0, "arr", "表示列名",     },
  { STR(320), 0, "cnd", "絞り込み条件", },
  { STR(320), 0, "srt", "並べ替え条件", },
};
static COLS csVIW = { ciVIW, _countof(ciVIW) };
static TBLI tiVIW = { &csVIW, NULL, "BOLVIW", };

HTBL WINAPI CreateVIWTable(I4B cap, rVIWS vs)
{ // 表示形式セット作成
  I4B i;
  HTBL tv;
  VIWE dat;

  if (vs && cap < vs->ni) { cap = vs->ni;}
  tv = CreateTable(cap, &tiVIW); if (!tv) return NULL;
  if (!vs) { return tv;}
  for (i = 0; i < vs->ni; i++) {
    strcpyx(dat.nam, vs->vi[i].nam? vs->vi[i].nam: format("_%03d", i + 1), sizeof(dat.nam) - 1);
    dat.ud = dat.us = 0;
    dat.fc = vs->vi[i].fc;
    strcpyx(dat.arr, vs->vi[i].arr? vs->vi[i].arr: "", sizeof(dat.arr) - 1);
    strcpyx(dat.cnd, vs->vi[i].cnd? vs->vi[i].cnd: "", sizeof(dat.cnd) - 1);
    strcpyx(dat.srt, vs->vi[i].srt? vs->vi[i].srt: "", sizeof(dat.srt) - 1);
    *(pVIWE)NewTableRow0(tv) = dat;
  }
  return tv;
}

pVIWI WINAPI SetVIWInfo(pVIWI vi, HBUF bv)
{ // 表示形式
  pVIWE pv = (pVIWE)TablePtr((HTBL)bv);

  vi->nam = pv->nam;
  vi->fc  = pv->fc;
  vi->arr = pv->arr;
  vi->cnd = pv->cnd;
  vi->srt = pv->srt;
  return vi;
}

I4B  WINAPI SearchVIWTableRow(HTBL tv, HBUF bv)
{ // 表示形式のサーチ
  pVIWE pb, pe, pv = (pVIWE)TablePtr((HTBL)bv);

  for (pb = (pVIWE)TablePtr(tv), pe = pb + NTableRows(tv); pb < pe; pb++) {
    if (pb->fc == pv->fc && !strcmp(pb->arr, pv->arr) && !strcmp(pb->cnd, pv->cnd) && !strcmp(pb->srt, pv->srt)) {
      return pb - (pVIWE)TablePtr(tv);
    }
  }
  return -1;
}

I4B  WINAPI SearchVIWTableRowByName(HTBL tv, rSTR nam)
{ // 表示形式名によるサーチ
  pVIWE pb, pe;

  for (pb = (pVIWE)TablePtr(tv), pe = pb + NTableRows(tv); pb < pe; pb++) {
    if (!strcmp(pb->nam, nam)) {
      return pb - (pVIWE)TablePtr(tv);
    }
  }
  return -1;
}

void WINAPI SetLastVIW(HTBL tv, HBUF bv)
{ // 最後に選択された表示形式を設定
  I4B ir;

  if ((ir = SearchVIWTableRow(tv, bv)) >= 0) { ((pVIWE)Row(tv, ir))->us = 1;}
}

I4B  WINAPI GetLastVIW(HTBL tv)
{ // 最後に選択された表示形式を取得してクリア
  pVIWE pb, pe;

  for (pb = (pVIWE)TablePtr(tv), pe = pb + NTableRows(tv); pb < pe; pb++) {
    if (pb->us) { pb->us = 0; return pb - (pVIWE)TablePtr(tv);}
  }
  return -1;
}

BOOL LOCALF fselVIW(pVIWE pb, uANY pa)
{ // ユーザー定義項目
  return pb->ud == 1;
}

void WINAPI CopyUserVIWTable(HTBL tv, HTBL tx)
{ // ユーザー定義項目のみコピー
  SelectCopyTableX(tv, tx, (FSEL)fselVIW, 0);
}

//――――――――――――――――――――――――――――――――――――――//

HVIW WINAPI CreateView0(HTBL tb)
{ // ビュー作成
  pI4B pi;
  pIDXS vr, vc;
  HTBL vw;

  vw = halloc(sizeof(TBLE) + 2 * sizeof(IDXS) + tb->cs->nc * sizeof(I4B), FALSE); if (!vw) { return ierr(E_MEM);}
  vr = (pANY)((pBIN)vw + sizeof(TBLE));
  vc = (pANY)((pBIN)vr + sizeof(IDXS));
  pi = halloc(TableCapacity(tb) * sizeof(I4B), FALSE); if (!pi) { hfree(vw); return ierr(E_MEM);}
  *vw = *tb;
  vr->pi = pi;
  vr->ni = 0;
  vw->vr = vr;
  vc->pi = (pI4B)((pBIN)vc + sizeof(IDXS));
  vc->ni = 0;
  vw->vc = vc;
  vw->otb = tb;
  vw->flg = tb->flg | TF_VIW;
  return (HVIW)vw;
}

HVIW WINAPI CreateViewX(HTBL tb, rIDXS pa, FSEL fsel, uANY ps, FSRT fsrt, uANY pc)
{ // ビュー作成
  HVIW vw;

  vw = CreateView0(tb); if (!vw) return NULL;
  ArrangeViewColumnsX(vw, pa);
  SelectViewRowsX(vw, fsel, ps);
  SortViewRowsX(vw, fsrt, pc);
  return vw;
}

HVIW WINAPI CreateView(HTBL tb, rSTR arr, rSTR cnd, rSTR srt)
{ // ビュー作成
  HTBL ta, tc, ts;
  HVIW vw = NULL;

  ta = CreateARRTable(0, tb);      if (!ta) goto _30;
  tc = CreateCNDTable(VIWCAP, tb); if (!tc) goto _20;
  ts = CreateSRTTable(VIWCAP, tb); if (!ts) goto _10;
  ScanARRTable(ta, arr);
  ScanCNDTable(tc, cnd);
  ScanSRTTable(ts, srt);
  vw = CreateViewX(tb, (rIDXS)ta->mb, fselCND, (uANY)tc, fsrtSRT, (uANY)ts);
  DeleteTable(ts); _10:
  DeleteTable(tc); _20:
  DeleteTable(ta); _30:
  return vw;
}

void WINAPI DeleteView(HVIW vw)
{ // ビューの削除
  DeleteTable((HTBL)vw);
}

HTBL WINAPI ViewHTBL(HVIW vw)
{ // 元の表
  return vw->otb;
}

I4B  WINAPI NViewRows(HVIW vw)
{ // 行数
  return vw->vr->ni;
}

pANY WINAPI ViewRow(HVIW vw, I4B ir)
{ // 行のアドレス
  if (ir < 0 || ir >= NViewRows(vw)) { ierr(E_IRO); return valloc(TableRowSize((HTBL)vw));}
  return Row((HTBL)vw, vw->vr->pi[ir]);
}

I4B  WINAPI ViewRowIndex(HVIW vw, I4B ir)
{ // ビュー上の行インデックスから実表上の行インデックスを求める
  return vw->vr->pi[ir];
}

I4B  WINAPI NViewColumns(HVIW vw)
{ // 列数
  return vw->vc->ni;
}

rCOLI LOCALF ViewColumnInfo0(HVIW vw, I4B ic)
{ // 列情報
  return vw->cs->co + vw->vc->pi[ic];
}

rCOLI WINAPI ViewColumnInfo(HVIW vw, I4B ic)
{ // 列情報
  if (ic < 0 || ic >= NViewColumns(vw)) { ierr(E_ICO); return valloc(sizeof(COLI));}
  return ViewColumnInfo0(vw, ic);
}

void WINAPI SetViewColumnWidth(HVIW vw, I4B ic, I4B wd)
{ // 列幅の設定
  if (ic < 0 || ic >= NViewColumns(vw)) { ierr(E_ICO); return;}
  WID(ViewColumnInfo0(vw, ic)) = (U1B)wd;
}

I4B  WINAPI ViewColumnWidth(HVIW vw, I4B ic)
{ // 列幅
  if (ic < 0 || ic >= NViewColumns(vw)) { return (I4B)ierr(E_ICO);}
  return WID(ViewColumnInfo0(vw, ic));
}

I4B  WINAPI ViewColumnWidthF(HVIW vw, I4B ic)
{ // 列幅
  I4B wd;

  if (!vw || ic < 0 || ic >= vw->vc->ni) { return DEFCWID;}
  wd = WID(ViewColumnInfo0(vw, ic)); { return wd? wd: DEFCWID;}
}

void WINAPI SetViewColumnTextAlign(HVIW vw, I4B ic, I4B al)
{ // 列の文字揃えコードの設定
  if (ic < 0 || ic >= NViewColumns(vw)) { ierr(E_ICO); return;}
  ALN(ViewColumnInfo0(vw, ic)) = (U1B)al;
}

I4B  WINAPI ViewColumnTextAlign(HVIW vw, I4B ic)
{ // 列の文字揃えコード
  if (ic < 0 || ic >= NViewColumns(vw)) { return (I4B)ierr(E_ICO);}
  return ALN(ViewColumnInfo0(vw, ic));
}

I4B  WINAPI ViewColumnTextAlignF(HVIW vw, I4B ic)
{ // 列の文字揃えコード
  if (!vw || ic < 0 || ic >= vw->vc->ni) { return ALN_RGT;}
  return ALN(ViewColumnInfo0(vw, ic));
}

rSTR WINAPI ViewColumnName(HVIW vw, I4B ic)
{ // 列名
  if (ic < 0 || ic >= NViewColumns(vw)) { ierr(E_ICO); return "";}
  return ViewColumnInfo0(vw, ic)->nam;
}

I4B  WINAPI ViewColumnIndex(HVIW vw, I4B ic)
{ // ビュー上の列インデックスから実表上の列インデックスを求める
  return vw->vc->pi[ic];
}

void WINAPI SetViewColumnTitle(HVIW vw, I4B ic, rSTR tit)
{ // 列タイトルの設定
  rCOLI co;

  if (ic < 0 || ic >= NViewColumns(vw)) { ierr(E_ICO); return;}
  co = ViewColumnInfo0(vw, ic);
  ((pCOLI)co)->tit = tit? tit: co->nam;
}

rSTR WINAPI ViewColumnTitle(HVIW vw, I4B ic)
{ // 列タイトル
  if (ic < 0 || ic >= NViewColumns(vw)) { ierr(E_ICO); return "";}
  return ViewColumnInfo0(vw, ic)->tit;
}

void WINAPI SetViewColumnDescription(HVIW vw, I4B ic, rSTR dsc)
{ // 列説明の設定
  rCOLI co;

  if (ic < 0 || ic >= NViewColumns(vw)) { ierr(E_ICO); return;}
  co = ViewColumnInfo0(vw, ic);
  ((pCOLI)co)->dsc = dsc? dsc: co->tit;
}

rSTR WINAPI ViewColumnDescription(HVIW vw, I4B ic)
{ // 列説明
  if (ic < 0 || ic >= NViewColumns(vw)) { ierr(E_ICO); return "";}
  return ViewColumnInfo0(vw, ic)->dsc;
}

rSTR WINAPI ViewColumnDescriptionR(HVIW vw, I4B ic)
{ // 列説明
  I4B ln;
  rSTR st;

  if (ic < 0 || ic >= NViewColumns(vw)) { ierr(E_ICO); return "";}
  st = ViewColumnInfo0(vw, ic)->dsc;
  if ((ln = strlen(st)) >= 4 && st[ln-4] == '(' && st[ln-3] == '&' && isaln(&st[ln-2]) && st[ln-1] == ')') {
    st = strcpyn(talloc(ln - 3), st, ln - 4);
  }
  return st;
}

void WINAPI SetViewColumnFlags(HVIW vw, I4B ic, I4B flg)
{ // 列属性の設定
  if (ic < 0 || ic >= NViewColumns(vw)) { ierr(E_ICO); return;}
  ((pCOLI)ViewColumnInfo0(vw, ic))->flg = flg;
}

I4B  WINAPI ViewColumnFlags(HVIW vw, I4B ic)
{ // 列属性
  if (ic < 0 || ic >= NViewColumns(vw)) { return (I4B)ierr(E_ICO);}
  return ViewColumnInfo0(vw, ic)->flg;
}

I4B  WINAPI ViewColumnFlagsF(HVIW vw, I4B ic)
{ // 列属性
  if (!vw || ic < 0 || ic >= vw->vc->ni) return 0;
  return ViewColumnInfo0(vw, ic)->flg;
}

void WINAPI SetViewColumnExtra(HVIW vw, I4B ic, uANY pa)
{ // 列の付加情報の設定
  if (ic < 0 || ic >= NViewColumns(vw)) { ierr(E_ICO); return;}
  ((pCOLI)ViewColumnInfo0(vw, ic))->pa2 = pa;
}

uANY WINAPI ViewColumnExtra(HVIW vw, I4B ic)
{ // 列の付加情報
  if (ic < 0 || ic >= NViewColumns(vw)) { return (uANY)ierr(E_ICO);}
  return ViewColumnInfo0(vw, ic)->pa2;
}

BOOL LOCALF SetViewCellValue0(HVIW vw, I4B ir, I4B ic, rANY pv)
{ // 値の設定
  return SetTableCellValue0((HTBL)vw, vw->vr->pi[ir], vw->vc->pi[ic], pv);
}

BOOL WINAPI SetViewCellValue(HVIW vw, I4B ir, I4B ic, rANY pv)
{ // 値の設定
  if (vw->flg & TF_RDO) { return (BOOL)ierr(E_RDO);}
  if (ir < 0 || ir >= NViewRows(vw)) { return (BOOL)ierr(E_IRO);}
  if (ic < 0 || ic >= NViewColumns(vw)) { return (BOOL)ierr(E_ICO);}
  if (ISCAL(ViewColumnInfo0(vw, ic))) { return (BOOL)ierr(E_CAL);}
  return SetViewCellValue0(vw, ir, ic, pv);
}

pANY LOCALF GetViewCellValue0(pANY pv, HVIW vw, I4B ir, I4B ic)
{ // 値の取得
  return GetTableCellValue0(pv, (HTBL)vw, vw->vr->pi[ir], vw->vc->pi[ic]);
}

pANY WINAPI GetViewCellValue(pANY pv, HVIW vw, I4B ir, I4B ic)
{ // 値の取得
  if (ir < 0 || ir >= NViewRows(vw)) { ierr(E_IRO); return pv;}
  if (ic < 0 || ic >= NViewColumns(vw)) { ierr(E_ICO); return pv;}
  return GetViewCellValue0(pv, vw, ir, ic);
}

BOOL LOCALF ScanViewCellValue0(HVIW vw, I4B ir, I4B ic, rSTR st)
{ // 文字列から読込
  return ScanTableCellValue0((HTBL)vw, vw->vr->pi[ir], vw->vc->pi[ic], st);
}

BOOL WINAPI ScanViewCellValue(HVIW vw, I4B ir, I4B ic, rSTR st)
{ // 文字列から読込
  if (vw->flg & TF_RDO) { return (BOOL)ierr(E_RDO);}
  if (ir < 0 || ir >= NViewRows(vw)) { return (BOOL)ierr(E_IRO);}
  if (ic < 0 || ic >= NViewColumns(vw)) { return (BOOL)ierr(E_ICO);}
  if (ISCAL(ViewColumnInfo0(vw, ic))) { return (BOOL)ierr(E_CAL);}
  return ScanViewCellValue0(vw, ir, ic, st);
}

BOOL WINAPI ScanViewCellValueF(HVIW vw, I4B ir, I4B ic, rSTR st)
{ // 文字列から読込
  if (!vw || (vw->flg & TF_RDO) || ir < 0 || ir >= NViewRows(vw) || ic < 0 || ic >= vw->vc->ni) return FALSE;
  if (ViewColumnInfo0(vw, ic)->flg & (CF_HCH|CF_RDO|CF_DED)) return FALSE;
  return ScanViewCellValue0(vw, ir, ic, st);
}

pSTR LOCALF PrintViewCellValue0(pSTR st, HVIW vw, I4B ir, I4B ic)
{ // 文字列に書出
  return PrintTableCellValue0(st, (HTBL)vw, vw->vr->pi[ir], vw->vc->pi[ic]);
}

pSTR WINAPI PrintViewCellValue(pSTR st, HVIW vw, I4B ir, I4B ic)
{ // 文字列に書出
  if (ir < 0 || ir >= NViewRows(vw)) { ierr(E_IRO); st[0] = '\0'; return st;}
  if (ic < 0 || ic >= NViewColumns(vw)) { ierr(E_ICO); st[0] = '\0'; return st;}
  return PrintViewCellValue0(st, vw, ir, ic);
}

pSTR WINAPI PrintViewCellValueF(pSTR st, HVIW vw, I4B ir, I4B ic, I4B flg)
{ // 文字列に書出
  st[0] = '\0';
  if (!vw || ir >= NViewRows(vw) || ic >= vw->vc->ni) { return st;}
  switch ((ir >= 0) * 2 + (ic >= 0)) {
  case 0:
    break;
  case 1:
    if (flg & PVF_TIT) { strcpys(st, ViewColumnTitle(vw, ic));}
    else if (flg & PVF_IDX) { sprintfs(st, "%d", vw->vc->pi[ic] + (flg & PVF_OBI));}
    else { strcpys(st, ViewColumnName(vw, ic));}
    break;
  case 2:
    sprintfs(st, "%d", vw->vr->pi[ir] + (flg & PVF_OBI));
    break;
  default:
    PrintViewCellValue0(st, vw, ir, ic);
    break;
  }
  return st;
}

BOOL WINAPI ClearViewRow(HVIW vw, I4B ir)
{ // 行のクリア
  return ClearViewRows(vw, ir, 1);
}

BOOL WINAPI ClearViewRows(HVIW vw, I4B ir, I4B nr)
{ // 範囲のクリア
  I4B i, sz = TableRowSize((HTBL)vw), nv = NViewRows(vw), re = TRUE;
  rI4B vi = vw->vr->pi;
  pANY pb, bk;

  if (vw->flg & TF_RDO) { return (BOOL)ierr(E_RDO);}
  if (ir + nr > nv) { nr = nv - ir;}
  if (ir < 0 || ir > nv || nr < 0) { return (BOOL)ierr(E_IRO);}
  bk = ualloc(sz);
  for (i = ir; i < ir + nr; i++) {
    memcpy(bk, pb = Row((HTBL)vw, vi[i]), sz);
    TableTrigger(vw->otb, TRGM_DEFAULT, vi[i], pb);
    if (!TableTrigger(vw->otb, TRGM_BEFOREUPDATE, vi[i], pb)) {
      memcpy(pb, bk, sz); re = FALSE;
    } else {
      TableTrigger(vw->otb, TRGM_AFTERUPDATE, vi[i], pb);
    }
  }
  return re;
}

BOOL WINAPI InsertViewRow(HVIW vw, I4B ir)
{ // 行の挿入
  return InsertViewRows(vw, ir, 1);
}

BOOL WINAPI InsertViewRows(HVIW vw, I4B ir, I4B nr)
{ // 範囲の挿入
  I4B i, k, ln = NTableRows((HTBL)vw), sz = TableRowSize((HTBL)vw), nv = NViewRows(vw);
  pI4B vi;

  if (vw->flg & TF_RDO) { return (BOOL)ierr(E_RDO);}
  if (vw->flg & TF_FIX) { return (BOOL)ierr(E_FIX);}
  if (ir < 0 || ir > nv || nr < 0) { return (BOOL)ierr(E_IRO);}
  if (ln + nr > TableCapacity((HTBL)vw)) {
    if (!ChangeTableCapacity0((HTBL)vw, ln + nr)) return FALSE;
  }
  vi = vw->vr->pi;
  if (ir < nv) {
    k = vi[ir];
    memmove(Row((HTBL)vw, k + nr), Row((HTBL)vw, k), (ln - k) * sz);
  } else {
    k = ln;
  }
  for (i = 0; i < nv; i++) {
    if (vi[i] >= k) { vi[i] += nr;}
  }
  if (ir < nv) {
    memmove(vi + ir + nr, vi + ir, (nv - ir) * sizeof(I4B));
  }
  for (i = ir; i < ir + nr; i++) {
    vi[i] = k + i - ir;
  }
  AddLen(vw->mb, nr);
  vw->vr->ni += nr;
  for (i = k; i < k + nr; i++) {
    TableTrigger(vw->otb, TRGM_DEFAULT, i, Row((HTBL)vw, i));
  }
  return TRUE;
}

BOOL WINAPI DeleteViewRow(HVIW vw, I4B ir)
{ // 行の削除
  return DeleteViewRows(vw, ir, 1);
}

BOOL WINAPI DeleteViewRows(HVIW vw, I4B ir, I4B nr)
{ // 範囲の削除
  I4B i, j, di, ln = NTableRows((HTBL)vw), sz = TableRowSize((HTBL)vw), nv = NViewRows(vw);
  pI4B vi = vw->vr->pi;

  if (vw->flg & TF_RDO) { return (BOOL)ierr(E_RDO);}
  if (vw->flg & TF_FIX) { return (BOOL)ierr(E_FIX);}
  if (ir == nv && nr >= 0) return TRUE;
  if (ir + nr > nv) { nr = nv - ir;}
  if (ir < 0 || ir > nv || nr < 0) { return (BOOL)ierr(E_IRO);}
  for (i = ir; i < ir + nr; i++) {
    if (!TableTrigger(vw->otb, TRGM_BEFOREDELETE, vi[i], Row((HTBL)vw, vi[i]))) return FALSE;
  }
  di = 0;
  for (j = 0; j < ln; j++) {
    for (i = 0; i < nv; i++) {
      if (vi[i] == j) {
        if (i >= ir && i < ir + nr) { di++; goto _10;}
        vi[i] -= di; break;
      }
    }
    if (di > 0) {
      memcpy(Row((HTBL)vw, j - di), Row((HTBL)vw, j), sz);
    }
   _10:;
  }
  if (ir + nr < nv) {
    memmove(vi + ir, vi + ir + nr, (nv - ir - nr) * sizeof(I4B));
  }
  AddLen(vw->mb, -di);
  vw->vr->ni -= nr;
  return TRUE;
}

BOOL WINAPI AddViewRow(HVIW vw)
{ // 行の追加
  return InsertViewRow(vw, vw->vr->ni);
}

pANY WINAPI NewViewRow(HVIW vw)
{ // 追加行
  return AddViewRow(vw)? Row((HTBL)vw, vw->vr->pi[vw->vr->ni - 1]): valloc(TableRowSize((HTBL)vw));
}

void WINAPI ArrangeViewColumnsX(HVIW vw, rIDXS pa)
{ // 列構成の設定
  I4B i, n, nc;
  pI4B vc = vw->vc->pi;
  rCOLI co;

  if (!pa) {
    co = vw->cs->co; nc = vw->cs->nc;
    for (n = i = 0; i < nc; i++) {
      if (WID(&co[i]) && !ISCAL(&co[i])) { vc[n++] = i;}
    }
  } else {
    for (n = i = 0; i < pa->ni; i++) {
      vc[n++] = pa->pi[i];
    }
  }
  vw->vc->ni = n;
}

I4B  WINAPI SearchViewRowX(HVIW vw, I4B i0, FSEL fsel, uANY pa)
{ // サーチ
  I4B i, nv = vw->vr->ni;
  rI4B vi = vw->vr->pi;

  if (i0 < 0 || i0 > nv) { ierr(E_IRO); return -1;}
  if (!fsel) { return i0;}
  for (i = i0; i < nv; i++) {
    if (fsel(Row((HTBL)vw, vi[i]), pa)) { return i;}
  }
  return -1;
}

I4B  WINAPI CountViewRowsX(HVIW vw, FSEL fsel, uANY pa)
{ // カウント
  I4B i, n, nv = vw->vr->ni;
  rI4B vi = vw->vr->pi;

  if (!fsel) { return nv;}
  for (n = i = 0; i < nv; i++) {
    if (fsel(Row((HTBL)vw, vi[i]), pa)) { n++;}
  }
  return n;
}

I4B  WINAPI SelectViewRowsX(HVIW vw, FSEL fsel, uANY pa)
{ // 絞り込み
  I4B i, n, ln = NTableRows((HTBL)vw);
  pI4B vi = vw->vr->pi;

  if (!fsel) { fsel = fselALL;}
  for (n = i = 0; i < ln; i++) {
    if (fsel(Row((HTBL)vw, i), pa)) {
      vi[n++] = i;
    }
  }
  return vw->vr->ni = n;
}

void WINAPI SortViewRowsX(HVIW vw, FSRT fsrt, uANY pa)
{ // 並べ替え
  I4B g, i, j, s, t, nv = NViewRows(vw);
  pI4B vi = vw->vr->pi;

  if (!fsrt || nv <= 1) return;
  g = nv;
  do {
    switch (g = g * 10 / 13) {
    case 0: g = 1; break;
    case 9: case 10: g = 11; break;
    }
    s = 0;
    for (i = 0, j = g; j < nv; i++, j++) {
      if (fsrt(Row((HTBL)vw, vi[i]), Row((HTBL)vw, vi[j]), pa) > 0) {
        t = vi[i]; vi[i] = vi[j]; vi[j] = t;
        s = 1;
      }
    }
  } while (s != 0 || g > 1);
}

void WINAPI ArrangeViewColumns(HVIW vw, rSTR arr)
{ // 列構成の設定
  HTBL ta;

  ta = CreateARRTable(0, (HTBL)vw); if (!ta) return;
  ScanARRTable(ta, arr);
  ArrangeViewColumnsX(vw, (rIDXS)ta->mb);
  DeleteTable(ta);
}

I4B  WINAPI SearchViewRow(HVIW vw, I4B i0, rSTR cnd)
{ // 絞り込み条件式によるサーチ
  I4B re;
  HTBL tc;

  tc = CreateCNDTable(VIWCAP, (HTBL)vw); if (!tc) return -1;
  ScanCNDTable(tc, cnd);
  re = SearchViewRowX(vw, i0, fselCND, (uANY)tc);
  DeleteTable(tc);
  return re;
}

I4B  WINAPI CountViewRows(HVIW vw, rSTR cnd)
{ // 絞り込み条件式によるカウント
  I4B re;
  HTBL tc;

  tc = CreateCNDTable(VIWCAP, (HTBL)vw); if (!tc) return 0;
  ScanCNDTable(tc, cnd);
  re = CountViewRowsX(vw, fselCND, (uANY)tc);
  DeleteTable(tc);
  return re;
}

I4B  WINAPI SelectViewRows(HVIW vw, rSTR cnd)
{ // 絞り込み条件式による絞り込み
  I4B re;
  HTBL tc;

  tc = CreateCNDTable(VIWCAP, (HTBL)vw); if (!tc) { return NTableRows((HTBL)vw);}
  ScanCNDTable(tc, cnd);
  re = SelectViewRowsX(vw, fselCND, (uANY)tc);
  DeleteTable(tc);
  return re;
}

void WINAPI SortViewRows(HVIW vw, rSTR srt)
{ // 並べ替え
  HTBL ts;

  ts = CreateSRTTable(VIWCAP, (HTBL)vw); if (!ts) return;
  ScanSRTTable(ts, srt);
  SortViewRowsX(vw, fsrtSRT, (uANY)ts);
  DeleteTable(ts);
}

void WINAPI SortTableRowsByView(HVIW vw)
{ // ビュー上の並び順による並べ替え
  I4B i, j, k, sz = TableRowSize((HTBL)vw), nv = NViewRows(vw);
  pI4B vi = vw->vr->pi;

  if (vw->flg & TF_RDO) { ierr(E_RDO); return;}
  for (i = 0; i < nv; i++) {
    k = vi[i]; if (k == i) continue;
    memswap(Row((HTBL)vw, i), Row((HTBL)vw, k), sz);
    vi[i] = i;
    for (j = i + 1; j < nv; j++) {
      if (vi[j] == i) { vi[j] = k; break;}
    }
  }
}

  // 集計項目データ
typedef struct {
  rCOLI co;   // -+
  I4B   iv;   //  |
  I8B   lv;   //  |
  F8B   dv;   //  |= AGGP
  I4B   cn;   // -+
  FAGG  fagg;
  I4B   df;
} AGGX;

HTBL LOCALF CreateSummaryX(HVIW vw, HTBL tg)
{ // 集計表作成
  I4B i, j, g, id, sz, wd, nv = vw->vr->ni;
  rI4B vi = vw->vr->pi;
  rBIN pb, pl;
  pGRPM pg = (pGRPM)tg->mb;
  rCOLI co; pCOLI ci;
  AGGX *ax;
  HTBL tr;
  HBUF rb;
  static TBLI tbi = { NULL, NULL, "BOLAGG", "集計表", NULL, TF_NOA|TF_DTR, };
  I1B bf[LBUF];

  tbi.cs = halloc(sizeof(COLS) + pg->ni * sizeof(COLI), FALSE); if (!tbi.cs) { return ierr(E_MEM);}
  tbi.cs->co = (pANY)((pBIN)tbi.cs + sizeof(COLS));
  ax = halloc(pg->ni * sizeof(AGGX), FALSE); if (!ax) { ierr(E_MEM); goto _50;}
  g = -1;
  for (i = 0; i < pg->ni; i++) {
    if (pg->ge[i].ic < 0) break;
    ax[i].co = co = &vw->cs->co[pg->ge[i].ic];
    wd = WID(co);
    switch (pg->ge[i].sw) {
    case AGG_SUM:
    case AGG_AVG: ax[i].fagg = (FAGG)faggSUM;
      id = (TIDOF(co) == TID_M8B)? TID_M8B: TID_F8B;
      goto _20;
    case AGG_MAX: ax[i].fagg = (FAGG)faggMAX; goto _10;
    case AGG_MIN: ax[i].fagg = (FAGG)faggMIN; _10:
      switch (BTP(co)) {
      case TID_I1B:
      case TID_U1B:
      case TID_I2B:
      case TID_U2B: id = TID_I4B; break;
      case TID_I4B: id = (TIDOF(co) == TID_M4B)? TID_M4B: TID_I4B; break;
      case TID_U4B: id = TID_U4B; break;
      case TID_I8B: id = TID_I8B; break;
      case TID_U8B: id = TID_U8B; break;
      case TID_F4B: id = TID_F8B; break;
      case TID_F8B: id = (TIDOF(co) == TID_M8B)? TID_M8B: TID_F8B; break;
      default:      id = TID_I4B; break;
      }
      goto _20;
    case AGG_COU: ax[i].fagg = (FAGG)faggCOU;
      id = TID_I4B;
     _20:
      sz = ctpsiz(BTP(&TIE[id]));
      switch (pg->ge[i].sb) {
      case FMT_DEC:
        if (id == TID_M4B) { id = TID_I4B;} else if (id == TID_M8B) { id = TID_F8B;}
        break;
      case FMT_CMA:
        if (id == TID_I4B) { id = TID_M4B;} else if (id == TID_F8B) { id = TID_M8B;}
        break;
      }
      if (pg->ge[i].wd > 0) {
        wd = pg->ge[i].wd + (pg->ge[i].sb == FMT_CMA) * 2 + (pg->ge[i].sc > 0) + strlen(pg->ge[i].unt);
      }
      break;
    default: ax[i].fagg = NULL;
      id = TID_STR;
      sz = wd + 4;
      if (pg->ge[i].sw == AGG_GRP) { g = i;}
      break;
    }
    ci = &tbi.cs->co[i];
    *ci = *co;
    ci->itp = MKU4B(id, sz);
    ci->atr = ATR(wd, ALN(co));
    ci->nam = "";
    if (pg->ge[i].tit[0]) {
      ci->tit = stostr(pg->ge[i].tit);
    }
    if (pg->ge[i].sb != 0 || id != TIDOF(co)) {
      ci->pa0 = (uANY)decfmt(id, &pg->ge[i]);
    }
    ci->flg &=~(CF_DDL|CF_DDN|CF_LNK);
  }
  tbi.cs->nc = i;
  tr = CreateTable(0, &tbi); if (!tr) goto _40;
  rb = CreateRowBuf(tr); if (!rb) { DeleteTable(tr); tr = NULL; goto _40;}
  for (i = 0; i <= nv; i++) {
    if (i > 0) { pl = pb;}
    if (i < nv) { pb = Row((HTBL)vw, vi[i]);}
    if (i == 0) goto _30;
    if (i == nv || (g >= 0 && cmpval(pl + OFS(ax[g].co), pb + OFS(ax[g].co), ax[g].co) != 0)) {
      for (j = 0; j < tbi.cs->nc; j++) {
        bf[0] = '\0';
        switch (pg->ge[j].sw) {
        case AGG_SUM:
          *(pF8B)bf = ax[j].dv; break;
        case AGG_AVG:
          *(pF8B)bf = (ax[j].cn > 0)? ax[j].dv / ax[j].cn: 0.0; break;
        case AGG_MAX:
        case AGG_MIN:
          switch (BTP(ax[j].co)) {
          case TID_I4B: case TID_U4B: *(pI4B)bf = ax[j].iv; break;
          case TID_I8B: case TID_U8B: *(pI8B)bf = ax[j].lv; break;
          case TID_F8B:               *(pF8B)bf = ax[j].dv; break;
          }
          break;
        case AGG_COU:
          *(pI4B)bf = ax[j].cn; break;
        default:
          if (ax[j].df == 0) { PrintTableCellValue0(bf, (HTBL)vw, vi[i-1], pg->ge[j].ic);}
          break;
        }
        SetRowBufCellValue0(rb, j, bf);
      }
      SetNewTableRow0(tr, rb); if (i == nv) break;
     _30:
      for (j = 0; j < tbi.cs->nc; j++) {
        ax[j].iv = 0; ax[j].lv = 0LL; ax[j].dv = 0.0; ax[j].cn = ax[j].df = 0;
      }
    } else {
      for (j = 0; j < tbi.cs->nc; j++) {
        if (pg->ge[j].sw == 0 && ax[j].df == 0) {
          ax[j].df = cmpval(pl + OFS(ax[j].co), pb + OFS(ax[j].co), ax[j].co);
        }
      }
    }
    for (j = 0; j < tbi.cs->nc; j++) {
      if (ax[j].fagg) { ax[j].fagg(pb, (uANY)&ax[j]);}
    }
  }
  DeleteRowBuf(rb);
 _40: hfree(ax);
 _50: hfree(tbi.cs);
  return tr;
}

HTBL WINAPI CreateSummary(HVIW vw, rSTR grp)
{ // 集計表作成
  HTBL tg, tr;

  tg = CreateGRPTable(VIWCAP, (HTBL)vw); if (!tg) return NULL;
  ScanGRPTable(tg, grp);
  tr = CreateSummaryX(vw, tg);
  DeleteTable(tg);
  return tr;
}

I4B  WINAPI SearchViewCellValue(HVIW vw, I4B i0, I4B ic, rANY pv)
{ // 値のサーチ
  I4B i, nv = vw->vr->ni;
  rI4B vi = vw->vr->pi;
  rCOLI co;
  U1B rv[LBUF];

  if (i0 < 0 || i0 > nv) { ierr(E_IRO); return -1;}
  if (ic < 0 || ic >= NViewColumns(vw)) { ierr(E_ICO); return -1;}
  co = ViewColumnInfo0(vw, ic);
  for (i = i0; i < nv; i++) {
    if (!memcmp(getval(rv, Row((HTBL)vw, vi[i]), co), pv, SIZ(co))) { return i;}
  }
  return -1;
}

I4B  WINAPI SearchViewCellText(HVIW vw, I4B i0, I4B ic, rSTR st, I4B flg)
{ // 文字列のサーチ
  I4B i, nv = vw->vr->ni;
  rI4B vi = vw->vr->pi;
  rCOLI co;
  I1B bf[LBUF];

  if (i0 < 0 || i0 > nv) { ierr(E_IRO); return -1;}
  if (ic < 0 || ic >= NViewColumns(vw)) { ierr(E_ICO); return -1;}
  co = ViewColumnInfo0(vw, ic);
  for (i = i0; i < nv; i++) {
    if (strfindx(prnval(bf, (pBIN)Row((HTBL)vw, vi[i]) + OFS(co), co), st, flg)) { return i;}
  }
  return -1;
}

I4B  LOCALF readval(pSTR wk, rSTR pt, rCSVI cv)
{ // 項目の読込
  I4B d;
  rSTR p1, p2, p3;

  p1 = pt;
  if (cv->dlm == ' ') { while (*p1 == ' ') { p1++;}}
  if (cv->quo && *p1 == cv->quo) {
    p1++;
    d = cv->quo;
  } else {
    d = cv->dlm;
  }
  p2 = p1;
  while (*p2 != '\0' && *p2 != d) { p2++;}
  p3 = p2;
  if (d == cv->quo && *p2 == d) {
    p3++;
    d = cv->dlm;
  }
  while (*p3 != '\0' && *p3 != d) { p3++;}
  if (cv->quo == 0) {
    if (*p1 == '\"' && p2 > p1 + 1 && *(p2-1) == '\"') {
      p1++; p2--;
    }
  }
  spncpy(wk, p1, p2);
  return p3 - pt;
}

#define  LBSZ  16384

BOOL WINAPI ReadCSV(HVIW vw, rSTR nam, rCSVI cv)
{ // ＣＳＶ読込
  I4B i, n, nc, ir, sw, re = FALSE;
  pI4B vi;
  pSTR bf, pt, pe;
  HBUF rb;
  HFIL hf;
  U1B wk[LBUF];

  if (vw->flg & TF_RDO) { return (BOOL)ierr(E_RDO);}
  if (vw->flg & TF_FIX) { return (BOOL)ierr(E_FIX);}
  bf = halloc(LBSZ, FALSE); if (!bf) { return (BOOL)ierr(E_MEM);}
  rb = CreateRowBuf((HTBL)vw); if (!rb) goto _30;
  hf = open_file(nam, OP_RDO); if (!hf) { ferr(E_FIR, nam); goto _20;}
  if (cv->tsw != TSW_NON) {
    read_line(hf, bf, LBSZ);
    pe = bf + strlen(bf);
  }
  if (cv->tsw == TSW_NAM) {
    nc = vw->cs->nc; if (nc < 64) { nc = 64;}
    vi = halloc(nc * sizeof(I4B), FALSE); if (!vi) { ierr(E_MEM); goto _10;}
    for (i = 0, pt = bf; i < nc && pt < pe; i++, pt += n + 1) {
      n = readval(wk, pt, cv);
      vi[i] = TableColumnIndex((HTBL)vw, wk);
    }
    for ( ; i < nc; i++) {
      vi[i] = -1;
    }
  } else {
    nc = vw->vc->ni;
  }
  while (read_line(hf, bf, LBSZ)) {
    pe = bf + strlen(bf);
    ClearRowBuf0(rb);
    sw = 0;
   _00:
    for (i = 0, pt = bf; i < nc && pt < pe; i++, pt += n + 1) {
      n = readval(wk, pt, cv);
      if (cv->tsw == TSW_NAM) {
        if (vi[i] >= 0) { ScanRowBufCellValue0(rb, vi[i], wk);}
      } else {
        ScanRowBufCellValue0(rb, ViewColumnIndex(vw, i), wk);
      }
    }
    if (sw == 0) {
      if ((ir = SearchKey((HTBL)vw, rb)) >= 0) {
        GetTableRow0(rb, (HTBL)vw, ir);
        sw = 1; goto _00;
      } else {
        ir = TableRowIndex((HTBL)vw, NewViewRow(vw));
      }
    }
    SetTableRow0((HTBL)vw, ir, rb);
  }
  if (cv->tsw == TSW_NAM) { hfree(vi);}
  re = TRUE;
 _10: close_file(hf);
 _20: DeleteRowBuf(rb);
 _30: hfree(bf);
  return re;
}

BOOL WINAPI WriteCSV(HVIW vw, rSTR nam, rCSVI cv)
{ // ＣＳＶ書出
  I4B i, j, op, nv = NViewRows(vw), nc = vw->vc->ni, sw, re = FALSE;
  pSTR bf, pt;
  HFIL hf;
  U1B wk[LBUF];

  bf = halloc(LBSZ, FALSE); if (!bf) { return (BOOL)ierr(E_MEM);}
  hf = open_file(nam, OP_WRI); if (!hf) { ferr(E_FIW, nam); goto _10;}
  op = (cv->tsw == TSW_NAM)? PVF_NAM: PVF_TIT;
  for (i = -(cv->tsw != TSW_NON); i < nv; i++) {
    pt = bf;
    for (j = 0; j < nc; j++) {
      if (ViewColumnWidth(vw, j) == 0) continue;
      PrintViewCellValueF(wk, vw, i, j, op);
      sw = (strspn(wk, "-.0123456789") != strlen(wk));
      if (cv->quo && sw) { *pt++ = cv->quo;}
      pt += sprintfs(pt, "%s", wk);
      if (cv->quo && sw) { *pt++ = cv->quo;}
      if (cv->dlm && j < nc - 1) { *pt++ = cv->dlm;}
    }
    *pt = '\0';
    write_line(hf, bf);
  }
  re = TRUE;
  close_file(hf);
 _10: hfree(bf);
  return re;
}

BOOL WINAPI ReadINI(pANY pb, rTBLI ti)
{ // 初期化ファイルから読込
  I4B ic, n, re = FALSE;
  HBUF rb;
  HFIL hf;
  I1B bf[LBUF];

  rb = CreateRowBufX(pb, ti); if (!rb) return FALSE;
  hf = open_file(ti->imp, OP_RDO); if (!hf) { ferr(E_FIR, ti->imp); goto _20;}
  n = 0;
  while (read_line(hf, bf, sizeof(bf))) {
    start(bf);
    if (token_is(TKN_IDN)) {
      if ((ic = TableColumnIndex((HTBL)rb, buf())) >= 0) {
        if (token_is(BOP_LEQ)) {
          ScanRowBufCellValue0(rb, ic, cpos());
          n++;
        }
      }
    }
  }
  if (n == 0) { ferr(E_FIR, ti->imp); goto _10;}
  re = TRUE;
 _10: close_file(hf);
 _20: DeleteRowBuf(rb);
  return re;
}

BOOL WINAPI WriteINI(pANY pb, rTBLI ti)
{ // 初期化ファイルに書出
  I4B i, re = FALSE;
  HBUF rb;
  HFIL hf;
  I1B bf[LBUF];

  rb = CreateRowBufX(pb, ti); if (!rb) return FALSE;
  hf = open_file(ti->imp, OP_WRI); if (!hf) { ferr(E_FIW, ti->imp); goto _10;}
  for (i = 0; i < ti->cs->nc; i++) {
    strcpys(bf, TableColumnTitle((HTBL)rb, i));
    if (bf[0] == '[') {
      write_line(hf, bf);
    }
    if (TableColumnFlags((HTBL)rb, i) & CF_DED) continue;
    sprintfs(bf, "%s=", TableColumnName((HTBL)rb, i)); PrintRowBufCellValue0(bf + strlen(bf), rb, i);
    write_line(hf, bf);
  }
  re = TRUE;
  close_file(hf);
 _10: DeleteRowBuf(rb);
  return re;
}

BOOL WINAPI ReadATR(pANY pb, rTBLI ti, rSTR st)
{ // 属性読込
  I4B ic;
  HBUF rb;

  rb = CreateRowBufX(pb, ti); if (!rb) return FALSE;
  start(st);
  while (token_is(TKN_IDN)) {
    if ((ic = TableColumnIndex((HTBL)rb, buf())) >= 0) {
      if (token_is(BOP_LEQ)) {
        if (token_is(TKN_U4B)) {
          ScanRowBufCellValue0(rb, ic, format("%d", *(rI4B)buf()));
        } else if (token_is(TKN_F8B)) {
          ScanRowBufCellValue0(rb, ic, format("%.15G", *(rF8B)buf()));
        } else if (token_is(TKN_STR) || token_is(TKN_IDN)) {
          ScanRowBufCellValue0(rb, ic, buf());
        } else break;
      } else break;
    } else break;
  }
  DeleteRowBuf(rb);
  return cpos() > st;
}

I4B  WINAPI RowBlkSize(HVIW vw, I4B nr)
{ // 行ブロックのサイズ
  return (vw->cs->nc + 2) * sizeof(I4B) + nr * TableRowSize((HTBL)vw);
}

void WINAPI CopyRowBlk(pANY pv, HVIW vw, I4B i0, I4B nr)
{ // 行ブロックのコピー
  I4B i, sz = TableRowSize((HTBL)vw), nv = vw->vr->ni, nc = vw->cs->nc;
  pBIN pb = pv;
  rI4B vi = vw->vr->pi;
  rCOLI co = vw->cs->co;

  if (i0 < 0 || i0 > nv || nr < 0) { ierr(E_IRO); return;}
  if (i0 + nr > nv) { nr = nv - i0;}
  *((pI4B)pb)++ = nc;
  for (i = 0; i < nc; i++) {
    *((pI4B)pb)++ = co[i].itp;
  }
  *((pI4B)pb)++ = nr;
  for (i = 0; i < nr; i++) {
    memcpy(pb, Row((HTBL)vw, vi[i0 + i]), sz);
    pb += sz;
  }
}

BOOL WINAPI InsertRowBlk(HVIW vw, I4B i0, rANY pv)
{ // 行ブロックの挿入
  I4B i, nr, nv = vw->vr->ni, nc = vw->cs->nc;
  rBIN pb = pv;
  rCOLI co = vw->cs->co;

  if (vw->flg & TF_RDO) { return (BOOL)ierr(E_RDO);}
  if (vw->flg & TF_FIX) { return (BOOL)ierr(E_FIX);}
  if (i0 < 0 || i0 > nv) { return (BOOL)ierr(E_IRO);}
  if (*((pI4B)pb)++ != nc) return FALSE;
  for (i = 0; i < nc; i++) {
    if (*((pI4B)pb)++ != co[i].itp) return FALSE;
  }
  nr = *((pI4B)pb)++;
  if (!InsertViewRows(vw, i0, nr)) return FALSE;
  memcpy(Row((HTBL)vw, vw->vr->pi[i0]), pb, nr * TableRowSize((HTBL)vw));
  return TRUE;
}

//――――――――――――――――――――――――――――――――――――――//

#define  PRGNAM  "BOLYAI"

static I1B  SNAM[16] = PRGNAM;
static I1B  STIT[32] = PRGNAM;
static I1B  SDSC[64] = PRGNAM;

static rSTR SLOG = PRGNAM".LOG";

static F8B  RTAX = 0.10;

static I4B  FYMN =  4;
static I4B  NMFY = 12;

static I1B  UDIR[LBUF] = "C:\\NFILES\\";

static I4B  CYMD;

void WINAPI SetSiteVariables(rSITI sv)
{ // サイト変数の設定
  if (sv->nam && strlen(sv->nam) < sizeof(SNAM) && isidn(sv->nam)) {
    strcpys(SNAM, sv->nam);
    SLOG = addext(sv->nam, ".LOG");
  }
  if (sv->tit && strlen(sv->tit) < sizeof(STIT)) { strcpys(STIT, sv->tit);}
  if (sv->dsc && strlen(sv->dsc) < sizeof(SDSC)) { strcpys(SDSC, sv->dsc);}
  if (sv->dir && strlen(sv->dir) < sizeof(UDIR)) { strcpys(UDIR, sv->dir);}
  if (sv->tax > 0.0 && sv->tax < 1.0) { RTAX = sv->tax;}
  if (sv->fym >= 1 && sv->fym <= 12)  { FYMN = sv->fym;}
  if (sv->nmf >= 1 && sv->nmf <= 18)  { NMFY = sv->nmf;}
}

rSTR WINAPI SiteName(void)
{ // サイト名
  return SNAM;
}

rSTR WINAPI SiteTitle(void)
{ // サイトタイトル
  return STIT;
}

rSTR WINAPI SiteDescription(void)
{ // サイト説明
  return SDSC;
}

F8B  WINAPI TaxRate(void)
{ // 消費税率
  return RTAX;
}

I4B  WINAPI FYearMonth(void)
{ // 事業年度開始月
  return FYMN;
}

I4B  WINAPI NMonthFYear(void)
{ // 事業年度月数
  return NMFY;
}

void WINAPI SetUserPath(rSTR dir)
{ // ユーザーフォルダの設定
  if (dir && strlen(dir) < LBUF) { strcpys(UDIR, dir);}
}

rSTR WINAPI UserPath(void)
{ // ユーザーフォルダ
  return UDIR;
}

void WINAPI SetCurDate(I4B sr)
{ // 計算日の設定
  if (sr) { CYMD = sr;}
}

I4B  WINAPI CurDate(void)
{ // 計算日
  return CYMD;
}

I4B  WINAPI BFYear(void)
{ // 事業年度開始日
  return date_serial(year(CYMD) - (month(CYMD) < FYMN), FYMN, 1);
}

I4B  WINAPI EFYear(void)
{ // 事業年度終了日
  return date_serial(year(BFYear()), FYMN + NMFY, 0);
}

I4B  WINAPI BMonth(void)
{ // 当月初日
  return date_serial(year(CYMD), month(CYMD), 1);
}

I4B  WINAPI EMonth(void)
{ // 当月末日
  return date_serial(year(CYMD), month(CYMD) + 1, 0);
}

//――――――――――――――――――――――――――――――――――――――//

BOOL LOCALF ftrgBSA(HTBL tb, I4B msg, I4B ir, pBSAI pb)
{ // ユーザー管理表トリガ関数
  switch (msg) {
  case MKU4B(TRGM_BEFOREUPDATEOF, 0):
    if (pb->usr[0] == '\0') { return (BOOL)terr(E_NUS, ir, 0);}
    break;
  case MKU4B(TRGM_BEFOREUPDATEOF, 1):
    if (pb->pwd[0] == '\0') { return (BOOL)terr(E_NPW, ir, 1);}
    break;
  case TRGM_BEFOREUPDATE:
    if (pb->usr[0] == '\0') { return (BOOL)terr(E_NUS, ir, 0);}
    if (pb->pwd[0] == '\0') { return (BOOL)terr(E_NPW, ir, 1);}
    break;
  }
  return DefaultTableTrigger(tb, msg, ir, (pANY)pb);
}

static rSTR SLEV[] = { "", "閲覧", "編集", "ＤＢ管理", "サイト管理" };
static ENMS esLEV = { SLEV, _countof(SLEV) };

static COLI ciBSA[] = {
  { STR(32),  0, "usr", "ユーザー名",   NULL, CF_KEY, },
  { STR(32),  0, "pwd", "パスワード",   NULL, CF_DSP, },
  { TID_E4B,  0, "lev", "権限",         NULL, CF_DDL, NULL, NULL, (uANY)&esLEV, },
};
static COLS csBSA = { ciBSA, _countof(ciBSA) };
static TBLI tiBSA = { &csBSA, NULL, "BOLBSA", "ユーザー管理表", NULL, TF_CYP, (FTRG)ftrgBSA, };

HTBL WINAPI CreateBSATable(I4B cap, BOOL ld)
{ // ユーザー管理表作成
  HTBL tb;

  tiBSA.imp = addext(SNAM, ".BSA");
  tb = CreateTable(cap, &tiBSA); if (!tb) return NULL;
  if (ld) { LoadBTB(tb);}
  return tb;
}

I4B  LOCALF srchbsa(HTBL tb, rSTR usr)
{ // ユーザー管理表のサーチ
  I4B i, ln = NTableRows(tb);

  for (i = 0; i < ln; i++) {
    if (!_stricmp(usr, ((pBSAI)Row(tb, i))->usr)) { return i;}
  }
  return -1;
}

I4B  LOCALF db_fenm0(HTBL tb, I4B pro)
{ // ダミー
  return 0;
}

static FENM db_fenm = db_fenm0;

void WINAPI override_db_fenm(FENM fenm)
{ // バイトコードのリスト作成関数登録
  db_fenm = fenm;
}

static COLI ciBSD[] = {
  { STR(16), 10, "nam", "名前",     NULL, CF_KEY, },
  { STR(32), 20, "tit", "タイトル", },
  { STR(64), 22, "dsc", "説明",     },
};
static COLS csBSD = { ciBSD, _countof(ciBSD) };
static TBLI tiBSD = { &csBSD, NULL, "BOLBSD", };

HTBL WINAPI CreateBSDTable(I4B cap, I4B pro)
{ // バイトコードリスト作成
  HTBL tb;

  tiBSD.imp = addext(SNAM, ".BSD");
  tb = CreateTable(cap, &tiBSD); if (!tb) return NULL;
  if (pro) { db_fenm(tb, pro);}
  return tb;
}

static COLI ciBSU[] = {
  { STR(32),  0, "usr", "ユーザー名", NULL, CF_KEY, },
};
static COLS csBSU = { ciBSU, _countof(ciBSU) };
static TBLI tiBSU = { &csBSU, NULL, "BOLBSU", };

HTBL WINAPI CreateBSUTable(I4B cap, BOOL ld)
{ // ログイン中ユーザーリスト作成
  HTBL tb;

  tiBSU.imp = addext(SNAM, ".BSU");
  tb = CreateTable(cap, &tiBSU); if (!tb) return NULL;
  if (ld) { LoadBTB(tb);}
  return tb;
}

BOOL LOCALF fselBSU(pBSUI pb, pBSUI pa)
{ // 選択関数
  return !strcmp(pb->usr, pa->usr);
}

BOOL LOCALF addusr(HTBL tb, rSTR usr)
{ // ユーザーを追加
  BSUI dat;

  new_file_if_not_exists(tb->imp);
  if (!OpenBTB(tb)) return FALSE;
  strcpyx(dat.usr, usr, sizeof(dat.usr) - 1);
  if (SearchTableRowX(tb, 0, (FSEL)fselBSU, (uANY)&dat) < 0) {
    *(pBSUI)NewTableRow0(tb) = dat;
  }
  return CloseBTB(tb, TRUE);
}

BOOL LOCALF delusr(HTBL tb, rSTR usr)
{ // ユーザーを削除
  I4B ir;
  BSUI dat;

  if (file_size(tb->imp) == 0) return FALSE;
  if (!OpenBTB(tb)) return FALSE;
  strcpyx(dat.usr, usr, sizeof(dat.usr) - 1);
  if ((ir = SearchTableRowX(tb, 0, (FSEL)fselBSU, (uANY)&dat)) >= 0) {
    DeleteTableRow0(tb, ir);
  }
  return CloseBTB(tb, TRUE);
}

BOOL LOCALF loglog(BOOL sw, rSTR usr)
{ // ログインログ書出
  HFIL hf;

  hf = open_file(SLOG, OP_APD); if (!hf) return FALSE;
  set_file_ptr(hf, 0, FILE_END);
  write_line(hf, strconc(dtformat("yyyy/mm/dd hh:mm:ss", now()), format(" %1d %s", sw, usr)));
  close_file(hf);
  return TRUE;
}

  // ＤＢ内の表情報
typedef struct {
  HTBL  tb;
  HTBL  tc;
  HTBL  tx;
  BOOL  rw;
  pVIWS vs;
} BDBE;
typedef BDBE *pBDBE;

static BDBE deBSA;
#define  hBSA  deBSA.tb
static HTBL hBSU;

static HTBL hBDU;
static HTBL hREF;
static HTBL hLCK;

static I1B  CUSR[32];
static I4B  CLEV;

static I1B  CNAM[16];
static I1B  CTIT[32];
static I1B  CDSC[64];
static I4B  CSTA;

static pBDBE CDE;
static I4B   NDE;

#define  ciBDD  ciBSD
static COLS csBDD = { ciBDD, _countof(ciBDD) };
static TBLI tiBDD = { &csBDD, NULL, "BOLBDD", };

HTBL WINAPI CreateBDDTable(I4B cap, BOOL ld)
{ // ＤＢ内の表リスト作成
  I4B i;
  HTBL tb;
  BDDI dat;

  tiBDD.imp = addext(CNAM, ".BDD");
  if (cap < NDE && CDE) { cap = NDE;}
  tb = CreateTable(cap, &tiBDD); if (!tb) return NULL;
  if (ld && CDE) {
    for (i = 0; i < NDE; i++) {
      strcpyx(dat.nam, CDE[i].tb->nam, sizeof(dat.nam) - 1);
      strcpyx(dat.tit, CDE[i].tb->tit, sizeof(dat.tit) - 1);
      strcpyx(dat.dsc, CDE[i].tb->dsc, sizeof(dat.dsc) - 1);
      *(pBDDI)NewTableRow0(tb) = dat;
    }
  }
  return tb;
}

static TBLI tiBDU = { &csBSU, NULL, "BOLBDU", };

HTBL WINAPI CreateBDUTable(I4B cap, BOOL ld)
{ // ＤＢ接続中ユーザーリスト作成
  HTBL tb;

  tiBDU.imp = addext(CNAM, ".BDU");
  tb = CreateTable(cap, &tiBDU); if (!tb) return NULL;
  if (ld && CDE) { LoadBTB(tb);}
  return tb;
}

  // 参照関係管理表
typedef struct {
  I4B   id1;
  I4B   id2;
} REFE;
typedef REFE *pREFE;

static COLI ciREF[] = {
  { TID_I4B,  0, "id1", "参照元", NULL, CF_KEY, },
  { TID_I4B,  0, "id2", "参照先", NULL, CF_KEY, },
};
static COLS csREF = { ciREF, _countof(ciREF) };
static TBLI tiREF = { &csREF, NULL, "BOLREF", };

HTBL LOCALF CreateREFTable(I4B cap)
{ // 参照関係管理表作成
  tiREF.imp = addext(CNAM, ".REF");
  return CreateTable(cap, &tiREF);
}

BOOL LOCALF fselREF(pREFE pb, pREFE pa)
{ // 選択関数
  return pb->id1 == pa->id1 && pb->id2 == pa->id2;
}

void LOCALF setref(HTBL tb, I4B id1, I4B id2)
{ // 表の参照関係を登録
  REFE dat;

  dat.id1 = id1; dat.id2 = id2;
  if (SearchTableRowX(tb, 0, (FSEL)fselREF, (uANY)&dat) < 0) {
    *(pREFE)NewTableRow0(tb) = dat;
  }
}

BOOL LOCALF isref(HTBL tb, I4B id1, I4B id2)
{ // 表の参照関係のチェック
  return IsDependent(tb, 0, 1, &id1, &id2);
}

static COLI ciLCK[] = {
  { TID_I4B,  0, "id",  "表ID",       NULL, CF_KEY, },
  { STR(32),  0, "usr", "ユーザー名", },
};
static COLS csLCK = { ciLCK, _countof(ciLCK) };
static TBLI tiLCK = { &csLCK, NULL, "BOLLCK", };

HTBL WINAPI CreateLCKTable(I4B cap, BOOL ld)
{ // ロック情報管理表作成
  HTBL tb;

  tiLCK.imp = addext(CNAM, ".LCK");
  tb = CreateTable(cap, &tiLCK); if (!tb) return NULL;
  if (ld && CDE) { LoadBTB(tb);}
  return tb;
}

BOOL LOCALF fselLCK(pLCKI pb, pLCKI pa)
{ // 選択関数
  return pb->id == pa->id;
}

BOOL LOCALF lock(HTBL tb, rSTR usr, rIDXS pt)
{ // ロック
  I4B i, ir, re = FALSE;
  LCKI dat;

  new_file_if_not_exists(tb->imp);
  if (!OpenBTB(tb)) return FALSE;
  strcpyx(dat.usr, usr, sizeof(dat.usr) - 1);
  for (i = 0; i < pt->ni; i++) {
    dat.id = pt->pi[i];
    if ((ir = SearchTableRowX(tb, 0, (FSEL)fselLCK, (uANY)&dat)) >= 0) {
      if (strcmp(((pLCKI)Row(tb, ir))->usr, usr)) { ierr(E_LCK); goto _10;}
    } else {
      *(pLCKI)NewTableRow0(tb) = dat;
    }
  }
  re = TRUE; _10:
  return CloseBTB(tb, re);
}

BOOL LOCALF unlock(HTBL tb, rSTR usr, rIDXS pt)
{ // アンロック
  I4B i, ir, re = FALSE;
  LCKI dat;

  if (file_size(tb->imp) == 0) return FALSE;
  if (!OpenBTB(tb)) return FALSE;
  strcpyx(dat.usr, usr, sizeof(dat.usr) - 1);
  for (i = 0; i < pt->ni; i++) {
    dat.id = pt->pi[i];
    if ((ir = SearchTableRowX(tb, 0, (FSEL)fselLCK, (uANY)&dat)) >= 0) {
      if (strcmp(((pLCKI)Row(tb, ir))->usr, usr)) { ierr(E_LCK); goto _10;}
      DeleteTableRow0(tb, ir);
    }
  }
  re = TRUE; _10:
  return CloseBTB(tb, re);
}

BOOL LOCALF fselFUN(pLCKI pb, pLCKI pa)
{ // 選択関数
  return !!strcmp(pb->usr, pa->usr);
}

BOOL LOCALF forceunlock(HTBL tb, rSTR usr)
{ // 強制アンロック
  I4B n1, n2;
  LCKI dat;

  if (file_size(tb->imp) == 0) return FALSE;
  if (!OpenBTB(tb)) return FALSE;
  strcpyx(dat.usr, usr, sizeof(dat.usr) - 1);
  n1 = NTableRows(tb);
  n2 = SelectTableRowsX(tb, (FSEL)fselFUN, (uANY)&dat);
  return CloseBTB(tb, n1 > n2);
}

BOOL WINAPI LoginSite(rSTR usr, rSTR pwd)
{ // ログイン
  I4B ir;
  pBSAI pb;

  if (CLEV > 0) { return (BOOL)ierr(E_DUL);}
  hBSA = CreateBSATable( 0, FALSE); if (!hBSA) return FALSE;
  hBSU = CreateBSUTable(32, FALSE); if (!hBSU) goto _20;
  if (!LoadBTB(hBSA)) goto _10;
  ir = srchbsa(hBSA, usr); if (ir < 0) goto _10;
  pb = (pBSAI)Row(hBSA, ir);
  if (_stricmp(pwd, pb->pwd) || pb->lev <= 0) goto _10;
  strcpys(CUSR, pb->usr);
  CLEV = pb->lev;
  loglog(TRUE, CUSR);
  addusr(hBSU, CUSR);
  return TRUE;

 _10: DeleteTable(hBSU);
 _20: DeleteTable(hBSA);
  return FALSE;
}

void WINAPI LogoutSite(void)
{ // ログアウト
  if (CLEV == 0) return;
  DisconnectDB();
  delusr(hBSU, CUSR);
  loglog(FALSE, CUSR);
  DeleteTable(hBSU);
  DeleteTable(hBSA);
  CUSR[0] = '\0';
  CLEV = 0;
}

void WINAPI ForceLogoutSite(rSTR usr)
{ // 強制ログアウト
  I4B i, ln;
  rSTR nam;
  HTBL tb, td, tl;

  if (CLEV < 3) { ierr(E_BSD); return;}
  if (!!(tb = CreateBSDTable(32, PRO_DEF)) && (ln = NTableRows(tb)) > 0) {
    td = CreateBDUTable(32, FALSE); if (!td) goto _20;
    tl = CreateLCKTable(32, FALSE); if (!tl) goto _10;
    for (i = 0; i < ln; i++) {
      nam = ((pBSDI)Row(tb, i))->nam;
      SetTableFileName(td, addext(nam, ".BDU"));
      delusr(td, usr);
      SetTableFileName(tl, addext(nam, ".LCK"));
      forceunlock(tl, usr);
    }
    DeleteTable(tl); _10:
    DeleteTable(td); _20:;
  } else if (CurDBName()[0] != '\0') {
    delusr(hBDU, usr);
    forceunlock(hLCK, usr);
  }
  delusr(hBSU, usr);
  DeleteTable(tb);
}

rSTR WINAPI CurUser(void)
{ // ユーザー名
  return CUSR;
}

I4B  WINAPI CurAuth(void)
{ // 権限
  return CLEV;
}

BOOL WINAPI ConnectDBXX(rBDBI db, FCRE fcre)
{ // ＤＢへ接続
  I4B i, j, f;
  HTBL tx;
  rTBLI ti;
  rCOLI co, cx;

  if (CLEV == 0) { return (BOOL)ierr(E_NOL);}
  if (CDE) { return (BOOL)ierr(E_DUC);}
  if (!db->nam || strlen(db->nam) >= sizeof(CNAM) || !isidn(db->nam)) { return (BOOL)ierr(E_DBN);}
  if (db->tit && strlen(db->tit) >= sizeof(CTIT)) { return (BOOL)ierr(E_DBT);}
  if (db->dsc && strlen(db->dsc) >= sizeof(CDSC)) { return (BOOL)ierr(E_DBD);}
  strcpys(CNAM, db->nam);
  strcpys(CTIT, db->tit? db->tit: db->nam);
  strcpys(CDSC, db->dsc? db->dsc: db->tit);
  CSTA = 2;
  if (!db->ts || !db->ts->ti || db->ts->ni <= 0) { ierr(E_MIS); goto _50;}
  CDE = halloc(db->ts->ni * sizeof(BDBE), TRUE); if (!CDE) { ierr(E_MEM); goto _50;}
  NDE = db->ts->ni;
  hBDU = CreateBDUTable(32, FALSE); if (!hBDU) goto _40;
  hREF = CreateREFTable(32); if (!hREF) goto _30;
  hLCK = CreateLCKTable(32, FALSE); if (!hLCK) goto _20;
  for (i = 0; i < NDE; i++) {
    ti = &db->ts->ti[i];
    if (!ti->nam || strlen(ti->nam) >= 16 || !isidn(ti->nam)) { ierr(E_TBN); goto _10;}
    if (ti->tit && strlen(ti->tit) >= 32) { ierr(E_TBT); goto _10;}
    if (ti->dsc && strlen(ti->dsc) >= 64) { ierr(E_TBD); goto _10;}
    f = 0;
    for (j = 0; j < ti->cs->nc; j++) {
      co = &ti->cs->co[j];
      if (co->flg & CF_REF) {
        if (RTI(co) >= i) { ierr(E_ITB); goto _10;}
        tx = CDE[RTI(co)].tb;
        if (RCI(co) >= tx->cs->nc) { ierr(E_ICO); goto _10;}
        cx = &tx->cs->co[RCI(co)];
        if (colsiz(co) != SIZ(cx) && !ISCAL(co)) { ierr(E_CSZ); goto _10;}
      }
      if (ISCAL(co)) {
        if (co->flg & CF_KEY) { ierr(E_CKY); goto _10;}
        if (co->flg & CF_REF) {
          if (!co->fcal) {
            if (!isref(hREF, i, RTI(co))) { ierr(E_NRF); goto _10;}
          } else {
            setref(hREF, i, RTI(co));
          }
        }
      } else {
        if (co->flg & CF_KEY) { f = 1;}
        if (co->flg & CF_REF) {
          if (!(cx->flg & CF_KEY)) { ierr(E_RKY); goto _10;}
          if (NTableKeys(tx) > 1) { ierr(E_NUN); goto _10;}
          setref(hREF, i, RTI(co));
        }
      }
    }
    if (!f) { ierr(E_NKY); goto _10;}
    CDE[i].tb = fcre(0, ti); if (!CDE[i].tb) goto _10;
    if (!(CDE[i].tb->flg & TF_RDO)) {
      CDE[i].tc = fcre(0, ti); if (!CDE[i].tc) goto _10;
      CDE[i].tx = fcre(0, ti); if (!CDE[i].tx) goto _10;
    }
    CDE[i].vs = ti->vs;
  }
  addusr(hBDU, CUSR);
  return TRUE;

 _10:
  for ( ; i >= 0; i--) {
    DeleteTable(CDE[i].tx);
    DeleteTable(CDE[i].tc);
    DeleteTable(CDE[i].tb);
  }
  DeleteTable(hLCK); _20:
  DeleteTable(hREF); _30:
  DeleteTable(hBDU); _40:
  hfree(CDE); CDE = NULL; NDE = 0; _50:
  CNAM[0] = CTIT[0] = CDSC[0] = '\0';
  CSTA = 0;
  return FALSE;
}

BOOL WINAPI ConnectDBX(rBDBI db)
{ // ＤＢへ接続
  return ConnectDBXX(db, CreateTable);
}

void LOCALF db_fdis0(void)
{ // ダミー
}

static FDIS db_fdis = db_fdis0;

void WINAPI override_db_fdis(FDIS fdis)
{ // 接続解除関数の登録
  db_fdis = fdis;
}

void WINAPI DisconnectDB(void)
{ // ＤＢへの接続解除
  I4B i;

  if (!CDE) return;
  db_fdis();
  if (CSTA > 0) {
    forceunlock(hLCK, CUSR);
    delusr(hBDU, CUSR);
  }
  for (i = NDE-1; i >= 0; i--) {
    DeleteTable(CDE[i].tx);
    DeleteTable(CDE[i].tc);
    DeleteTable(CDE[i].tb);
  }
  DeleteTable(hLCK);
  DeleteTable(hREF);
  DeleteTable(hBDU);
  hfree(CDE); CDE = NULL; NDE = 0;
  CNAM[0] = CTIT[0] = CDSC[0] = '\0';
  CSTA = 0;
}

rSTR WINAPI CurDBName(void)
{ // 現ＤＢ名
  return CNAM;
}

rSTR WINAPI CurDBTitle(void)
{ // 現ＤＢタイトル
  return CTIT;
}

rSTR WINAPI CurDBDescription(void)
{ // 現ＤＢ説明
  return CDSC;
}

I4B  WINAPI CurDBStatus(void)
{ // 現ＤＢ状態
  return CSTA;
}

I4B  WINAPI NDBTables(void)
{ // 現ＤＢに属する表の数
  return NDE;
}

HTBL WINAPI DBTable(I4B id)
{ // 表インデックスから表ハンドルを求める
  if (!CDE) { return ierr(E_NOC);}
  if (id < 0 || id >= NDE) { return ierr(E_ITB);}
  return CDE[id].tb;
}

rSTR WINAPI DBTableName(I4B id)
{ // 表インデックスから表名を求める
  if (!CDE) { ierr(E_NOC); return "";}
  if (id < 0 || id >= NDE) { ierr(E_ITB); return "";}
  return CDE[id].tb->nam;
}

rSTR WINAPI DBTableTitle(I4B id)
{ // 表インデックスから表タイトルを求める
  if (!CDE) { ierr(E_NOC); return "";}
  if (id < 0 || id >= NDE) { ierr(E_ITB); return "";}
  return CDE[id].tb->tit;
}

rSTR WINAPI DBTableDescription(I4B id)
{ // 表インデックスから表説明を求める
  if (!CDE) { ierr(E_NOC); return "";}
  if (id < 0 || id >= NDE) { ierr(E_ITB); return "";}
  return CDE[id].tb->dsc;
}

rSTR WINAPI DBTableFileName(I4B id)
{ // 表インデックスから表ファイル名を求める
  if (!CDE) { ierr(E_NOC); return "";}
  if (id < 0 || id >= NDE) { ierr(E_ITB); return "";}
  return CDE[id].tb->imp;
}

pVIWS WINAPI DBTableVIWS(I4B id)
{ // 表インデックスからシステム定義のビューセットを求める
  if (!CDE) { return ierr(E_NOC);}
  if (id < 0 || id >= NDE) { return ierr(E_ITB);}
  return CDE[id].vs;
}

I4B  WINAPI DBTableIndex(rSTR nam)
{ // 表名から表インデックスを求める
  I4B i;

  if (!CDE) return -1;
  for (i = 0; i < NDE; i++) {
    if (!_stricmp(CDE[i].tb->nam, nam)) { return i;}
  }
  return -1;
}

HTBL WINAPI DBHTBL(rSTR nam)
{ // 表名から表ハンドルを求める
  I4B i;

  if (!CDE) { return ierr(E_NOC);}
  for (i = 0; i < NDE; i++) {
    if (!_stricmp(CDE[i].tb->nam, nam)) { return CDE[i].tb;}
  }
  return ierr(E_TBN);
}

  // 表オープン情報(単独)
typedef struct {
  I4B   md;
  pBDBE de;
} OPNI;
typedef OPNI *pOPNI;

HOPN LOCALF OpenTableI(pBDBE de, BOOL rw)
{ // 表を開く(単独)
  pOPNI op;

  op = halloc(sizeof(OPNI), FALSE); if (!op) { return ierr(E_MEM);}
  if (rw) {
    if (de->rw) { ierr(E_ORW); goto _10;}
    new_file_if_not_exists(de->tb->imp);
    if (!LoadBTB(de->tb)) goto _10;
    de->tc = DuplicateTable(de->tb); if (!de->tc) goto _10;
    de->rw = TRUE;
    op->md = (OM_IND|OM_RDW);
  } else {
    if (!de->rw) {
      if (!LoadBTB(de->tb)) goto _10;
    }
    op->md = (OM_IND|OM_RDO);
  }
  op->de = de;
  return (HOPN)op;

 _10:
  hfree(op);
  return NULL;
}

HOPN WINAPI CreateHOPN(HTBL tb, BOOL rw)
{ // 表オープン情報作成
  pOPNI op;
  pBDBE de;

  op = halloc(sizeof(OPNI) + sizeof(BDBE), FALSE); if (!op) { ierr(E_MEM);}
  de = (pANY)((pBIN)op + sizeof(OPNI));
  de->tb = tb;
  de->tx = NULL;
  if (rw) {
    de->tc = DuplicateTable(de->tb); if (!de->tc) { hfree(op); return NULL;}
    de->rw = TRUE;
    op->md = (OM_IND|OM_RDW);
  } else {
    de->tc = NULL;
    de->rw = FALSE;
    op->md = (OM_IND|OM_RDO);
  }
  op->de = de;
  return (HOPN)op;
}

HOPN WINAPI OpenBSATable(BOOL rw)
{ // ユーザー管理表を開く
  if (CLEV == 0) { return ierr(E_NOL);}
  if (CLEV < 4)  { return ierr(E_BSA);}
  return OpenTableI(&deBSA, rw);
}

  // 表オープン情報
typedef struct {
  I4B   md;
  pIDXS pt;
  pIDXS pr;
} OPNE;
typedef OPNE *pOPNE;

HOPN WINAPI OpenTableX(rIDXS pt, I4B md)
{ // 表を開く
  I4B i, j, i1, i2;
  pOPNE op;
  pIDXS pw, pr;

  if (!CDE) { return ierr(E_NOC);}
  switch (md) {
  case OM_RDO: case OM_RDW: case OM_LCK: case OM_RDO|OM_LCK: case OM_RDW|OM_LCK: break;
  default: return ierr(E_PAR);
  }
  if (CLEV < 2 && (md & (OM_RDW|OM_LCK))) { return ierr(E_RDW);}
  if (md & OM_RDW) {
    for (i = 0; i < pt->ni; i++) {
      if (CDE[pt->pi[i]].tb->flg & TF_RDO) { return ierr(E_ORO);}
      if (CDE[pt->pi[i]].rw) { return ierr(E_ORW);}
    }
  }
  op = halloc(sizeof(OPNE) + 2 * sizeof(IDXS) + NDE * sizeof(P4B), FALSE); if (!op) { return ierr(E_MEM);}
  pw = (pANY)((pBIN)op + sizeof(OPNE));
  pr = (pANY)((pBIN)pw + sizeof(IDXS));
  pw->pi = (pANY)((pBIN)pr + sizeof(IDXS));
  memcpy(pw->pi, pt->pi, pt->ni * sizeof(P4B));
  pw->ni = pt->ni;
  pr->pi = pw->pi + pw->ni;
  pr->ni = 0;
  op->md = md;
  op->pt = pw;
  op->pr = pr;
  if (md & (OM_RDO|OM_RDW)) {
    for (i = 0; i < pt->ni; i++) {
      i1 = pt->pi[i];
      for (i2 = 0; i2 < NDE; i2++) {
        if (i1 != i2 && isref(hREF, i1, i2)) {
          for (j = 0; j < pw->ni + pr->ni; j++) {
            if (pw->pi[j] == i2) goto _10;
          }
          pr->pi[pr->ni++] = i2;
        }
       _10:;
      }
    }
  }
  if (md & (OM_RDW|OM_LCK)) {
    if (!lock(hLCK, CUSR, pw)) goto _50;
  }
  if (md & OM_RDW) {
    for (i = 0; i < pw->ni; i++) {
      if (!LoadBTB(CDE[pw->pi[i]].tb)) goto _20;
      CDE[pw->pi[i]].rw = TRUE;
      CopyTable(CDE[pw->pi[i]].tc, CDE[pw->pi[i]].tb);
    }
    for (i = 0; i < pr->ni; i++) {
      if (CDE[pr->pi[i]].rw) continue;
      if (!LoadBTB(CDE[pr->pi[i]].tb)) goto _30;
    }
  } else if (md & OM_RDO) {
    for (i = 0; i < pw->ni + pr->ni; i++) {
      if (!LoadBTB(CDE[pw->pi[i]].tb)) goto _40;
    }
  }
  if ((md & (OM_RDW|OM_LCK)) == OM_RDW) { unlock(hLCK, CUSR, pw);}
  return (HOPN)op;

 _20:
  for ( ; i >= 0; i--) {
    CDE[pw->pi[i]].rw = FALSE;
  }
  goto _40;
 _30:
  for (i = 0; i < pw->ni; i++) {
    CDE[pw->pi[i]].rw = FALSE;
  }
 _40:
  if (md & (OM_RDW|OM_LCK)) { unlock(hLCK, CUSR, pw);}
 _50:
  hfree(op);
  return NULL;
}

BOOL LOCALF scntbs(pIDXS pt, rSTR st)
{ // 表名リスト読込
  I4B i, n, id;

  n = 0;
  start(st);
  switch (token()) {
  case TKN_END:
  case BOP_AST:
    for (i = 0; i < NDE; i++) {
      pt->pi[n++] = i;
    }
    break;
  case TKN_IDN:
    goto _20;
  }
  goto _40;
 _10:
  if (token_is(TKN_IDN)) {
   _20:
    if ((id = DBTableIndex(buf())) >= 0) {
      for (i = 0; i < n; i++) {
        if (pt->pi[i] == id) goto _30;
      }
      pt->pi[n++] = id;
    }
   _30:
    if (token_is(BOP_CMA)) goto _10;
  }
 _40:
  pt->ni = n;
  return n > 0;
}

HOPN WINAPI OpenTable(rSTR tbs, I4B md)
{ // 表を開く
  HOPN op;
  pIDXS pt;

  pt = halloc(sizeof(IDXS) + NDE * sizeof(P4B), FALSE); if (!pt) { return ierr(E_MEM);}
  pt->pi = (pANY)((pBIN)pt + sizeof(IDXS));
  scntbs(pt, tbs); if (pt->ni <= 0) { hfree(pt); return ierr(E_TBN);}
  op = OpenTableX(pt, md);
  hfree(pt);
  return op;
}

BOOL WINAPI SaveTable(HOPN op)
{ // 表の保存
  I4B i, md = ((pOPNE)op)->md, re = FALSE;
  pIDXS pw;
  HTBL d1, d2;

  if (md & OM_RDO) return FALSE;
  if (md & OM_IND) {
    re = SaveBTB(((pOPNI)op)->de->tb);
    if (re) { CopyTable(((pOPNI)op)->de->tc, ((pOPNI)op)->de->tb);}
    return re;
  }
  pw = ((pOPNE)op)->pt;
  if ((md & (OM_RDW|OM_LCK)) == OM_RDW) { lock(hLCK, CUSR, pw);}
  for (i = 0; i < pw->ni; i++) {
    d1 = CreateDIFTable(CDE[pw->pi[i]].tb, CDE[pw->pi[i]].tc); if (!d1) goto _00;
    re = LoadBTB(CDE[pw->pi[i]].tx); if (!re) goto _20;
    d2 = CreateDIFTable(CDE[pw->pi[i]].tx, CDE[pw->pi[i]].tc); if (!d2) goto _20;
    if (NTableRows(d2) > 0) {
      if (IsConflict(d1, d2)) { re = (BOOL)ierr(E_CNF); goto _10;}
      MergeDIFTable(CDE[pw->pi[i]].tb, d2);
    }
    DIFTableTrigger(CDE[pw->pi[i]].tb, CDE[pw->pi[i]].tc, d1);
    re = SaveBTB(CDE[pw->pi[i]].tb); if (!re) goto _10;
    DeleteTable(d2);
    DeleteTable(d1);
    CopyTable(CDE[pw->pi[i]].tc, CDE[pw->pi[i]].tb);
  }
 _00:
  if ((md & (OM_RDW|OM_LCK)) == OM_RDW) { unlock(hLCK, CUSR, pw);}
  return re;

 _10: DeleteTable(d2);
 _20: DeleteTable(d1);
  goto _00;
}

BOOL WINAPI CloseTable(HOPN op, BOOL sv)
{ // 表を閉じる
  I4B i, md, re;
  pIDXS pw;

  if (!op) return FALSE;
  re = sv? SaveTable(op): TRUE;
  md = ((pOPNE)op)->md;
  if (md & OM_IND) {
    if (md & OM_RDW) {
      ((pOPNI)op)->de->rw = FALSE;
      DeleteTable(((pOPNI)op)->de->tc);
    }
    hfree(op);
    return re;
  }
  pw = ((pOPNE)op)->pt;
  if (md & OM_RDW) {
    for (i = 0; i < pw->ni; i++) {
      CDE[pw->pi[i]].rw = FALSE;
    }
  }
  if (md & OM_LCK) { unlock(hLCK, CUSR, pw);}
  hfree(op);
  return re;
}

HTBL WINAPI OHTBL(HOPN op)
{ // 開いた表
  if (((pOPNE)op)->md & OM_IND) { return ((pOPNI)op)->de->tb;}
  return CDE[((pOPNE)op)->pt->pi[0]].tb;
}

I4B  WINAPI NOTables(HOPN op)
{ // 開いた表の数
  if (((pOPNE)op)->md & OM_IND) { return 1;}
  return ((pOPNE)op)->pt->ni + ((pOPNE)op)->pr->ni;
}

HTBL WINAPI OTable(HOPN op, I4B i)
{ // 開いた表のi番目
  if (((pOPNE)op)->md & OM_IND) { return (i == 0)? ((pOPNI)op)->de->tb: ierr(E_PAR);}
  if (i < 0 && i >= ((pOPNE)op)->pt->ni + ((pOPNE)op)->pr->ni) { return ierr(E_PAR);}
  return CDE[((pOPNE)op)->pt->pi[i]].tb;
}

BOOL WINAPI IsReadOnly(HOPN op)
{ // 読取専用
  return (((pOPNE)op)->md & OM_RDO) != 0;
}

BOOL WINAPI IsLocked(HOPN op)
{ // ロック中
  return (((pOPNE)op)->md & OM_LCK) != 0;
}

BOOL WINAPI IsModified(HOPN op)
{ // 表が更新されている
  I4B i, md = ((pOPNE)op)->md;
  pIDXS pw;

  if (!(md & OM_RDW)) return FALSE;
  if (md & OM_IND) { return !!CompareTable(((pOPNI)op)->de->tb, ((pOPNI)op)->de->tc);}
  pw = ((pOPNE)op)->pt;
  for (i = 0; i < pw->ni; i++) {
    if (CompareTable(CDE[pw->pi[i]].tb, CDE[pw->pi[i]].tc)) return TRUE;
  }
  return FALSE;
}

BOOL WINAPI NewDBFiles(void)
{ // 空の表ファイル作成
  I4B i;

  if (CLEV < 3) { return (BOOL)ierr(E_BSD);}
  if (!CDE) { return (BOOL)ierr(E_NOC);}
  for (i = 0; i < NDE; i++) {
    new_file_if_not_exists(DBTableFileName(i));
  }
  return TRUE;
}

BOOL WINAPI BackupDBFiles(rSTR dir)
{ // 現ＤＢに属するファイルの一括コピー
  I4B i, re = TRUE;

  if (CLEV < 3) { return (BOOL)ierr(E_BSD);}
  if (!CDE) { return (BOOL)ierr(E_NOC);}
  if (!new_path_if_not_exists(dir)) { return (BOOL)ierr(E_DIR);}
  for (i = 0; i < NDE; i++) {
    re &= copy_file_to(dir, DBTableFileName(i));
  }
  re &= copy_file_to(dir, addext(CNAM, EXT_DEF));
  return re;
}

BOOL WINAPI TrashDBFiles(rSTR dir)
{ // 現ＤＢに属するファイルの一括移動
  I4B i, re = TRUE;

  if (CLEV < 3) { return (BOOL)ierr(E_BSD);}
  if (!CDE) { return (BOOL)ierr(E_NOC);}
  if (!new_path_if_not_exists(dir)) { return (BOOL)ierr(E_DIR);}
  for (i = 0; i < NDE; i++) {
    if (TableFlags(DBTable(i)) & TF_IMP) continue;
    re &= move_file_to(dir, DBTableFileName(i));
  }
  re &= move_file_to(dir, addext(CNAM, EXT_DEF));
  move_file_to(dir, addext(CNAM, ".BDU"));
  move_file_to(dir, addext(CNAM, ".LCK"));
  return re;
}

//――――――――――――――――――――――――――――――――――――――//

U4B  WINAPI BOLDBEVer(void)
{ // バージョン情報
  return MODVER;
}

static HLEX BLE;

BOOL WINAPI InitBOLDBE(uANY pa)
{ // 開始処理
  register_error_descriptions(&emDBE);
  BLE = CreateParsEnv(&xiBOL);
  SelectParsEnv(BLE);
  RegisterColumnType(&tpICO);
  RegisterColumnType(&tpLOP);
  RegisterColumnType(&tpFMT);
  CYMD = today();
  return TRUE;
}

void WINAPI TermBOLDBE(void)
{ // 終了処理
  DeleteParsEnv(BLE);
}

//――――――――――――――――――――――――――――――――――――――//
