/*
 * DBApp : 
 *
 * 1998/05/02:Eiichiroh Itoh
 *  (1) 作成開始
 * 修正履歴
 * 1998/09/17:Eiichiroh Itoh
 *  (1) initdb.iniの形式に変更した
 * 1999/02/02:Eiichiroh Itoh
 *  (1) BLOBのインポートに対応した
 *
 */
#include	"conslib.h"
#include	<tchar.h>
#include	<windbase.h>
#include	"kctrl.h"
#include	"tools.h"

#define		MAX_SORTORDER		4

TCHAR			AppName[] = TEXT("DBApp") ;	/* 必須項目 */
DWORD			AppVersion = 6 ;
TCHAR			MessageBuf[ 256 ] ;
TCHAR			g_szDBName[ MAX_PATH ] ;
PEGOID			g_oidDatabase ;
HANDLE			g_hDatabase ;
PEGPROPVAL		g_propVal[ 100 ] ;
DWORD			g_dwNumProp = 0 ;
TCHAR			g_propStr[ 1024 ] ;
LPTSTR			g_propCur ;
DWORD			g_dwArgc ;
LPTSTR			g_pArgv[ 128 ] ;
CHAR			g_szSjis[ 1024 ] ;
TCHAR			g_szUnicode[ 1024 ] ;
SORTORDERSPEC	g_pSortOrder[ MAX_SORTORDER ] ;
DWORD			g_dwNumSortOrder = 0 ;
BOOL			g_bContinue = FALSE ;
PEGBLOB			*g_blobVal = NULL ;

DWORD
xatol( LPCTSTR str )
{
	TCHAR	c ;
	DWORD	result = 0 ;

	while ( c = *str++ ) {
		if ( c >= TEXT('0') && c <= TEXT('9') ) {
			c -= '0' ;
		} else if ( c >= TEXT('a') && c <= TEXT('f') ) {
			c = c - TEXT('a') + 10 ;
		} else if ( c >= TEXT('A') && c <= TEXT('F') ) {
			c = c - TEXT('A') + 10 ;
		} else {
			break ;
		}
		result <<= 4 ;
		result += (DWORD) (c & 0x0F) ;
	}
	return result ;
}

void
cut_crlf( LPTSTR buf )
{
	LPTSTR	ptr ;

	ptr = _tcschr( buf, TEXT('\r') ) ;
	if ( ptr ) {
		*ptr = 0 ;
	}
	ptr = _tcschr( buf, TEXT('\n') ) ;
	if ( ptr ) {
		*ptr = 0 ;
	}
}

void
rtrim( LPTSTR dst )
{
	TCHAR	c ;
	BOOL	f_first = TRUE ;
	LPTSTR	last_white = 0 ;

	while ( c = *dst++ ) {
		if ( c == TEXT(' ') || c == TEXT('\t') ) {
			if ( f_first ) {
				last_white = dst - 1 ;
				f_first = FALSE ;
			}
		} else {
			last_white = 0 ;
			f_first = TRUE ;
		}
	}
	if ( last_white ) {
		*last_white = 0 ;
	}
}

BOOL
split_line( LPTSTR src, LPDWORD narg, LPTSTR *arg )
{
	TCHAR	c ;
	LPTSTR	dst = src ;
	BOOL	f_skip = TRUE, f_quote = FALSE, bRet = TRUE ;

	*narg = 0 ;
	while ( c = *src ) {
		if ( f_skip ) {
			if ( c == TEXT(':') ) {
				f_quote = FALSE ;
				*dst = 0 ;
				arg[ (*narg) ++ ] = dst ;
			} else if ( !(c == TEXT(' ') || c == TEXT('\t')) ) {
				f_skip = FALSE ;
				if ( c == TEXT('\\') ) {
					c = * ++ src ;
					if ( c == 0 ) {
						bRet = FALSE ;
						break ;
					} else if ( c == TEXT('r') ) {
						c = TEXT('\r') ;
					} else if ( c == TEXT('n') ) {
						c = TEXT('\n') ;
					}
				} else if ( c == TEXT('"') ) {
					f_quote = TRUE ;
				}
				arg[ (*narg) ++ ] = src ;
			}
			dst = ++ src ;
		} else {
			if ( f_quote ) {
				if ( c == TEXT('"') ) {
					f_quote = FALSE ;
				} else if ( c == TEXT('\\') ) {
					c = * ++ src ;
					if ( c == 0 ) {
						bRet = FALSE ;
						break ;
					} else if ( c == TEXT('r') ) {
						c = TEXT('\r') ;
					} else if ( c == TEXT('n') ) {
						c = TEXT('\n') ;
					}
				}
			} else if ( c == TEXT(':') ) {
				f_skip = TRUE ;
				*dst = 0 ;
				rtrim( arg[ (*narg) - 1 ] ) ;
				dst = ++ src ;
				continue ;
			} else if ( c == TEXT('\\') ) {
				c = * ++ src ;
				if ( c == 0 ) {
					bRet = FALSE ;
					break ;
				} else if ( c == TEXT('r') ) {
					c = TEXT('\r') ;
				} else if ( c == TEXT('n') ) {
					c = TEXT('\n') ;
				}
			}
			*dst ++ = c ;
			src ++ ;
		}
	}
	*dst = 0 ;
	if ( f_skip ) {
		arg[ (*narg) ++ ] = dst ;
	} else if ( *narg ) {
		rtrim( arg[ (*narg) - 1 ] ) ;
	}
	return bRet ;
}

void
unpack_str( LPTSTR dst, LPCTSTR src )
{
	TCHAR	c ;

	while ( c = *src++ ) {
		if ( c == '\\' ) {
			*dst++ = '\\' ;
		}
		*dst++ = c ;
	}
	*dst = 0 ;
}

/*
 * Palm-size PCでの文字コード変換異常に対処する
 */
TCHAR
conv( TCHAR c )
{
	switch ( c ) {
	case 0x201A:	c = 0x82 ;	break ;
	case 0x0192:	c = 0x83 ;	break ;
	case 0x201E:	c = 0x84 ;	break ;
	case 0x2026:	c = 0x85 ;	break ;
	case 0x2020:	c = 0x86 ;	break ;
	case 0x2021:	c = 0x87 ;	break ;
	case 0x02C6:	c = 0x88 ;	break ;
	case 0x2030:	c = 0x89 ;	break ;
	case 0x0160:	c = 0x8A ;	break ;
	case 0x2039:	c = 0x8B ;	break ;
	case 0x0152:	c = 0x8C ;	break ;
	case 0x2018:	c = 0x91 ;	break ;
	case 0x2019:	c = 0x92 ;	break ;
	case 0x201C:	c = 0x93 ;	break ;
	case 0x201D:	c = 0x94 ;	break ;
	case 0x2022:	c = 0x95 ;	break ;
	case 0x2013:	c = 0x96 ;	break ;
	case 0x2014:	c = 0x97 ;	break ;
	case 0x02DC:	c = 0x98 ;	break ;
	case 0x2122:	c = 0x99 ;	break ;
	case 0x0161:	c = 0x9A ;	break ;
	case 0x203A:	c = 0x9B ;	break ;
	case 0x0153:	c = 0x9C ;	break ;
	case 0x0178:	c = 0x9F ;	break ;
	}
	return c ;
}

BOOL
dbopen( LPTSTR dbname, PEGPROPID propid, DWORD flag )
{
	*g_szDBName = 0 ;
	g_oidDatabase = 0 ;
	g_hDatabase = PegOpenDatabase( &g_oidDatabase, dbname, propid, flag, NULL ) ;
	if ( g_hDatabase == INVALID_HANDLE_VALUE ) {
		wsprintf( MessageBuf, TEXT("Error: PegOpenDatabase(%d)\n"), GetLastError() ) ;
		return FALSE ;
	}
	_tcscpy( g_szDBName, dbname ) ;
	return TRUE ;
}

void
dbclose( void )
{
	if ( !CloseHandle( g_hDatabase ) ) {
		wsprintf( MessageBuf, TEXT("Error: PegCloseHandle(%d)\n"), GetLastError() ) ;
	}
}

PEGPROPID
dbgetsort( LPTSTR dbname )
{
	PEGOID		pegOID ;
	PEGPROPID	propID ;
	HANDLE		hOpenDB ;
	PEGOIDINFO	pegInfo ;

	pegOID = 0 ;
	hOpenDB = PegOpenDatabase( &pegOID, dbname, 0, 0, NULL ) ;
	if ( hOpenDB == INVALID_HANDLE_VALUE ) {
		return 0 ;
	}
	if ( !PegOidGetInfo( pegOID, &pegInfo ) ) {
		CloseHandle( hOpenDB ) ;
		return 0 ;
	}
	propID = pegInfo.infDatabase.rgSortSpecs[0].propid ;
	CloseHandle( hOpenDB ) ;
	return propID ;
}

BOOL
dbdelete( LPTSTR dbname )
{
	PEGOID		oid ;

	oid = 0 ;
	g_hDatabase = PegOpenDatabase( &oid, dbname, 0, 0, NULL ) ;
	if ( g_hDatabase == INVALID_HANDLE_VALUE ) {
		wsprintf( MessageBuf, TEXT("Error: PegOpenDatabase(%d)\n"), GetLastError() ) ;
		return FALSE ;
	}
	CloseHandle( g_hDatabase ) ;
	if ( !PegDeleteDatabase( oid ) ) {
		wsprintf( MessageBuf, TEXT("Error: PegDeleteDatabase(%d)\n"), GetLastError() ) ;
		return FALSE ;
	}
	return TRUE ;
}

BOOL
import_begin_db( DWORD argc, LPTSTR argv[] )
{
	DWORD		i ;
	PEGPROPID	propID ;

	if ( argc < 4 ) {
		Cputs( TEXT("Too few args in [Begin DB Section]\r\n") ) ;
		return FALSE ;
	}
	/* ソート順序を設定する */
	g_dwNumSortOrder = _ttoi( argv[3] ) ;
	for ( i = 0 ; i < g_dwNumSortOrder ; i ++ ) {
		g_pSortOrder[i].propid  = xatol( argv[i*2+4] ) ;
		g_pSortOrder[i].dwFlags = xatol( argv[i*2+5] ) ;
	}
	/* データベース名を作成する */
	_tcscpy( g_szDBName, argv[1] ) ;
	chop_quote( g_szDBName ) ;
	/* データベースを作成する */
	g_oidDatabase = PegCreateDatabase( g_szDBName, xatol( argv[2] ), (WORD) g_dwNumSortOrder, g_pSortOrder ) ;
	if ( !g_oidDatabase ) {
		DWORD	ret = GetLastError() ;

		if ( ret != ERROR_DUP_NAME ) {
			wsprintf( MessageBuf, TEXT("Error: PegCreateDatabase(%d)\r\n"), GetLastError() ) ;
			Cputs( MessageBuf ) ;
			return FALSE ;
		}
		/* 既にデータベースが作成されている場合 */
		wsprintf( MessageBuf, TEXT("Database already exists.\r\n") ) ;
		Cputs( MessageBuf ) ;
		g_oidDatabase = 0 ;
	}
	propID = g_dwNumSortOrder ? g_pSortOrder[0].propid : 0 ;
	g_hDatabase = PegOpenDatabase( &g_oidDatabase, g_szDBName, propID, 0, NULL ) ;
	if ( g_hDatabase == INVALID_HANDLE_VALUE ) {
		wsprintf( MessageBuf, TEXT("Error: PegOpenDatabase(%d)\r\n"), GetLastError() ) ;
		Cputs( MessageBuf ) ;
		return FALSE ;
	}
	return TRUE ;
}

BOOL
import_end_db( void )
{
	if ( g_hDatabase != INVALID_HANDLE_VALUE ) {
		if ( !CloseHandle( g_hDatabase ) ) {
			wsprintf( MessageBuf, TEXT("Error: PegCloseHandle(%d)\n"), GetLastError() ) ;
		}
		g_hDatabase = INVALID_HANDLE_VALUE ;
	}
	return TRUE ;
}

BOOL
import_begin_rec( void )
{
	g_dwNumProp = 0 ;
	g_propCur = g_propStr ;
	return TRUE ;
}

BOOL
import_str( LPTSTR str )
{
	chop_quote( str ) ;
	_tcscpy( g_propCur, str ) ;
	g_propCur += _tcslen( g_propCur ) ;
	if ( g_bContinue ) {
		*g_propCur   = 0 ;
		return FALSE ;
	}
	g_propCur ++ ;
	return TRUE ;
}

const	LPCTSTR		g_szHex = TEXT("0123456789ABCDEF") ;

DWORD
import_blob_sub( LPBYTE blob, LPTSTR str )
{
	BYTE	h ;
	TCHAR	c ;
	LPCTSTR	ptr ;
	BOOL	bData ;
	DWORD	count ;

	h = 0 ;
	count = 0 ;
	bData = FALSE ;
	while ( 1 ) {
		c = *str++ ;
		if ( !c ) {
			if ( bData ) {
				if ( blob ) {
					*blob++ = h * 16 ;
				}
				count ++ ;
			}
			break ;
		}
		ptr = _tcschr( g_szHex, c ) ;
		if ( !ptr ) {
			if ( bData ) {
				if ( blob ) {
					*blob++ = h * 16 ;
				}
				count ++ ;
			}
		} else if ( !bData ) {
			bData = TRUE ;
			h = (BYTE) ((ptr - g_szHex) % 16) ; ;
		} else {
			if ( blob ) {
				*blob++ = h * 16 + (BYTE) ((ptr - g_szHex) % 16) ;
			}
			count ++ ;
			bData = FALSE ;
		}
	}
	return count ;
}

BOOL
import_blob( LPTSTR str )
{
	LPBYTE		ptr ;
	DWORD		count ;

	if ( !g_blobVal ) {
		return FALSE ;
	}
	count = import_blob_sub( NULL, str ) ;
	if ( !count ) {
		return TRUE ;
	}
	count += g_blobVal->dwCount ;
	ptr = LocalAlloc( LPTR, count ) ;
	if ( !ptr ) {
		return FALSE ;
	}
	if ( g_blobVal->lpb ) {
		memcpy( ptr, g_blobVal->lpb, g_blobVal->dwCount ) ;
		LocalFree( g_blobVal->lpb ) ;
	}
	import_blob_sub( &ptr[ g_blobVal->dwCount ], str ) ;
	g_blobVal->lpb = ptr ;
	g_blobVal->dwCount = count ;
	return TRUE ;
}

BOOL
import_field( DWORD argc, LPTSTR argv[] )
{
	DWORD		len ;
	LPTSTR		ptr ;
	PEGPROPID	propID ;

	memset( &g_propVal[g_dwNumProp], 0, sizeof g_propVal[g_dwNumProp] ) ;
	g_blobVal = 0 ;

	propID = xatol( argv[1] ) ;
	g_propVal[g_dwNumProp].propid = propID ;
	switch ( TypeFromPropID( propID ) ) {
	case PEGVT_I2:
		g_propVal[g_dwNumProp].val.iVal = (short) xatol( argv[2] ) ;
		break ;
	case PEGVT_I4:
		g_propVal[g_dwNumProp].val.lVal = (long) xatol( argv[2] ) ;
		break ;
	case PEGVT_UI2:
		g_propVal[g_dwNumProp].val.uiVal = (WORD) xatol( argv[2] ) ;
		break ;
	case PEGVT_UI4:
		g_propVal[g_dwNumProp].val.ulVal = (DWORD) xatol( argv[2] ) ;
		break ;
	case PEGVT_FILETIME:
		len = _tcslen( argv[2] ) ;
		if ( len <= 8 ) {
			g_propVal[g_dwNumProp].val.filetime.dwLowDateTime  = xatol( argv[2] ) ;
			g_propVal[g_dwNumProp].val.filetime.dwHighDateTime = 0 ;
		} else {
			ptr = &argv[2][len - 8] ;
			g_propVal[g_dwNumProp].val.filetime.dwLowDateTime = xatol( ptr ) ;
			*ptr = 0 ;
			g_propVal[g_dwNumProp].val.filetime.dwHighDateTime = xatol( argv[2] ) ;
		}
		break ;
	case PEGVT_LPWSTR:
		g_propVal[g_dwNumProp].val.lpwstr = g_propCur ;
		import_str( argv[2] ) ;
		break ;
	case PEGVT_BLOB:
		g_blobVal = &g_propVal[g_dwNumProp].val.blob ;
		g_blobVal->dwCount = 0 ;
		g_blobVal->lpb = 0 ;
		import_blob( argv[2] ) ;
		break ;
	default:
		wsprintf( MessageBuf, TEXT("Invalid Property:%08X\r\n"), propID ) ;
		Cputs( MessageBuf ) ;
		return FALSE ;
	}
	g_dwNumProp ++ ;
	return TRUE ;
}

BOOL
import_end_rec( void )
{
	if ( !PegWriteRecordProps( g_hDatabase, 0, (WORD) g_dwNumProp, g_propVal ) ) {
		wsprintf( MessageBuf,
				  TEXT("Error: PegWriteRecordProps(%d)\n"),
				  GetLastError() ) ;
		Cputs( MessageBuf ) ;
		return FALSE ;
	}
	return TRUE ;
}

BOOL
import_file( LPCTSTR fn )
{
	DWORD		count_db, count_rec ;
	BOOL		bRecord = FALSE ;
	BOOL		bDatabase = FALSE ;

	if ( !Fopen( fn, TEXT("r") ) ) {
		wsprintf( MessageBuf,
				  TEXT("Error: can't open file: %s\n"),
				  fn ) ;
		return FALSE ;
	}
	count_db = 0 ;
	count_rec = 0 ;
	while ( Fgets( g_szSjis, sizeof g_szSjis ) ) {
		if ( !*g_szSjis || *g_szSjis == ';' ) {
			continue ;
		}
		sjis2unicode( g_szSjis, g_szUnicode, sizeof g_szUnicode ) ;
		cut_crlf( g_szUnicode ) ;
		g_bContinue = !split_line( g_szUnicode, &g_dwArgc, g_pArgv ) ;

		if ( !_tcsicmp( g_pArgv[0], TEXT("DATABASE") ) ) {
			/* データベースセクション開始 */
			import_end_db() ;
			if ( import_begin_db( g_dwArgc, g_pArgv ) ) {
				bDatabase = TRUE ;
			}
			++ count_db ;
			bRecord = FALSE ;
		} else if ( !_tcsicmp( g_pArgv[0], TEXT("END DATABASE") ) ) {
			/* データベースセクション終了 */
			if ( !bDatabase ) {
				Cputs( TEXT("Not in [DB Section]\r\n") ) ;
				continue ;
			}
			import_end_db() ;
			bDatabase = FALSE ;
			bRecord = FALSE ;
		} else if ( !_tcsicmp( g_pArgv[0], TEXT("RECORD") ) ) {
			/* レコードセクション開始 */
			if ( !bDatabase ) {
				Cputs( TEXT("Not in [DB Section]\r\n") ) ;
				continue ;
			}
			if ( import_begin_rec() ) {
				bRecord = TRUE ;
			}
		} else if ( !_tcsicmp( g_pArgv[0], TEXT("FIELD") ) ) {
			/* フィールドデータ */
			if ( !bRecord ) {
				Cputs( TEXT("Not in [Rec Section]\r\n") ) ;
				continue ;
			}
			import_field( g_dwArgc, g_pArgv ) ;
		} else if ( !_tcsicmp( g_pArgv[0], TEXT("STRING") ) ) {
			/* 文字列データ */
			if ( !bRecord ) {
				Cputs( TEXT("Not in [Rec Section]\r\n") ) ;
				continue ;
			}
			import_str( g_pArgv[1] ) ;
		} else if ( !_tcsicmp( g_pArgv[0], TEXT("BLOB") ) ) {
			/* BLOBデータ */
			if ( !bRecord ) {
				Cputs( TEXT("Not in [Rec Section]\r\n") ) ;
				continue ;
			}
			import_blob( g_pArgv[1] ) ;
		} else if ( !_tcsicmp( g_pArgv[0], TEXT("END") ) ) {
			/* レコードセクション終了 */
			if ( !bRecord ) {
				Cputs( TEXT("Not in [Rec Section]\r\n") ) ;
				continue ;
			}
			import_end_rec() ;
			++ count_rec ;
			bRecord = FALSE ;
		}
	}
	import_end_db() ;
	Fclose() ;

	wsprintf( MessageBuf, TEXT("%d database(s), %d record(s) imported.\r\n"),
			  count_db, count_rec ) ;
	Cputs( MessageBuf ) ;

	return TRUE ;
}

void
export_str( LPCTSTR str )
{
	LPSTR	ptr ;
	WORD	sjis ;
	TCHAR	c, cSjis = 0 ;

	ptr = g_szSjis ;
	*ptr++ = TEXT('"') ;
	while ( c = *str++ ) {
		c = conv( c ) ;
		if ( c == TEXT('\r' ) ) {
			*ptr++ = '\\' ;
			*ptr++ = 'r' ;
			cSjis = 0 ;
		} else if ( c == TEXT('\n') ) {
			*ptr++ = '\\' ;
			*ptr++ = 'n' ;
			*ptr++ = '"' ;
			*ptr++ = ' ' ;
			*ptr++ = '\\' ;
			*ptr++ = '\n' ;
			*ptr = 0 ;
			Fputs( g_szSjis ) ;
			ptr = g_szSjis ;
			strcpy( ptr, "String : \"" ) ;
			ptr += strlen( ptr ) ;
			cSjis = 0 ;
		} else if ( cSjis ) {
			*ptr++ = 0xFF & cSjis ;
			*ptr++ = 0xFF & c ;
			cSjis = 0 ;
		} else if ( c == TEXT('"') || c == TEXT('\\') ) {
			*ptr++ = '\\' ;
			*ptr++ = (CHAR) c ;
			cSjis = 0 ;
		} else if ( c >= 0x80 && c < 0x100 ) {
			cSjis = c ;
		} else {
			sjis = unicode2sjis_char( c ) ;
			if ( sjis == 0xFFFF ) {
				*ptr++ = (CHAR) c ;
				continue ;
			} else {
				c = sjis ;
			}
			if ( c > 0x100 ) {
				*ptr++ = c >> 8 ;
			}
			*ptr++ = c & 0xFF ;
		}
	}
	*ptr++ = '"' ;
	*ptr++ = '\n' ;
	*ptr = 0 ;
	Fputs( g_szSjis ) ;
}

void
export_blob( DWORD size, LPBYTE data )
{
	DWORD		i ;
	LPTSTR		ptr ;

	ptr = g_szUnicode ;
	for ( i = 0 ; i < size ; i ++ ) {
		if ( i && ((i % 16) == 0) ) {
			*ptr++ = TEXT('\\') ;
			*ptr++ = TEXT('\n') ;
			*ptr   = 0 ;
			unicode2sjis( g_szUnicode, g_szSjis, sizeof g_szSjis ) ;
			Fputs( g_szSjis ) ;
			ptr = g_szUnicode ;
			_tcscpy( ptr, TEXT("Blob : ") ) ;
			ptr += _tcslen( ptr ) ;
		}
		wsprintf( ptr, TEXT("%02X "), 0xFF & data[i] ) ;
		ptr += _tcslen( ptr ) ;
	}
	*ptr++ = TEXT('\n') ;
	*ptr   = 0 ;
	unicode2sjis( g_szUnicode, g_szSjis, sizeof g_szSjis ) ;
	Fputs( g_szSjis ) ;
}

BOOL
export_file( LPCTSTR fn, BOOL bAppend )
{
	PEGOID		oid ;
	LPTSTR		ptr ;
	LPBYTE		pBuf ;
	PEGPROPID	propID ;
	PEGOIDINFO	pegInfo ;
	PPEGPROPVAL	pPropVal ;
	WORD		numProps ;
	DWORD		cbBuf, i, count_rec ;

	count_rec = 0 ;
	if ( !Fopen( fn, bAppend ? TEXT("w") : TEXT("a") ) ) {
		wsprintf( MessageBuf,
				  TEXT("Error: can't open file: %s\n"),
				  fn ) ;
		return FALSE ;
	}

	/* Databaseのプロパティを出力する */
	ptr = g_szUnicode ;
	wsprintf( ptr, TEXT("Database: \"") ) ;
	ptr += _tcslen( ptr ) ;
	unpack_str( ptr, g_szDBName ) ;
	ptr += _tcslen( ptr ) ;
	_tcscpy( ptr, TEXT("\" : ") ) ;
	ptr += _tcslen( ptr ) ;
	if ( PegOidGetInfo( g_oidDatabase, &pegInfo ) ) {
		wsprintf( ptr, TEXT("%X : %d"),
				  pegInfo.infDatabase.dwDbaseType,
				  pegInfo.infDatabase.wNumSortOrder ) ;
		ptr += _tcslen( ptr ) ;
		for ( i = 0 ; i < pegInfo.infDatabase.wNumSortOrder ; i ++ ) {
			wsprintf( ptr, TEXT(" : %X : %X"),
					  pegInfo.infDatabase.rgSortSpecs[i].propid,
					  pegInfo.infDatabase.rgSortSpecs[i].dwFlags ) ;
			ptr += _tcslen( ptr ) ;
		}
	}
	*ptr++ = TEXT('\n') ;
	*ptr = 0 ;
	unicode2sjis( g_szUnicode, g_szSjis, sizeof g_szSjis ) ;
	Fputs( g_szSjis ) ;

	while ( 1 ) {
		pBuf = NULL ;
		cbBuf = 0 ;
		oid = PegReadRecordProps( g_hDatabase, PEGDB_ALLOWREALLOC,
								  &numProps, NULL, &pBuf, &cbBuf ) ;
		if ( !oid ) {
			break ;
		}
		if ( pBuf && numProps ) {
			Fputs( "Record :\n" ) ;

			pPropVal = (PPEGPROPVAL) pBuf ;
			for ( i = 0 ; i < numProps ; i ++ ) {
				propID = pPropVal[i].propid ;
				ptr = g_szUnicode ;
				wsprintf( ptr, TEXT("Field : %X : "), propID ) ;
				ptr += _tcslen( ptr ) ;
				switch ( TypeFromPropID( propID ) ) {
				case PEGVT_FILETIME:
					wsprintf( ptr, TEXT("%08X%08X\n"),
							  pPropVal[i].val.filetime.dwHighDateTime,
							  pPropVal[i].val.filetime.dwLowDateTime ) ;
					unicode2sjis( g_szUnicode, g_szSjis, sizeof g_szSjis ) ;
					Fputs( g_szSjis ) ;
					break ;
				case PEGVT_I2:
					wsprintf( ptr, TEXT("%X\n"), pPropVal[i].val.iVal ) ;
					unicode2sjis( g_szUnicode, g_szSjis, sizeof g_szSjis ) ;
					Fputs( g_szSjis ) ;
					break ;
				case PEGVT_I4:
					wsprintf( ptr, TEXT("%X\n"), pPropVal[i].val.lVal ) ;
					unicode2sjis( g_szUnicode, g_szSjis, sizeof g_szSjis ) ;
					Fputs( g_szSjis ) ;
					break ;
				case PEGVT_UI2:
					wsprintf( ptr, TEXT("%X\n"), pPropVal[i].val.uiVal ) ;
					unicode2sjis( g_szUnicode, g_szSjis, sizeof g_szSjis ) ;
					Fputs( g_szSjis ) ;
					break ;
				case PEGVT_UI4:
					wsprintf( ptr, TEXT("%X\n"), pPropVal[i].val.ulVal ) ;
					unicode2sjis( g_szUnicode, g_szSjis, sizeof g_szSjis ) ;
					Fputs( g_szSjis ) ;
					break ;
				case PEGVT_LPWSTR:
					unicode2sjis( g_szUnicode, g_szSjis, sizeof g_szSjis ) ;
					Fputs( g_szSjis ) ;
					export_str( pPropVal[i].val.lpwstr ) ;
					break ;
				case PEGVT_BLOB:
					unicode2sjis( g_szUnicode, g_szSjis, sizeof g_szSjis ) ;
					Fputs( g_szSjis ) ;
					export_blob( pPropVal[i].val.blob.dwCount, pPropVal[i].val.blob.lpb ) ;
					break ;
				default:
					_tcscpy( ptr, TEXT("?\n") ) ;
					unicode2sjis( g_szUnicode, g_szSjis, sizeof g_szSjis ) ;
					Fputs( g_szSjis ) ;
					break ;
				}
			}
			Fputs( "End\n" ) ;
			++ count_rec ;
		}
		if ( pBuf ) {
			LocalFree( pBuf ) ;
		}
	}
	Fputs( "End Database\n" ) ;
	Fclose() ;

	wsprintf( MessageBuf, TEXT("%d record(s) exported.\r\n"),
			  count_rec ) ;
	Cputs( MessageBuf ) ;

	return TRUE ;
}

int
AppMain( DWORD argc, LPTSTR argv[] )
{
	PEGPROPID	propid ;

	wsprintf( MessageBuf,
			  TEXT("%s V%d.%02d Copyright (C) 1998, E.ITO\n"),
			  AppName, AppVersion / 100, AppVersion % 100 ) ;
	Cputs( MessageBuf ) ;
	if ( argc <= 1 ) {
		wsprintf( MessageBuf,
				  TEXT("Usage: %s command dbname params...\n")
				  TEXT("\texport: -e dbname export-file\n")
				  TEXT("\texport: -E dbname export-file (append)\n")
				  TEXT("\timport: -i import-file\n")
				  TEXT("\tdelete: -d dbname\n"),
				  AppName ) ;
		return 1 ;
	}
	if ( !_tcscmp( argv[ 1 ], TEXT("-d") ) ) {
		if ( argc <= 2 ) {
			wsprintf( MessageBuf,
					  TEXT("Error: %s -d dbname\n"),
					  AppName ) ;
			return 1 ;
		}
		if ( !dbdelete( argv[ 2 ] ) ) {
			return 2 ;
		}
	} else if ( !_tcscmp( argv[ 1 ], TEXT("-i") ) ) {
		if ( argc <= 2 ) {
			wsprintf( MessageBuf,
					  TEXT("Error: %s -i import-file\n"),
					  AppName ) ;
			return 1 ;
		}
		if ( !import_file( argv[ 2 ] ) ) {
			return 1 ;
		}
	} else if ( !_tcsicmp( argv[ 1 ], TEXT("-e") ) ) {
		if ( argc <= 3 ) {
			wsprintf( MessageBuf,
					  TEXT("Error: %s -i dbname export-file\n"),
					  AppName ) ;
			return 1 ;
		}
		propid = dbgetsort( argv[ 2 ] ) ;
		if ( !dbopen( argv[ 2 ], propid, PEGDB_AUTOINCREMENT ) ) {
			return 3 ;
		}
		if ( !export_file( argv[ 3 ], _tcscmp( argv[ 1 ], TEXT("-e") ) ) ) {
			dbclose() ;
			return 4 ;
		}
		dbclose() ;
	}
	return 0 ;
}

int
Main( DWORD argc, LPTSTR argv[] )
{
	int		ret ;

	if ( !InitKanjiControls() ) {
		wsprintf( MessageBuf,
				  TEXT("KCTRL.DLL Initialize error\r\nError=%x"),
				  GetLastError() ) ;
		Cputs( MessageBuf ) ;
		return 1 ;
	}
	ret = AppMain( argc, argv ) ;
	if ( ret ) {
		Cputs( MessageBuf ) ;
	}
	ReleaseKanjiControls() ;
	return 1 ;
}
