/*<Header>==============================================================
*
*	RESUME MANAGER / "EIN_RSM.C"
*
*	COPYRIGHT  Nam  1994, All rights reserved.
*
*		[ Ein(tm) project : リジュームマネージャ関数群 ]
*
*-----------------------------------------------------------------------
*	V1.0L01α	94.04.12/Nam	プロトタイプ
*	V1.0L01γ	94.04.15/Nam	debug,EOF対応
*	V1.0L02α	94.04.18/Nam	`RSM_WORK'に仕様変更
*	V1.0L03α	94.04.27/Nam	プロジェクト名を'EIN(TM)'に（命名:ま２）
*	V1.0L03γ	94.06.22/Nam	CD起動時はinitに失敗するよう変更
*	V1.0L04α	94.07.06/Nam	DLL化/関数名を'EIN_rsm..'に変更
*</Header>==============================================================*/
#include	<stdarg.h>
#include	<stdio.h>
#include 	<stdlib.h>
#include 	<string.h>
#include	<snd.h>
#include	<winb.h>
#include	<te.h>
#include	<fntb.h>
#include	<gui.h>
#include 	<time.h>

#define	EIN_RSM
#include 	"..\eintm.h"


#define	RSMVER	("### EIN(TM):  Resume Data File V0.1L04α ###\n\n\n")

#define	RSMENV	("RSM")
#define	RSMNAME	("RESUME.INI")
#define	RBKNAME	("RESUME.BAK")

#ifndef NOERR
#define	NOERR	(0)
#endif
#ifndef ERROR
#define	ERROR	(1)
#endif


#define	CHR_EOF	(0x1a)
#define	CHR_EOB	(0x01)	/* ^A */
#define	CHR_CR	(0x0d)
#define	CHR_LF	(0x0a)

#ifdef EINLIB
	#define	CBUFSIZE	(4096)
	#define	PBUFSIZE	(512)
#else
	#define	CBUFSIZE	(256)
	#define	PBUFSIZE	(128)
#endif

#define	RSMWID	("RSMMGR 004α")
#define	RSMTAGIDLEN	(63)
#define	RSMPATHLEN	(63)

/* ワークエリア識別id */
static char rsmworkstr[16]=RSMWID;
/* 改行文字＆改データ文字 */
static char	str_lf[3]={ CHR_CR, CHR_LF, 0 };
static char	str_eob[4]={ CHR_EOB, CHR_CR, CHR_LF, 0 };
/* 共用入出力バッファ域 */
static char	cbuf[CBUFSIZE+2];

/* 編集属性構造体 */
typedef struct {
	/* ワークエリア識別文字列 */
	char		workid[16];				/* ワークエリア識別文字列 */
	
	char		*rbuf;					/* データバッファポインタ           */
	long int	rbufsize;				/* データバッファサイズ             */
	
	char		idstr[64];				/* 識別タグ文字列                   */
	char		bname[64];				/* 読み出しファイル名               */
	char		fname[64];				/* 書き込みファイル名               */
	FILE		*fp_r;					/* 読み出し用ファイルポインタ       */
	FILE		*fp_w;					/* 書き込み用ファイルポインタ       */
	
	long int	tagstart;				/* データ開始位置                   */
	long int	fstart;					/* 指定データ開始位置               */
	long int	osize;					/* 指定データのサイズ(byte)         */

	long int	tagSum;					/* 保存したタグ総数                 */
	long int	bufRemain;				/* 保存バッファの残り(byte)         */
	char		bufError;				/* 保存エラーフラグ(save時に使用)   */
	char		lastChar;				/* 最後にコピーした文字             */
	
}	EIN_RSMWORK;						/* リジュームマネージャワーク構造体 */


/*<Func>================================================================
*	int		EIN_rsmInit( EIN_RSMWORK *work, char *idstr )
*
*	【概  要】	リジュームマネージャの初期化
*
*	【機  能】	
*
*	【入  力】
*				*work		:	ワークエリアへのポインタ
*				*idstr		:	識別id文字列へのポインタ(終端はNULL,改行無し)
*
*	【出  力】
*
*	【関数値】	== NOERR	正常終了
*
*	【注  意】	
*
*	【参  照】	
*
*-----------------------------------------------------------------------
*	V11L10	1994.04.16/Nam
*</Func>==============================================================*/
int		EIN_rsmInit( EIN_RSMWORK *work, char *idstr )
{
	int		bootDrv;
	int		len;
	int		ret = NOERR;
	char	path[64];

	/* ワークエリア識別id書き込み */
	strcpy( work->workid, rsmworkstr);

	/* データ識別id読み込み */
	strncpy( work->idstr, idstr, RSMTAGIDLEN );
	work->idstr[RSMTAGIDLEN] = '\0';	/* id長が大きすぎる場合のtrap */

	/* ワーク初期化 */
	work->rbuf = NULL;			/* データバッファポインタ     */
	work->rbufsize = 0;			/* データバッファサイズ       */
	work->fp_r = NULL;			/* 読み出し用ファイルポインタ */
	work->fp_w = NULL;			/* 書き込み用ファイルポインタ */
	work->tagstart = 0;			/* データ開始位置             */
	work->fstart   = 0;			/* 指定データ開始位置         */
	work->osize    = 0;			/* 指定データのサイズ         */
	work->tagSum   = 0;			/* タグ総数                   */
	work->bufRemain= 0;			/* 保存バッファの残り(byte)   */
	work->bufError = NOERR;		/* バッファ保存フラグ         */
	work->lastChar = 0;			/* 最後にコピーした文字       */

	/* リジュームファイルのパス名を取得 */
	if ( (getenv(RSMENV) == NULL) ){
		 /* 環境パスが存在しない場合は */
		#ifdef EINLIB
			extern unsigned char	FSYS_getBOOT();
			bootDrv = FSYS_getBOOT();
		#else
			bootDrv=3;	/* 単独テストの場合はCドライブに固定 */
		#endif
		/* 起動ドライブがQ以外ならリジューム可能 */
		if ( bootDrv != 16 ){
			path[0]=(bootDrv+'A');
			path[1]=0;
			strcat(path, ":\\T_FILE\\");
		} else {
			/* 起動ドライブがQならリジュームできない */
			strcpy( work->workid, ""); 
			ret = ERROR;
		}
	} else {
		/*	環境パス(%RESUME%)が有る*/
		strncpy( path, getenv(RSMENV), (RSMPATHLEN-13) );
		*(path+(RSMPATHLEN-13)) = '\0';	/* id長が大きすぎる場合のtrap */
		len = strlen (path);				/* パス名を得る              */
		if (path[len-1] != '\\'){			/* 終端が '\' で無い場合は   */
			strcat(path, "\\");				/* '\'を追加                 */
		}
	}
	/* リジュームファイルの絶対パス名を設定 */
	strcpy(work->fname, path);
	strcat(work->fname, RSMNAME);
	/* リジュームファイルのバックアップの絶対パス名を設定 */
	strcpy(work->bname, path);
	strcat(work->bname, RBKNAME);
	
	#ifdef DEBUG
	printf(" EIN_rsmInit( %x, %s )\n", work, idstr);
	printf("           fname:%s  bname:%s\n", work->fname, work->bname);
	printf("           bootDrv=%d\n", bootDrv);
	#endif
	
	return ret;
}

/*======================================================================
*	int		__EIN_rsmChkWork( EIN_RSMWORK *work )
*
*	【概  要】	リジュームマネージャワークエリアの正当性チェック
*
*	【機  能】	
*
*	【入  力】
*				*work		:	ワークエリアへのポインタ
*
*	【出  力】
*
*	【関数値】	== NOERR	正常終了
*				!= NOERR	異常終了
*								-1:ワークエリアのアドレスがNULL
*								-2:ワークエリアが未初期化
*								-3:マネージャのVersionが違う
*								-4:ワークエリアの初期化に失敗
*
*	【注  意】	
*
*	【参  照】	
*
*-----------------------------------------------------------------------
*	V11L10	1994.04.16/Nam
*=====================================================================*/
int		__EIN_rsmChkWork( EIN_RSMWORK *work )
{
	if ( work==NULL ){
		#ifdef DEBUG
		printf("__EIN_rsmChkWork: ワークエリアのアドレスがNULLです\n");
		#endif
		return -1;
	}
	if ( work->workid[0]!='R' ){
		#ifdef DEBUG
		printf("__EIN_rsmChkWork: ワークエリアを初期化していません\n");
		#endif
		return -2;
	}
	if ( strcmp(work->workid,rsmworkstr) != 0){
		#ifdef DEBUG
		printf("__EIN_rsmChkWork: リジュームマネージャのVersionが違います\n");
		#endif
		return -3;
	}
	if ( work->idstr==NULL || work->fname==NULL || work->bname==NULL ){
		#ifdef DEBUG
		printf("__EIN_rsmChkWork: ワークエリアの初期化に失敗しています\n");
		#endif
		return -4;
	}
	return NOERR;
}

/*======================================================================
*	int		__EIN_rsmGetBufRemain( EIN_RSMWORK *work )
*
*	【概  要】	リジューム情報バッファ残り算出
*
*	【機  能】	リジューム情報バッファの残りbyte数を計算します
*
*	【入  力】	*work		:	ワークエリアへのポインタ
*
*	【出  力】
*
*	【関数値】	残りbyte数
*
*	【注  意】	バッファ終端サイズを含めます.
*				ワークエリアのチェックはしないので注意して下さい.
*
*	【参  照】	
*
*-----------------------------------------------------------------------
*	V11L10	1994.06.24/Nam
*=====================================================================*/
int		__EIN_rsmGetBufRemain( EIN_RSMWORK *work )
{
	work->bufRemain = work->rbufsize - 
					(strlen(work->rbuf)+strlen(str_lf)+strlen(str_eob)+1);
	return work->bufRemain;
}

/*<Func>================================================================
*	int		EIN_rsmBufHead( EIN_RSMWORK *work )
*
*	【概  要】	リジューム情報バッファID設定
*
*	【機  能】	リジューム情報バッファ先頭にID文字列を設定します
*
*	【入  力】	*work		:	ワークエリアへのポインタ
*
*	【出  力】
*
*	【関数値】	== NOERR	正常終了
*				!= NOERR	異常終了
*
*	【注  意】	
*
*	【参  照】	
*
*-----------------------------------------------------------------------
*	V11L10	1994.04.18/Nam
*</Func>==============================================================*/
int		EIN_rsmBufHead( EIN_RSMWORK *work )
{
	time_t		ct = time(NULL);
	struct tm  *lt = localtime(&ct);
	char		tmp[80];

	if (__EIN_rsmChkWork(work)!=NOERR){
		return ERROR;
	}
	if ( work->rbuf==NULL || work->rbufsize<64 ){
		#ifdef DEBUG
		printf("EIN_rsmBufHead: バッファ指定が不正\n");
		#endif
		return ERROR;
	}
	/* set id */
	strcpy( work->rbuf, work->idstr );
	strcat( work->rbuf, str_lf );	/* 最後にCRLFを追加 */
	/* set time */
	strcpy( tmp, "UPDATE:  " );
	strcat( tmp, asctime(lt) );
	strcat( work->rbuf, tmp );
	/* calc buf remain */
	__EIN_rsmGetBufRemain( work );

	return NOERR;
}

/*<Func>================================================================
*	int		EIN_rsmBufTail( EIN_RSMWORK *work )
*
*	【概  要】	リジューム情報バッファ終端設定
*
*	【機  能】	リジューム情報バッファの終端タグ("^L")を設定します。
*
*	【入  力】	*work		:	ワークエリアへのポインタ
*
*	【出  力】
*
*	【関数値】	== NOERR	正常終了
*				!= NOERR	異常終了
*
*	【注  意】	バッファが足りない場合は、強制的に終端にLF&EOBを上書きします.
*
*	【参  照】	
*
*-----------------------------------------------------------------------
*	V11L10	1994.04.18/Nam
*	V11L11	1994.06.24/Nam		バッファ不足時の処理を強化
*</Func>==============================================================*/
int		EIN_rsmBufTail( EIN_RSMWORK *work )
{
	register int	size;

	if (__EIN_rsmChkWork(work)!=NOERR){
		return ERROR;
	}
	if ( work->rbuf == NULL ){
		#ifdef DEBUG
		printf("EIN_rsmBufTail: バッファ指定が不正\n");
		#endif
		return ERROR;
	}
	/* バッファ末尾に既にEOBが有れば終了 */
	size=strlen(work->rbuf);
	if ( work->rbuf[size-3]==CHR_EOB &&
		 work->rbuf[size-2]==CHR_CR  &&
		 work->rbuf[size-1]==CHR_LF ){
		#ifdef DEBUG
		printf("EIN_rsmBufTail: 既にEOBが書かれているので処理を中断します\n");
		#endif
		return NOERR;
	}
	if ( work->rbufsize < (strlen(work->rbuf)+strlen(str_eob)+1) ){
		#ifdef DEBUG
		printf("EIN_rsmBufTail: バッファサイズ不足 (%d < %d) \n",
			work->rbufsize, (strlen(work->rbuf)+strlen(str_eob)+1) );
		#endif
		/* 強制的にEOBを付加する */
		size = work->rbufsize;
		work->rbuf[size-6] = CHR_CR;	/* まず改行 */
		work->rbuf[size-5] = CHR_LF;
		work->rbuf[size-4] = CHR_EOB;	/* EOB */
		work->rbuf[size-3] = CHR_CR;	/* また改行 */
		work->rbuf[size-2] = CHR_LF;
		work->rbuf[size-1] = 0;			/* 文字列終端 */
		/* 保存エラーフラグを立てる */
		work->bufError = ERROR;
		
		return ERROR;
	}
	strcat( work->rbuf, str_eob );

	return NOERR;
}

/*<Func>================================================================
*	int		EIN_rsmBufSet( EIN_RSMWORK *work, char *rbuf, int rbufsize )
*
*	【概  要】	リジューム情報読み込みバッファ設定
*
*	【機  能】	
*
*	【入  力】	*work		:	ワークエリアへのポインタ
*				*rbuf		:	バッファポインタ
*				rbufsize	:	バッファサイズ(byte)
*
*	【出  力】
*
*	【関数値】	== NOERR	正常終了
*
*	【注  意】	設定時にアプリ識別IDをバッファ先頭に埋め込みます
*
*	【参  照】	
*
*-----------------------------------------------------------------------
*	V11L10	1994.04.16/Nam
*	V11L10	1994.04.21/Nam (識別ID自動埋め込み)
*</Func>==============================================================*/
int		EIN_rsmBufSet( EIN_RSMWORK *work, char *rbuf, int rbufsize )
{
	if (__EIN_rsmChkWork(work)!=NOERR){
		return ERROR;
	}
	if ( rbuf==NULL || rbufsize<16 ){
		#ifdef DEBUG
		printf("__RSMMG_setBuf: バッファ指定が不正\n");
		#endif
		return ERROR;
	}
	work->rbuf = rbuf;
	work->rbufsize = (long int)rbufsize;
	#ifdef DEBUG
	printf("__RSMMG_setBuf: rbuf:0x%x  rbufsize:%d\n", rbuf, rbufsize);
	#endif
	/* アプリ識別ID埋め込み */
	EIN_rsmBufHead( work );

	return NOERR;
}

/*======================================================================
*	int		__EIN_rsmReadFile( EIN_RSMWORK *work, int mode )
*
*	【概  要】	ファイルリード
*
*	【機  能】	
*
*	【入  力】	*work		:	ワークエリアへのポインタ
*				mode		:	動作モード( 0:検索のみ / 1:読み込み )
*
*	【出  力】
*
*	【関数値】	== NOERR	正常終了
*
*	【注  意】	あらかじめEIN_rsmInit()でワークを初期化しておくこと
*
*	【参  照】	
*
*-----------------------------------------------------------------------
*	V11L10	1994.04.12/Nam
*	V11L20	1994.04.16/Nam	(RSM_WORKを使用するよう改造)
*=====================================================================*/
int		__EIN_rsmReadFile( EIN_RSMWORK *work, int mode )
{
	FILE	*fp_r;
	char	pbuf[PBUFSIZE];	/* 行読み込みバッファ */
	char	*bp;		/*  */
	char	*nbp;		/*  */
	char	*rbuf;		/*  */
	int		fptr=0;		/* 現在のファイルポインタ */
	int		bptr=0;		/* バッファ巻き込み開始位置 */
	int		readsize=0;	/* タグ読み取りサイズ(byte) */
	int		size;		/* ファイル読み込みサイズ */
	int		foo;
	char	tagflag=0;	/* タグ開始フラグ(0/1) */
	char	eobflag=0;	/* EOBフラグ(0/1) */
	
	/* お約束のErrorTrap */
	if (__EIN_rsmChkWork(work)!=NOERR){
		return ERROR;
	}
	/* 読み込みモードでもバッファが無ければ検索のみに */
	if ( work->rbuf==NULL ){
		mode = 0;
	}
	rbuf = work->rbuf;
	
	/* resumeファイルをOpen */
	fp_r = fopen( work->fname, "rb" );
	if (fp_r==NULL) {
		#ifdef DEBUG
		printf("\t: ファイルを開けません.\n");
		#endif
		return -1;
	}
	work->fstart=0;
	work->osize=0;
	
	/* ファイルの続く限りループ */
	for ( ; ((size = fread( (&cbuf[0]+bptr), 1, (CBUFSIZE-bptr), fp_r )) > 0); ){
		cbuf[size+bptr]=0;
		/*
		printf("@@@ inc=%d   size=%d  bptr=%d\n", i++, size, bptr);
		printf("!!%s", cbuf);
		*/
		bp=&cbuf[0];
		/* バッファ内のデータを'\n'単位で読み出す */
		for ( ; (bp<&cbuf[CBUFSIZE]) && ((nbp=strchr(bp,0x0a))!=NULL) ; ){
			foo = (nbp-bp)-1;
			if ( foo > 0 ){
				/* 行バッファをはみ出ないように */
				if ( foo > (PBUFSIZE-2) ){
					foo = PBUFSIZE-2;
				}
				strncpy(pbuf,bp,foo);
				pbuf[foo]=0;	/* id長が大きすぎる場合のtrap */
			} else {
				pbuf[0]=0;
			}
			/*
			printf("%x(%d): %s\n", bp, strlen(pbuf), pbuf);
			*/
			
			/* データブロック開始チェック                              */
			/* (直前がEOBかつ識別ID文字列であればタグ開始フラグを真に) */
			if ( (eobflag > 0) &&
				 (strcmp( pbuf, work->idstr ) == 0) ){
				/* ファイル上開始位置 */
				work->fstart = fptr+(int)(bp-&cbuf[bptr]);
				/* タグ開始フラグを真に */
				tagflag=1;
				/*	printf("## start: %x:\n", fptr+(bp-&cbuf[bptr]));	*/
			}
			/* eobフラグをクリア */
			eobflag = 0;
			/*  tagflagが真の間は */
			if ( tagflag>0 ){
				/* 失われた0d0aを付加 */
				foo = strlen(pbuf);
				pbuf[foo  ]=0x0d;
				pbuf[foo+1]=0x0a;
				pbuf[foo+2]=0;
				readsize+=strlen(pbuf);
				/*	printf("%d(+%d): %s", readsize, strlen(pbuf), pbuf);	*/
				/* もし読み込みモードなら */
				if ( mode>0 ){
					foo = strlen(pbuf);
					/* もしrbufをはみ出しそうなら終了 */
					if ( work->rbufsize <= (readsize+foo) ){
						/* ファイルの最後へ */
						fseek( fp_r, 0, SEEK_END );
						break;
					}
					memcpy(rbuf,pbuf,foo);
					rbuf+= foo;
				}
			}
			/* データブロック終端('^A')のcheck */
			if ( strchr(pbuf, CHR_EOB)!=NULL ){
				/* EOBフラグを真に */
				eobflag = 1;
				/*printf("EOB: %s", pbuf);*/
				/* もしデータブロックフラグが真なら、これで読み込み終了 */
				if ( tagflag>0 ){
					tagflag=0;
					/* ファイルの最後へ */
					fseek( fp_r, 0, SEEK_END );
					/*	printf("## end: %x:\n", fptr+(bp-&cbuf[bptr])+2);	*/
					break;
				}
			}
			bp=nbp+1;
		}
		/* バッファの最後の行が中断しているなら持ち越し処理 */
		if ( (bp>&cbuf[0]) && (bp<&cbuf[CBUFSIZE-1]) ){
			memcpy( &cbuf[0], bp, &cbuf[CBUFSIZE]-bp );
			bptr=&cbuf[CBUFSIZE]-bp;
			/*
			printf("## memcpy( %x,%x,%d)\n", &cbuf[0], bp, &cbuf[CBUFSIZE]-bp );
			cbuf[bptr+1]=0;
			printf("## %s\n", cbuf);
			*/
		} else {
			bptr=0;
		}
		fptr+=size;
		/*
		printf("## bptr=%d\n", bptr);
		*/
	}
	fclose(fp_r);

	/* ワークエリアに結果を保存 */
	work->osize = readsize;

	return readsize;
}

/*======================================================================
*	int		__EIN_rsmCloseAndRename( EIN_RSMWORK *work )
*
*	【概  要】	ファイル作成に失敗した時の内部関数
*
*	【機  能】	ファイルハンドルをクローズし、古いファイル名にリネームします
*
*	【入  力】	*work		:	ワークエリアへのポインタ
*
*	【出  力】
*
*	【関数値】	-9			正常終了
*
*	【注  意】	バイナリモードでOPENしてください
*
*	【参  照】	
*
*-----------------------------------------------------------------------
*	V11L10	1994.04.12/Nam
*=====================================================================*/
int		__EIN_rsmCloseAndRename( EIN_RSMWORK *work )
{
	if ( work->fp_r!=NULL ){
		fclose( work->fp_r );
		work->fp_r = NULL;
	}
	if ( work->fp_w!=NULL ){
		fclose( work->fp_w );
		work->fp_w = NULL;
	}
	rename( work->bname, work->fname );
	#ifdef DEBUG
	printf("\t: 失敗したので remane(%s->%s)\n", work->bname, work->fname);
	#endif
	return -9;
}

/*======================================================================
*	int		__EIN_rsmCopyF( EIN_RSMWORK *work, int size )
*
*	【概  要】	現在のファイルポインタから指定バイト数をコピー
*
*	【機  能】	
*
*	【入  力】	*work		:	ワークエリアへのポインタ
*				size		:	書き込むバイト数
*
*	【出  力】
*
*	【関数値】	NOERR	:
*				ERROR	:
*
*	【注  意】	バイナリモードでOPENしてください
*
*	【参  照】	
*
*-----------------------------------------------------------------------
*	V11L10	1994.04.12/Nam
*=====================================================================*/
int		__EIN_rsmCopyF( EIN_RSMWORK *work, int size )
{
	int		csize;
	
	work->lastChar = CHR_LF;
	if ( size < 1 ){
		return NOERR;
	}
	csize = ( size < CBUFSIZE ) ?size :CBUFSIZE;
	for ( ; size > 0; ){
		if ( fread(  cbuf, csize, 1, work->fp_r ) < 1 ){
			break;
		}
		if ( fwrite( cbuf, csize, 1, work->fp_w ) < 1 ){
			break;
		}
		/* 最後にコピーした一文字 */
		work->lastChar = cbuf[csize-1];
		/* あと何byteあるか */
		size -= csize;
		csize = ( size < CBUFSIZE ) ?size :CBUFSIZE;
	}
	#ifdef DEBUG
	printf(" __EIN_rsmCopyF: lastChar =%x\n", work->lastChar);
	#endif
	return ( (size>0) ?ERROR :NOERR );
}

/*======================================================================
*	int		__EIN_rsmCopyR( EIN_RSMWORK *work )
*
*	【概  要】	現在のファイルポインタからファイル終端までコピー
*
*	【機  能】	
*
*	【入  力】	*work		:	ワークエリアへのポインタ
*
*	【出  力】
*
*	【関数値】	== NOERR	正常終了
*				== ERROR	異常終了
*
*	【注  意】	最後のバイトがEOFだったばあいはEOFはコピーしません
*
*	【参  照】	
*
*-----------------------------------------------------------------------
*	V11L10	1994.04.12/Nam
*=====================================================================*/
int		__EIN_rsmCopyR( EIN_RSMWORK *work )
{
	int		csize;
	
	work->lastChar = CHR_LF;
	
	for ( ; (csize=fread(cbuf, 1, CBUFSIZE, work->fp_r ))>0;  ){
		/* もし最後の1byteがEOFならコピーしない */
		if ( cbuf[csize-1]==CHR_EOF){
			csize--;
			#ifdef DEBUG
			printf("  最後の1byteがEOFなのでコピーしません\n");
			#endif
		}
		if ( csize > 0 ){
			if ( fwrite( cbuf, csize, 1, work->fp_w ) < 1 ){
				return ERROR;
			}
			/* 最後にコピーした一文字 */
			work->lastChar = cbuf[csize-1];
		}
	}
	#ifdef DEBUG
	printf(" __EIN_rsmCopyR: lastChar =%x\n", work->lastChar);
	#endif
	
	return NOERR;
}

/*======================================================================
*	int		__EIN_rsmTextWrite( EIN_RSMWORK *work, char *buf )
*
*	【概  要】	指定バッファをテキストモードでファイル書き出し
*
*	【機  能】	
*
*	【入  力】	*work		:	ワークエリアへのポインタ
*				*buf		:	書き出したいバッファ
*
*	【出  力】
*
*	【関数値】	== NOERR	正常終了
*
*	【注  意】	改行コードがLFの時はCRLFに自動変換します
*
*	【参  照】	
*
*-----------------------------------------------------------------------
*	V11L10	1994.04.12/Nam
*=====================================================================*/
int		__EIN_rsmTextWrite( EIN_RSMWORK *work, char *buf )
{
	int		size;
	char	*bp, *nbp, *limit;
	
	limit=buf+strlen(buf);
	#ifdef DEBUG
	printf("  strlen=%d  buf=%x  limit=%x\n", strlen(buf), buf, limit);
	#endif
	for ( bp=buf; ((nbp=strchr(bp,10))!=NULL); ){
		size = (nbp-bp)+1;
		strncpy(cbuf, bp, size);
		/* 改行変換 */
		if ( (size>1) &&
			 (cbuf[size-2]!=0x0d) && (cbuf[size-1]==0x0a) ){
			cbuf[size-1]=0x0d;
			cbuf[size  ]=0x0a;
			cbuf[size+1]=0;
			size++;
		}
		if ( fwrite( cbuf, size, 1, work->fp_w ) < 1 ){
			return ERROR;
		}
		#ifdef DEBUG
		printf("%x-%x (size:%d) %s", bp,nbp,size,cbuf);
		#endif
		bp=nbp+1;
		if (bp>=limit){
			break;
		}
	}
	return NOERR;
}

/*<Func>================================================================
*	int		EIN_rsmSave( EIN_RSMWORK *work )
*
*	【概  要】	リジュームデータのセーブ
*
*	【機  能】	
*
*	【入  力】
*				*idstr		:	サーチするデータブロックの認識文字列
*
*	【出  力】
*
*	【関数値】	== NOERR	正常終了
*
*	【注  意】	
*
*	【参  照】	
*
*-----------------------------------------------------------------------
*	V11L10	1994.04.12/Nam
*</Func>==============================================================*/
int		EIN_rsmSave( EIN_RSMWORK *work )
{
	int		size;
	char	buf[128];
	char	lf[4]="\n";

	/* お約束のErrorTrap */
	if (__EIN_rsmChkWork(work)!=NOERR){
		return ERROR;
	}
	if ( work->rbuf==NULL || work->rbufsize<16 ){
		#ifdef DEBUG
		printf("EIN_rsmSave: 書き込みバッファ未設定\n");
		#endif
		return ERROR;
	}
	/* バッファ末尾が"^A\n"でなければ追加 */
	EIN_rsmBufTail( work );
	/* まず置換元の位置とサイズを取得 */
	size=__EIN_rsmReadFile( work, 0 );
	#ifdef DEBUG
	printf("## old size=%d    newsize=%d   fstart=%d\n", size, work->rbufsize, work->fstart);
	#endif
	/* resumeファイルが無いなら新規作成(こりゃラクだ) */
	if ( size < 0 ){
		#ifdef DEBUG
		printf("## resumeファイルが無いなら新規作成(こりゃラクだ)\n");
		#endif
		work->fp_w = fopen( work->fname, "wb" );
		if (work->fp_w==NULL) {
			#ifdef DEBUG
			printf("\t: セーブファイルを開けません.\n");
			#endif
			return -1;
		}
		/* ヘッダ書き込み */
		strcpy(buf, RSMVER);
		__EIN_rsmTextWrite( work, buf );
		/* 中身書き込み */
		size=__EIN_rsmTextWrite( work, work->rbuf );
		fclose( work->fp_w );
		if ( size != NOERR ){
			#ifdef DEBUG
			printf("\t: 全部はセーブできませんでした.\n");
			#endif
			return -2;
		}
		return work->rbufsize;
	}
	/* リジュームファイルはありました。 */
	/* んじゃresumeファイルを書き換えるよ */
	/* まずバックアップファイルを作成 */
	work->fp_w = fopen( work->bname, "rb" );
	if (work->fp_w!=NULL) {
		/* 古いバックアップファイルを削除する */
		fclose( work->fp_w );
		if ( remove( work->bname ) != 0 ){
			#ifdef DEBUG
			printf("\t: 古いバックアップファイルを削除できませんでした.\n");
			#endif
			return -4;
		}
	}
	/* 現在のresumeファイルをバックアップ名にリネームする */
	if ( rename( work->fname, work->bname ) != 0 ){
		#ifdef DEBUG
		printf("\t: バックアップファイルを作成できませんでした.\n");
		#endif
		return -5;
	}
	/* んじゃ開始 */
	work->fp_r = fopen( work->bname, "rb" );
	work->fp_w = fopen( work->fname, "wb" );
	/* ファイル作成に失敗したら元に戻そうね */
	if ( (work->fp_r==NULL) || (work->fp_w==NULL) ){
		return __EIN_rsmCloseAndRename( work );
	}
	/* もし指定IDのデータが初めてなら */
	if ( size == 0 ){
		/* 元のファイルを終わりまでコピー */
		if ( __EIN_rsmCopyR( work ) != NOERR ){
			return __EIN_rsmCloseAndRename( work );
		}
		/* もし最後の1byteがLFでないなら改行しようね */
		if ( work->lastChar!=CHR_LF ){
			#ifdef DEBUG
			printf(" add LF\n");
			#endif
			if ( __EIN_rsmTextWrite( work, lf ) != NOERR ){
				return __EIN_rsmCloseAndRename( work );
			}
		}
		/* 最後にデータを書き込み */
		if ( work->rbufsize > 0 ){
			if (__EIN_rsmTextWrite( work, work->rbuf ) != NOERR){
				#ifdef DEBUG
				printf("\t: データの書き込みに失敗しました.\n");
				#endif
				return __EIN_rsmCloseAndRename( work );
			}
		}
	} else {
		/* 前の分をコピー */
		if ( work->fstart > 0 ){
			if ( __EIN_rsmCopyF( work, work->fstart ) != NOERR ){
				return __EIN_rsmCloseAndRename( work );
			}
		}
		#ifdef DEBUG
		printf("  前の分をコピーしました: (fp_r:%d  fp_w:%d)\n", ftell(work->fp_r), ftell(work->fp_w) );
		#endif
		/* 元ファイルの真ん中をseek */
		if ( size > 0 ){
			if ( fseek( work->fp_r, (long int)size, SEEK_CUR ) != 0 ){
				return __EIN_rsmCloseAndRename( work );
			}
		}
		#ifdef DEBUG
		printf("  SEEKしました          : (fp_r:%d  fp_w:%d)\n", ftell(work->fp_r), ftell(work->fp_w) );
		#endif
		/* もし最後の1byteがLFでないなら改行しようね */
		if ( work->lastChar!=CHR_LF ){
			#ifdef DEBUG
			printf(" add LF2\n");
			#endif
			if ( __EIN_rsmTextWrite( work, lf ) != NOERR ){
				return __EIN_rsmCloseAndRename( work );
			}
		}
		/* 真ん中を書き込み */
		if ( work->rbufsize > 0 ){
			if (__EIN_rsmTextWrite( work, work->rbuf ) != NOERR){
				#ifdef DEBUG
				printf("\t: データの書き込みに失敗しました.\n");
				#endif
				return __EIN_rsmCloseAndRename( work );
			}
		}
		#ifdef DEBUG
		printf("  データを書き込みました: (fp_r:%d  fp_w:%d)\n", ftell(work->fp_r), ftell(work->fp_w) );
		#endif
		/* 終わりまでコピー */
		if ( __EIN_rsmCopyR( work ) != NOERR ){
			return __EIN_rsmCloseAndRename( work );
		}
		/* もし最後の1byteがLFでないなら改行しようね */
		if ( work->lastChar!=CHR_LF ){
			#ifdef DEBUG
			printf(" add LF3\n");
			#endif
			if ( __EIN_rsmTextWrite( work, lf ) != NOERR ){
				return __EIN_rsmCloseAndRename( work );
			}
		}
	}
	/* 終了 */
	fclose( work->fp_r );
	fclose( work->fp_w );

	/* 保存エラーフラグを返す */
	return work->bufError;
}

/*<Func>================================================================
*	int		EIN_rsmGetDataSize( EIN_RSMWORK *work )
*
*	【概  要】	書き込まれているリジュームデータのbyte数を得る
*
*	【機  能】	
*
*	【入  力】	*work		:	ワークエリアへのポインタ
*
*	【出  力】
*
*	【関数値】	>0		正常終了(読み込んだbyte数を返す)
*				0		指定idのデータはなかった
*				<0		異常終了
*
*	【注  意】	
*
*	【参  照】	
*
*-----------------------------------------------------------------------
*	V11L10	1994.04.16/Nam
*</Func>==============================================================*/
int		EIN_rsmGetDataSize( EIN_RSMWORK *work )
{
	/* お約束のErrorTrap */
	if (__EIN_rsmChkWork(work)!=NOERR){
		return ERROR;
	}
	return __EIN_rsmReadFile( work, 0 );
}

/*<Func>================================================================
*	int		EIN_rsmLoad( EIN_RSMWORK *work )
*
*	【概  要】	リジュームデータのロード
*
*	【機  能】	
*
*	【入  力】	*work		:	ワークエリアへのポインタ
*
*	【出  力】
*
*	【関数値】	>0		正常終了(読み込んだbyte数を返す)
*				0		指定idのデータはなかった
*				<0		異常終了
*
*	【注  意】	あらかじめEIN_rsmBufSetでバッファを設定しておくこと
*
*	【参  照】	
*
*-----------------------------------------------------------------------
*	V11L10	1994.04.12/Nam
*</Func>==============================================================*/
int		EIN_rsmLoad( EIN_RSMWORK *work )
{
	/* お約束のErrorTrap */
	if (__EIN_rsmChkWork(work)!=NOERR){
		return ERROR;
	}
	if ( work->rbuf==NULL || work->rbufsize<16 ){
		#ifdef DEBUG
		printf("EIN_rsmLoad: 読み込みバッファ未設定\n");
		#endif
		return ERROR;
	}
	
	return __EIN_rsmReadFile( work, 1 );
}

/*<Func>================================================================
*	int		EIN_rsmBufCat( EIN_RSMWORK *work, char *str )
*
*	【概  要】	リジューム情報バッファにコピー
*
*	【機  能】	リジューム情報バッファに文字列を追加します
*
*	【入  力】	*work		:	ワークエリアへのポインタ
*				*str		:	コピーしたい文字列(0end)へのポインタ
*
*	【出  力】
*
*	【関数値】	== NOERR	正常終了
*				!= NOERR	異常終了
*
*	【注  意】	
*
*	【参  照】	
*
*-----------------------------------------------------------------------
*	V11L10	1994.04.18/Nam
*</Func>==============================================================*/
int		EIN_rsmBufCat( EIN_RSMWORK *work, char *str )
{
	register int	len;

	if (__EIN_rsmChkWork(work)!=NOERR){
		return ERROR;
	}
	if ( work->rbuf==NULL ){
		#ifdef DEBUG
		printf("EIN_rsmBufCat: バッファ指定が不正\n");
		#endif
		return ERROR;
	}
	len = strlen(str);
	if ( (len+strlen(str_lf)+1) > __EIN_rsmGetBufRemain(work) ){
		#ifdef DEBUG
		printf("EIN_rsmBufCat: バッファサイズ不足\n");
		#endif
		work->bufError = ERROR;
		return ERROR;
	}
	strcat( work->rbuf, str );
	/* もし最後の1byteがLFでないなら改行しようね */
	if ( str[len-1]!=CHR_LF ){
		strcat( work->rbuf, str_lf );	/* 最後にCRLFを追加 */
		#ifdef DEBUG
		printf("EIN_rsmBufCat: 最後の1byteがLFでないので改行します\n");
		#endif
	}

	return NOERR;
}

static int	__encDec( char *buf, char *nptr )
{
	register signed long	num = (long int)(nptr);
	register long			div, n;
	register char			len = 0, flag=0;
	/*
	printf("[%d", num);
	*/
	if ( num < 0 ){
		buf[len++] = '-';
		num = abs(num);
	}
	for ( div = 1000000000; div>=10; div/=10 ){
		if ( num>=div || flag!=0 ){
			n = num / div;
			num %= div;
			/*
			printf("@%d.%d", n, num );
			*/
			buf[len++] = n + '0';
			flag=1;
		}
	}
	buf[len++] = num + '0';
	buf[len] = 0;
	/*
	printf(":%dL]", len);
	*/
	return len;
}

static int	__encHex( char *buf, char *nptr )
{
	register signed long	num = (long int)(nptr);
	register long			div, n;
	register char			len = 0, flag=0;
	/*
	printf("[%d", num);
	*/
	if ( num < 0 ){
		buf[len++] = '-';
		num = abs(num);
	}
	for ( div = 0x10000000; div>=16; div=div/16 ){
		if ( num>=div || flag!=0 ){
			n = num / div;
			num %= div;
			/*
			printf("@%d.%d", n, num );
			*/
			buf[len++] = (n<10) ?(n+'0') :(n+55);
			flag=1;
		}
	}
	buf[len++] = (num<10) ?(num+'0') :(num+55);
	buf[len] = 0;
	/*
	printf(":%dL]", len);
	*/
	return len;
}

static int	__encStr( char *dst, char *src )
{
	register int		len;
	register char		ch;
	/*
	printf("[%s", src);
	*/
	for ( len=0; ; len++){
		ch = src[len];
		dst[len] = ch;
		if ( ch==0 ){
			break;
		}
	}
	/*
	printf(":%dL]", len);
	*/
	return len;
}

/*<Func>================================================================
*	int		EIN_rsmBufPrintf( EIN_RSMWORK *work, char *str,  )
*
*	【概  要】	リジューム情報バッファにprintf
*
*	【機  能】	リジューム情報バッファに文字列を追加します
*
*	【入  力】	*work		:	ワークエリアへのポインタ
*				*str		:	書式文字列
*				*p1,...		:	パラメータ
*
*	【出  力】
*
*	【関数値】	== NOERR	正常終了
*				!= NOERR	異常終了
*
*	【注  意】	%sと%dしか使えません(^^;)
*
*	【参  照】	
*
*-----------------------------------------------------------------------
*	V11L10	1994.04.18/Nam
*</Func>==============================================================*/
int		EIN_rsmBufPrintf( char *para, ... )
{
	EIN_RSMWORK *work;
	va_list	args;					/* 可変個引数 */
	char	*argv;
	char	*form;
	char	ch;
	int		len = 0;
	char	*bptr;

	/* 最初の引数はcountでつぶされるので,ここで取得しておく */
	work = (EIN_RSMWORK *)para;
	
	/* お約束のErrorTrap */
	if (__EIN_rsmChkWork(work)!=NOERR){
		return ERROR;
	}
	if ( work->rbuf==NULL ){
		#ifdef DEBUG
		printf("EIN_rsmBufPrintf: バッファ指定が不正\n");
		#endif
		return ERROR;
	}
	/* 現在のバッファ終端 */
	bptr = work->rbuf + strlen(work->rbuf);
	/* 可変個引数処理開始 */
	va_start( args, para );
	/* 2番目の引数はフォーマット文字列 */
	form = va_arg( args, char * );
	/*printf("work:%x  form:%s\n", work, form);*/
	/* バッファ残りチェック */
	if ( (strlen(form)) > __EIN_rsmGetBufRemain(work) ){
		#ifdef DEBUG
		printf("EIN_rsmBufPrintf: バッファサイズ不足\n");
		#endif
		work->bufError = ERROR;
		return ERROR;
	}
	/* フォーマット文字列を読みながら処理 */
	for ( len=0; (ch=form[len])!=0; len++ ){
		if ( ch!='%' ){
			bptr[0]=ch;
			bptr++;
		} else {
			len++;
			ch = form[len];
			if ( ch==0 ){
				break;
			}
			/* "%"の次のキャラクタ */
			switch ( ch ){
				/* "%%"だったら */
				case 0x25:
					bptr[0]=ch;
					bptr++;
					break;
				/* "%s"なら */
				case 0x73:
					argv = va_arg( args, char * );
					bptr += __encStr( bptr, argv );
					/*
					printf("##%s (0x%x)\n", argv, argv);
					*/
					break;
				/* "%d"なら */
				case 0x64:
					argv = va_arg( args, char * );
					bptr += __encDec( bptr, argv );
					/*
					printf("##%d\n", (long int)(argv), argv);
					*/
					break;
				/* "%x"なら */
				case 0x78:
					argv = va_arg( args, char * );
					bptr += __encHex( bptr, argv );
					/*
					printf("##%d\n", (long int)(argv), argv);
					*/
					break;
				default:
					break;
			}
		}
	}
	bptr[0]=0;
	va_end( args );
	/* 可変個引数処理終了 */

	/* もし最後の1byteがLFでないなら改行しようね */
	len = strlen(work->rbuf);
	if ( work->rbuf[len-1]!=CHR_LF ){
		strcat( work->rbuf, str_lf );	/* 最後にCRLFを追加 */
		#ifdef DEBUG
		printf("EIN_rsmBufPrintf: 最後の1byteがLFでないので改行します\n");
		#endif
	}

	return NOERR;
}

/* 単独テスト用 */
#ifndef EINLIB
void	main(int argc, char *argv[], char *envp[])
{
	EIN_RSMWORK	work;

	char	buf[128], str[80];
	char	*ptr;
	int		size,x,y, ret;

	printf("rsmbufsize=%d:\n", sizeof(work));

	/* リジュームマネージャの初期化 */
	EIN_rsmInit( &work, "%%%FOO 12345%%%" );
	/* バッファ設定 */
	EIN_rsmBufSet( &work, buf, 80 );
	/* リジューム情報読み込み */
	size = EIN_rsmLoad( &work );
	printf("read size: %d\n%s", size, buf);
	if ( ((ptr = strstr(buf,"ICON: ")) != NULL ) &&
		 (sscanf(ptr,"%s %d %x\n", &str, &x, &y) > 0 ) ){
		 printf("%d,%x", x,y);
	}

	/* リジュームマネージャの初期化 */
	EIN_rsmInit( &work, "%%%FOO 12345%%%" );
	/* バッファ設定 */
	EIN_rsmBufSet( &work, buf, 128 );
	/* バッファに文字列を追加 */
	EIN_rsmBufPrintf( (char *)&work, "ICON: %s %d %x", "foo", 10, 0x1234 );
	sprintf(str,"test of resumefile.");
	EIN_rsmBufCat( &work, str );
	/* バッファ終端(^L)設定 */
	EIN_rsmBufTail( &work );
	/* バッファをセーブ */
	ret = EIN_rsmSave( &work );
	printf("ret=%d\n", ret);

	exit( 0 );
}
#endif
