/* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/

	【機能概要】	: C言語アプリ用・共有メモリアクセスSR
					  実際の共有メモリアクセスの実装は GG_SHM0011 であり、本アプリは
					  取得データの成形を行う部分を実装している

	【作成日】		: 2021.04.23

	【呼出形式】	: GG_SHM0111 (
						  int outNum[3]						# 行数（Title行含） / 列数 / カラム長を返却
						, int inNum							# 入力パラメータ数を入力
						, char in[][GG_SHM0001_MaxPrmLen]	# 各パラメータを入力（パラメータ例は以下）
															# テーブルID / 検索ID / key1 / value1 / key2 / value2 ･･･
					  )
	【戻り値】		: char***								# 1行目:項目名称
															# 2行目以降:データ値

_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */

#include <string.h>

#include <stdio.h>
#include <ctype.h>
#include <limits.h>
#include <unistd.h>
#include <sys/syscall.h>

#ifndef WIN32
#include <pthread.h>
#else
#include <windows.h>
#endif

#include "GG_SHMCOM.h"

// 0:共有メモリモード, 1:ファイル入力モード
static	int sharedMode = 0;

#ifdef _NONSTOP
#define SYS_gettid 2
int syscall(int id);
#endif

char ***GG_SHM0111_getSharedMemory ( int outNum[3] , int inNum , char in[][GG_SHM0001_MaxPrmLen] ) ;
char ***GG_SHM0111_getFileData ( int outNum[3] , int inNum , char in[][GG_SHM0001_MaxPrmLen] ) ;
int  GG_SHM0011_logic ( int prmNum , char Prm[][GG_SHM0001_MaxPrmLen] ) ;
void GG_SHM0011_getData    ( char *arrOut ) ;

/* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
	共有メモリ検索メイン（C言語版）
	各処理振り分けとデータ返却を実装
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */

char ***GG_SHM0111 ( int outNum[3] , int inNum , char in[][GG_SHM0001_MaxPrmLen]) {

	// 戻り用　件数・列数・最大項目長の初期化
	outNum[0] = 0 ;
	outNum[1] = 0 ;
	outNum[2] = 0 ;

	// 共有メモリモード判定（0:共有メモリからデータ取得、1:ファイルからデータ取得）
	char *c_env = getenv ( "GG_SHM_TBLDEF" ) ;
	if ( c_env == NULL ) {
		sharedMode = 0 ;
	} else {
		c_env = getenv ( "GG_SHM_SHAREDMODE" ) ;
		if ( c_env != NULL ) {
			sharedMode = atoi ( c_env ) ;
		}
	}

	if (sharedMode == 0) {
		return (GG_SHM0111_getSharedMemory( outNum , inNum, in ));
	}
	else {
		return (GG_SHM0111_getFileData( outNum , inNum, in ));
	}
}

/* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
	ファイル検索モードは未実装
	全て、NULL（データ検索失敗）を返却
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */

char ***GG_SHM0111_getFileData ( int outNum[3] , int inNum , char in[][GG_SHM0001_MaxPrmLen] ) {
	return ( NULL ) ;
}

/* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
	共有メモリ検索モード（主な処理は下記の通り）
	1. ログ出力場所決定
	2. 共有メモリ検索処理の呼び出し
	3. 共有メモリデータ取得処理の呼び出し
	4. 返却データ領域の作成
	5. 返却データの設定と返却
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */

char ***GG_SHM0111_getSharedMemory ( int outNum[3] , int inNum , char in[][GG_SHM0001_MaxPrmLen] ) {

	char    szLogFileTmpPath [ MAX_PATH ] ;			// XMLファイル名
	char    g_szLogFilePath  [ MAX_PATH ] ;			// ログファイル名
	char    szAccessDate [ 30 ] ;					// YYYY-MM-DD HH:MM:SS.mmmmmm

	int		ThreadId = (int)syscall(SYS_gettid) ;

	// ログ出力場所の決定
	getEnvString ( szLogFileTmpPath , "GG_LogFileSHM0111"
		, GG_SHM0011_LOGPATH , sizeof(szLogFileTmpPath) );
	getLocalTimeString ( g_szLogFilePath , sizeof(g_szLogFilePath) , szLogFileTmpPath ) ;

	/* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		共有メモリ検索処理
		本処理(StcTbl.GG_SHM0011)では、業務APが設定したパラメータに従って共有
		メモリ検索を行い、C言語中に検索結果を一時格納し、データサイズを返却
 	_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */

	int dataSize = GG_SHM0011_logic ( inNum , in ) ;

 	/* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		検索データ取得処理（返却データ無しの場合） GG_SHM0011_logic（C言語）中の
		内部バッファクリアのために呼び出しが必要
	_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */

	if (dataSize <= 0) {
		if (dataSize <= 0 && dataSize > -10) {
			char outBt = '\0' ;
			GG_SHM0011_getData ( &outBt ) ;
		}
		char errorMsg[256] ;
		if (dataSize == -1) {
			sprintf ( errorMsg , "テーブルID不正エラー (%d)" , dataSize ) ;
		} else
		if (dataSize == -2) {
			sprintf ( errorMsg , "アクセスパターン名不正エラー (%d)" , dataSize ) ;
		} else
		if (dataSize == -3) {
			sprintf ( errorMsg , "数値比較項目に数字以外が設定された (%d)" , dataSize ) ;
		} else
		if (dataSize == -4) {
			sprintf ( errorMsg , "検索項目名不正エラー (%d)" , dataSize ) ;
		} else
		if (dataSize == -5) {
			sprintf ( errorMsg , "比較演算子不正エラー（内部エラー） (%d)" , dataSize ) ;
		} else
		if (dataSize == -6) {
			sprintf ( errorMsg , "メモリ確保エラー（内部エラー） (%d)" , dataSize ) ;
		} else
		if (dataSize == -10) {
			sprintf ( errorMsg , "共有メモリ取得エラー (%d)" , dataSize ) ;
		} else
		if (dataSize == -11) {
			sprintf ( errorMsg , "初期化スレッド失敗（内部エラー） (%d)" , dataSize ) ;
		} else
		if (dataSize == -12) {
			sprintf ( errorMsg , "テーブルID不正エラー (%d)" , dataSize ) ;
		} else
		if (dataSize == -13) {
			sprintf ( errorMsg , "共有メモリ論理エラー（内部エラー） (%d)" , dataSize ) ;
		} else
		{
			sprintf ( errorMsg , "論理エラー (%d)" , dataSize ) ;
		}
		getLocalTimeString ( szAccessDate , sizeof(szAccessDate), "%Y/%m/%d %H:%M:%S.%U" ) ;
		GG_MsgOut ( g_szLogFilePath , 9
			, "(%05d) **** ( %s ) **** %s"
			, ThreadId , szAccessDate , errorMsg ) ;
		return ((char ***)NULL);
	}

	char *outBt = (char *)malloc ( dataSize + 1 ) ;
	outBt[0] = '\n' ;

	/* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		検索データ取得処理
		本処理(StcTbl.GG_SHM0011getData)では、前処理(StcTbl.GG_SHM0011)から返却さ れたデータ長の
		バッファ(outBt)を用意し、そのバッファに検索データを返却する。
		(バッファ長の圧縮による性能向上が目的)
	_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */

	GG_SHM0011_getData ( outBt ) ;
	outBt[dataSize] = '\0' ;

//	printf ("dataSize=%d outBt=[%s]\n",dataSize,outBt) ;

	/* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		返却データ領域確保・列数/カラム数/カラム長の検査
		返却データ内の[\t][\n]から、列数/カラム数/カラム長を検査する
	_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */

	int colnum = 1 , colsz = 0 , rownum = 0 ;
	char *ln = strchr ( outBt , '\n' ) ;
	for ( int i=0 ; i<(ln-outBt) ; i++ ) {
		if ( outBt[i] == '\t' ) colnum ++ ;
	}
	for ( int i=0 ,j=0 ; i<dataSize ; i++ ) {
		if ( outBt[i] == '\n' ) rownum ++ ;
		if ( outBt[i] == '\t' || outBt[i] == '\n' ) {
			if ( colsz < (i-j) ) colsz = i-j ;
			j = i + 1 ;
		}
	}
	colsz ++ ;

	/* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		返却データ領域確保・配列情報の設定
		列数/カラム数/カラム長の検査結果から、返却データ領域の確保と配列情報の
		設定を行う
	_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */

	char ***a, **b, *c;
	int t = sizeof(char) * colsz ;
	a = (char***)malloc((sizeof(*a) + sizeof(**a) * colnum + t * colnum) * rownum);
	if(a != NULL) {
		b = (char**)(a + rownum);
		c = (char*)(b + rownum * colnum);
		for(int idx1 = 0; idx1 < rownum; idx1++){
			a[idx1] = b;
			for(int idx2 = 0; idx2 < colnum; idx2++){
				b[idx2] = c;
				c += t;
			}
			b += colnum;
		}
		getLocalTimeString ( szAccessDate,sizeof(szAccessDate),"%Y/%m/%d %H:%M:%S.%U" ) ;
		GG_MsgOut ( g_szLogFilePath , 9
				, "**** ( %s ) **** GG_SHM1200 GG_SHM1200_malloc 2 pStructData=[%x]"
				, szAccessDate,a ) ;
	}

	/* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		返却データの設定
		返却データ領域にデータの設定を行う。
		また、削除部分（0x1F）の削除を行う。
		 ※ 各行/カラムを内部では固定長化するため、0x1Fデータが埋め込まれている
			が、利用者（上位アプリ）には不要なデータのため削除する
	_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */

	for(int idx1 = 0 , i=0 , j=0 ; idx1 < rownum; idx1++){
		for(int idx2 = 0; idx2 < colnum; idx2++){
			for ( ; outBt[i] != '\t' && outBt[i] != '\n' ; i++ ) {}
			if ( i > j ) {
				int k=j ;
				for ( ; k<i ; k++) {
					if ( outBt[k] == SP_REP ) break ;
				}
				memcpy ( a[idx1][idx2] , outBt+j , (k-j) ) ;
				a[idx1][idx2][k-j] = '\0' ;
//				printf ( "a[%d][%d]=%s\n",idx1,idx2,a[idx1][idx2]) ;
			} else {
				a[idx1][idx2][0] = '\0' ;
			}
			i ++ ;
			j = i ;
		}
	}
	free ( outBt ) ;
	outNum[0] = rownum ;
	outNum[1] = colnum ;
	outNum[2] = colsz ;
//	printf ( "rownum=%d colnum=%d colsz=%d\n",rownum,colnum,colsz) ;
	
	return (a) ;
}

#ifdef _NONSTOP
/* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
    NonStop用syscall
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */
int syscall(int id)
{
	pthread_t	tid;
	tid = pthread_self();

	// tidの内容
	// tid.field1=134263616
	// tid.field2=4   ←  スレッドからアクセスされた場合、field2が増加する。
	// tid.field3=4
	
	return (tid).field2;
}
#endif
