/* MOVE file [arg1] contiguously {to block [arg2] bzw. [arg2,rvn2]} */

#include stdlib
#include stddef
#include string
#include stdio
#include assert

#include fab
#include nam

#include descrip
typedef struct dsc$descriptor DESCR;

typedef	struct Fid {
	unsigned short num;
	unsigned short seq;
	unsigned char rvn;
	unsigned char nmx;
} FID;

#include <fibdef>
#define	FIB$L_ACCTL	0
#define	FIB$W_FID	4
#define	FIB$W_DID	10
#define	FIB$W_EXCTL	22
#define	FIB$B_ALOPTS	32
#define	FIB$B_ALALIGN	33
#define	FIB$W_LOC_FID	34
#define	FIB$L_LOC_ADDR	40
#define	FIB$L_MOV_SVBN	64
#define	FIB$L_MOV_VBNCNT	68
#define	FIB$C_LENGTH	72
#define	FIB$M_NOPLACE	16384
#define	FIB$M_ALCON	1
#define	FIB$M_EXACT	1
#define	FIB$C_LBN	2
typedef struct Fib {	/* stub, only what's needed */
	/* unsigned char fill0[FIB$L_ACCTL]; */
	unsigned int acctl;
	/* unsigned char fill1[FIB$W_FID - FIB$L_ACCTL - sizeof(int)]; */
	FID fid;
	FID did;
	unsigned char fill2[FIB$W_EXCTL - FIB$W_DID - sizeof(FID)];
	unsigned short exctl;
	unsigned char fill3[FIB$B_ALOPTS - FIB$W_EXCTL - sizeof(short)];
	unsigned char alopts;
	/* unsigned char fill4[FIB$B_ALALIGN - FIB$B_ALOPTS - sizeof(char)]; */
	unsigned char alalign;
	/* unsigned char fill5[FIB$W_LOC_FID - FIB$B_ALALIGN - sizeof(char)]; */
	FID loc_fid;
	/* unsigned char fill6[FIB$L_LOC_ADDR - FIB$W_LOC_FID - sizeof(FID)]; */
	unsigned int loc_addr;
	unsigned char fill7[FIB$L_MOV_SVBN - FIB$L_LOC_ADDR - sizeof(int)];
	unsigned int mov_svbn;
	/* unsigned char fill8[FIB$L_MOV_VBNCNT - FIB$L_MOV_SVBN - sizeof(int)]; */
	unsigned int mov_vbncnt;
	/* unsigned char fill9[FIB$C_LENGTH - FIB$L_MOV_VBNCNT - sizeof(int)]; */
} FIB;

extern void lib$stop();
extern unsigned sys$qiow();
extern unsigned sys$open();

				/* IODEF.H doesn't have MOVEFILE yet */
globalvalue IO$_DEACCESS,IO$_MODIFY,IO$M_MOVEFILE;

#ifndef NULL
#define NULL ((void *) 0)
#endif

#define CHECKV(k) if((k&1) == 0) lib$stop(k)
#define CHECK(k) {unsigned status = k; CHECKV(status);}
#define ZERO1(arr,len) memset(arr,0,(len))

/*****/

main(argc,argv)
int argc; char **argv;
{
	static struct NAM rmsnam;
	static struct FAB rmsfab;
	static char rsfile[NAM$C_MAXRSS],exfile[NAM$C_MAXRSS];
	static FIB fib;
	DESCR fibdsc = {sizeof(fib),0,0,&fib};
	unsigned short chan,iosb[4];
	int arg2c,arg2n1,arg2n2;


	assert(FIB$L_ACCTL == 0);
	assert(FIB$W_FID - FIB$L_ACCTL - sizeof(int) == 0);
	assert(FIB$B_ALALIGN - FIB$B_ALOPTS - sizeof(char) == 0);
	assert(FIB$W_LOC_FID - FIB$B_ALALIGN - sizeof(char) == 0);
	assert(FIB$L_LOC_ADDR - FIB$W_LOC_FID - sizeof(FID) == 0);
	assert(FIB$L_MOV_VBNCNT - FIB$L_MOV_SVBN - sizeof(int) == 0);
	assert(FIB$C_LENGTH - FIB$L_MOV_VBNCNT - sizeof(int) == 0);


	if(argc < 2) {
		printf("Usage: MOVEF1 file [lbn[,rvn]]\n");
		exit(2);
	}
	if(argc < 3) {
		arg2c = 0;
	} else {
		arg2c = sscanf(argv[2],"%d,%d",&arg2n1,&arg2n2);
		if(arg2c != 1 && arg2c != 2) {
			printf("bad arg2\n");
			exit(2);
		}
	}

	rmsnam = cc$rms_nam;
	rmsnam.nam$l_esa = exfile;
	rmsnam.nam$b_ess = sizeof(exfile);
	rmsnam.nam$l_rsa = rsfile;
	rmsnam.nam$b_rss = sizeof(rsfile);
	rmsfab = cc$rms_fab;
	rmsfab.fab$l_nam = &rmsnam;
	rmsfab.fab$l_fna = argv[1];
	rmsfab.fab$b_fns = strlen(argv[1]);
	rmsfab.fab$l_fop = FAB$M_UFO;

	CHECK(sys$open(&rmsfab));

	chan = rmsfab.fab$l_stv;

	ZERO1(&fib,sizeof(fib));

	CHECK(sys$qiow(0,chan,IO$_DEACCESS,		/* "close" */
			       &iosb,0,0,
			       &fibdsc,0,0,0,0,0));
	CHECK(iosb[0]);


	printf("Moving file %.*s",rmsnam.nam$b_rsl,rsfile);

	ZERO1(&fib,sizeof(fib));
	lib$movc3(&sizeof(FID),&(rmsnam.nam$w_fid[0]),&fib.fid);

	fib.exctl = FIB$M_ALCON | FIB$M_NOPLACE;

	if(arg2c >= 1) {
		fib.alopts = FIB$M_EXACT;
		fib.alalign = FIB$C_LBN;
		if(arg2c >= 2) {
			fib.loc_fid.rvn = arg2n2;
		} else {
			fib.loc_fid.rvn = fib.fid.rvn;
		}
		fib.loc_addr = arg2n1;

		printf(" => LBN %d, RVN %d\n",
			fib.loc_addr,fib.loc_fid.rvn);
	}

	fib.mov_svbn = 1;
	fib.mov_vbncnt = 0;

	printf("\n");

	CHECK(sys$qiow(0,chan,IO$_MODIFY | IO$M_MOVEFILE,
			       &iosb,0,0,
			       &fibdsc,0,0,0,0,0));
	CHECK(iosb[0]);
}
