ユーザ組み込み関数の機能を,C言語の出口関数中に記述します。
C言語の出口関数の仕様を次に示します。
#include "ETexit.h"
long userfunc (long lArgNum, EXITARG *ppInArg[],
EXITARG *pOutArg )
注:出口関数名(userfunc部分)には任意の名前を指定します。
ユーザ組み込み関数を使用した場合,トランスレータは,システム情報ファイル「ettrans.ini」の定義に従って対応する出口関数を呼び出します。
lArgNumが0の場合は,ppInArgにNULLが設定されます。
typedef struct {
long lType;
ETEXITDATA data;
} ETEXITARG;
typedef union {
long lNumber;
double dNumber;
void *pPtr;
ETEXITDATASTRING edstring;
ETEXITDATASTREAM edstream;
ETEXITDATADTM eddtm;
ETEXITDATAENVSTRING edenvstring;
} ETEXITDATA;
typedef struct {
long lCode;
long lLength;
char *pszString;
} ETEXITDATASTRING;
typedef struct {
long lLength;
char *psStream;
} ETEXITDATASTREAM;
typedef struct {
long lYear; /* year */
long lMonth; /* month */
long lDay; /* day */
long lHour; /* hour */
long lMinute; /* minute */
double dSecond; /* second */
char *pszZone; /* zone string */
} ETEXITDATADTM;
typedef struct {
long lErrCode;
long lCode;
char *pszString;
} ETEXITDATAENVSTRING;
表11-3 ETEXITDATAENVSTRING構造体のメンバの内容
項番 | lErrCode | 文字コード変換結果 | lCode | pszString |
---|---|---|---|---|
1 | 0 | 変換に成功した※1 | 実行環境のロケールに従った文字コード | 実行環境のロケールに従った文字コードのNULL終端文字列です。 |
2 | 0x01000001 | 変換時に不正文字コードを検出した※2 | 実行環境のロケールに従った文字コード | 実行環境のロケールに従った文字コードのNULL終端文字列で,検出した不正文字コードをスペース文字へ置換したものです。 |
3 | -1 | 変換に失敗した | ユーザ組み込み関数に渡された文字列の文字コード | ユーザ組み込み関数に渡された文字列に終端NULLを付加したものです。 |
システム情報ファイルの[Userfunc_Option]セクションでUSE02IFオプションが指定されている場合,引数ppInArgの末尾にET_PTR型の情報を追加して渡します。ここにはETtrans2Exec関数で指定されたポインタを格納します。指定がない又はバージョン1の互換APIを使用している場合は,NULLが設定されます。また,lArgNumの値はシステム情報ファイルで定義した入力パラメタ数+1となります。
USE02IFオプションが指定されていない場合は,ET_PTR型のデータは追加設定しません。
pOutArgのデータは初期化された状態で出口関数に渡されます。ETEXITARG構造体のlTypeには,組み込み関数の戻り値型に対応した値があらかじめ設定されます。また,ETEXITDATA構造体のlNumber,dNumber,ETEXTITDATADTMのlYear~dSecondは,それぞれ0で初期化されます。
戻り値の型が文字列型の場合のpszString,バイト列型の場合のpsStream,日付時刻型の場合のpszZoneには,2,000バイト分確保したメモリのアドレスが設定されます。2,000バイトの領域は0で初期化されます。文字列,バイト列,日付時刻型のゾーン文字列を出力する場合は,出口関数内で2,000バイトに収まるようにデータを設定する必要があります。ゾーン文字列には終端NULLを付けてください。
異常終了時の戻り値(0以外の値)は出口関数内で任意に設定してかまいません。負の値を返した場合,トランスレータは変換処理を中止します。正の値を返した場合,トランスレータは変換処理を続行します。続行する場合,pOutArgとして出口関数からトランスレータに渡す値はリターン時のものになるので注意してください。エラー発生時の戻り値は,トランスレータのログとして出力されます。
C言語の出口関数の実装例を,整数型の場合,実数型で可変個引数の場合,文字列型の場合,日付時刻型の場合,及びUSE02IFオプションを使用した場合に分けて次に示します。
/*
* usermod.c - 整数型ユーザ出口関数の実装例
*/
#include <stdlib.h>
#include "ETexit.h"
long usermod(long lArgNum, ETEXITARG *ppInArg[],
ETEXITARG *pOutArg)
{
/* 余剰を求める */
long lArg1, lArg2;
if (lArgNum != 2 || ppInArg == NULL) return -1;
if (ppInArg[0] == NULL || ppInArg[0]->lType != ET_INT) return -2;
if (ppInArg[1] == NULL || ppInArg[1]->lType != ET_INT) return -2;
lArg1 = ppInArg[0]->data.lNumber;
lArg2 = ppInArg[1]->data.lNumber;
if (lArg2 == 0) return -3;
pOutArg->data.lNumber = lArg1 % lArg2;
return 0;
}
/*
* useraverage.c : 実数型可変個引数ユーザ関数の実装例
*/
#include <stdlib.h>
#include "ETexit.h"
long useraverage(long lArgNum, ETEXITARG *ppInArg[],
ETEXITARG *pOutArg)
{
/* 平均値を求める */
double dTotal = 0.0;
int i;
if (lArgNum < 1 || ppInArg == NULL) return -1;
for ( i = 0; i < lArgNum; i++){
if (ppInArg[i] == NULL || ppInArg[i]->lType != ET_REAL)
return -2;
dTotal += ppInArg[i]->data.dNumber;
}
pOutArg->data.dNumber = dTotal/(double)lArgNum;
return 0;
}
/*
* userisspace.c : 文字列型ユーザ関数の実装例
*/
#include <stdlib.h>
#include <string.h>
#include "ETexit.h"
long userisspace(long lArgNum, ETEXITARG *ppInArg[],
ETEXITARG *pOutArg)
{
/* 文字列中のスペースをチェックする */
ETEXITDATASTRING *peds1, *peds2;
long i;
if (lArgNum != 1 || ppInArg == NULL) return -1;
if (ppInArg[0] == NULL || ppInArg[0]->lType != ET_STRING)
return -2;
peds1 = &ppInArg[0]->data.edstring;
if (peds1->lLength >= 2000) return -3;
if (peds1->lCode != ETEXIT_CODE_SJIS) return -4;
peds2 = &pOutArg->data.edstring;
for (i = 0; i < peds1->lLength; i++) {
if (peds1->pszString[i] != ' ') break;
}
if (i < peds1->lLength){
strncpy(peds2->pszString, peds1->pszString, peds1->lLength);
peds2->pszString[peds1->lLength] = '¥0';
} else {
strcpy(peds2->pszString, "(space)");
}
peds2->lLength = strlen(peds2->pszString);
peds2->lCode = ETEXIT_CODE_SJIS;
return 0;
}
/*
* userdtm.c : 日付時刻型ユーザ関数の実装例
*/
#include <stdlib.h>
#include <string.h>
#include "ETexit.h"
long userdtm(long lArgNum, ETEXITARG *ppInArg[], ETEXITARG *pOutArg)
{
/* 特定の日時を設定する */
pOutArg->data.eddtm.lYear = 2002;
pOutArg->data.eddtm.lMonth = 2;
pOutArg->data.eddtm.lDay = 15;
pOutArg->data.eddtm.lHour = 12;
pOutArg->data.eddtm.lMinute = 0;
pOutArg->data.eddtm.dSecond = 0.0;
strcpy(pOutArg->data.eddtm.pszZone, "+09:30");
return 0;
}
/*
* userPrintEnvstring.c : 実行環境文字コード文字列型とAPIからのポインタを使用したユーザ関数の実装例
*/
#include <string.h>
#include <stdio.h>
#include "ETexit.h"
/* 実行環境文字コード型引数で受け取った文字列を,APIから渡されたファイルに書き込む関数 */
long userPrintEnvstring(long lArgNum, ETEXITARG *ppInArg[],
ETEXITARG *pOutArg)
{
ETEXITDATAENVSTRING *pEdEnvstr = NULL;
ETEXITDATASTRING *peds = NULL;
const char *cszFile = NULL;
FILE *fp = NULL;
if (lArgNum != 2 || ppInArg == NULL) return -1;
if (ppInArg[0] == NULL || ppInArg[0]->lType != ET_ENVSTRING)
return -2;
if (ppInArg[1] == NULL || ppInArg[1]->lType != ET_PTR) return -3;
pEdEnvstr = &ppInArg[0]->data.edenvstring;
if (pEdEnvstr == NULL || pEdEnvstr->lErrCode == -1) return -4;
else {
/* 実行環境の文字コードは SJISを仮定 */
if (pEdEnvstr->lCode != ETEXIT_CODE_SJIS) return -5;
}
/* APIから渡されたファイル名を取り出す */
cszFile = (const char *)ppInArg[1]->data.pPtr;
if (!cszFile) return -6;
/* ファイルに引数で受け取った文字列を書き込む */
fp = fopen(cszFile, "w");
if (!fp) return -7;
fprintf(fp, "%s", pEdEnvstr->pszString);
if (fp) fclose(fp);
/* ユーザ組み込み関数の戻り値には引数の文字列をそのまま渡す */
peds = &pOutArg->data.edstring;
strcpy(peds->pszString, pEdEnvstr->pszString);
peds->lLength = strlen(peds->pszString);
peds->lCode = ETEXIT_CODE_SJIS;
return 0;
}