/*
 * This file has been modified for the cdrkit suite.
 *
 * The behaviour and appearence of the program code below can differ to a major
 * extent from the version distributed by the original author(s).
 *
 * For details, see Changelog file distributed with the cdrkit package. If you
 * received this file from another source then ask the distributing person for
 * a log of modifications.
 *
 */

/* @(#)vms.c	1.9 04/03/04 joerg */
/*
 * File vms.c - assorted bletcherous hacks for VMS.
 *
 * Written by Eric Youngdale (1993).
 *
 */

#include <mconfig.h>
#ifdef VMS
#define	opendir	fake_opendir
#include "genisoimage.h"
#undef opendir
#include <rms.h>
#include <descrip.h>
#include <ssdef.h>

static struct RAB	*rab;		/* used for external mailfiles */
static int		rms_status;

static
error_exit(char *text)
{
	fprintf(stderr, "%s\n", text);
	exit(33);
}


char *strrchr(const char *, char);

int
VMS_stat(char *path, struct stat * spnt)
{
	char		*spath;
	char		sbuffer[255];
	char		*pnt,
			*ppnt;
	char		*pnt1;

	ppnt = strrchr(path, ']');
	if (ppnt)
		ppnt++;
	else
		ppnt = path;

	spath = path;

	if (strcmp(ppnt, ".") == 0 || strcmp(ppnt, "..") == 0) {
		strcpy(sbuffer, path);

		/* Find end of actual name */
		pnt = strrchr(sbuffer, ']');
		if (!pnt)
			return (0);

		pnt1 = pnt;
		while (*pnt1 != '[' && *pnt1 != '.')
			pnt1--;

		if (*pnt1 != '[' && strcmp(ppnt, "..") == 0) {
			pnt1--;
			while (*pnt1 != '[' && *pnt1 != '.')
				pnt1--;
		};

		if (*pnt1 == '.') {
			*pnt1 = ']';
			pnt = pnt1;
			while (*pnt != '.' && *pnt != ']')
				pnt++;
			*pnt++ = ']';
			while (*pnt != '.' && *pnt != ']')
				pnt++;
			*pnt = 0;
			strcat(sbuffer, ".DIR;1");
		};

		if (*pnt1 == '[') {
			pnt1++;
			*pnt1 = 0;
			strcat(pnt1, "000000]");
			pnt1 = strrchr(path, '[') + 1;
			pnt = sbuffer + strlen(sbuffer);
			while (*pnt1 && *pnt1 != '.' && *pnt1 != ']')
				*pnt++ = *pnt1++;
			*pnt = 0;
			strcat(sbuffer, ".DIR;1");
		};

		spath = sbuffer;
	};
	return (stat_filter(spath, spnt));
}

static int		dircontext[32] = {0, };
static char		*searchpath[32];
static struct direct	d_entry[32];

int			optind = 0;
char			*optarg;

int
getopt(int argc, char *argv[], char *flags)
{
	char		*pnt;
	char		c;

	optind++;
	if (*argv[optind] != '-')
		return (EOF);
	optarg = 0;

	c = *(argv[optind] + 1);
	pnt = (char *) strchr(flags, c);
	if (!pnt)
		return (c);	/* Not found */
	if (pnt[1] == ':') {
		optind++;
		optarg = argv[optind];
	};
	return (c);
}

void
vms_path_fixup(char *name)
{
	char		*pnt1;

	pnt1 = name + strlen(name) - 6;

	/* First strip the .DIR;1 */
	if (strcmp(pnt1, ".DIR;1") == 0)
		*pnt1 = 0;

	pnt1 = (char *) strrchr(name, ']');
	if (pnt1) {
		if (pnt1[1] == 0)
			return;
		*pnt1 = '.';
		strcat(name, "]");
		return;
	};
	pnt1 = (char *) strrchr(name, '>');
	if (pnt1) {
		if (pnt1[1] == 0)
			return;
		*pnt1 = '.';
		strcat(name, ">");
		return;
	};
}

int
opendir(char *path)
{
	int		i;

	for (i = 1; i < 32; i++) {
		if (dircontext[i] == 0) {
			dircontext[i] = -1;
			searchpath[i] = (char *) e_malloc(strlen(path) + 6);
			strcpy(searchpath[i], path);
			vms_path_fixup(searchpath[i]);
			strcat(searchpath[i], "*.*.*");
			return (i);
		};
	};
	exit(0);
}

struct direct  *
readdir(int context)
{
	int		i;
	char		cresult[100];
	char		*pnt;
	int		status;

	$DESCRIPTOR(dpath, searchpath[context]);
	$DESCRIPTOR(result, cresult);

	if (dircontext[context] == -1) {
		dircontext[context] = -2;
		strcpy(d_entry[context].d_name, ".");
		return (&d_entry[context]);
	};

	if (dircontext[context] == -2) {
		dircontext[context] = -3;
		strcpy(d_entry[context].d_name, "..");
		return (&d_entry[context]);
	};

	if (dircontext[context] == -3)
		dircontext[context] = 0;

	dpath.dsc$w_length = strlen(searchpath[context]);
	lib$find_file(&dpath, &result, &dircontext[context],
		0, 0, &status, 0);

	if (status == SS$_NOMOREFILES)
		return (0);

	/* Now trim trailing spaces from the name */
	i = result.dsc$w_length - 1;
	while (i && cresult[i] == ' ')
		i--;
	cresult[i + 1] = 0;

	/* Now locate the actual portion of the file we want */

	pnt = (char *) strrchr(cresult, ']');
	if (pnt)
		pnt++;
	else
		pnt = cresult;

	strcpy(d_entry[context].d_name, pnt);
	return (&d_entry[context]);
}

void
closedir(int context)
{
	lib$find_file_end(&dircontext[context]);
	free(searchpath[context]);
	searchpath[context] = (char *) 0;
	dircontext[context] = 0;
}

static
open_file(char *fn)
{
	/*
	 * this routine initializes a rab and  fab required to get the
	 * correct definition of the external data file used by mail
	 */
	struct FAB	*fab;

	rab = (struct RAB *) e_malloc(sizeof (struct RAB));
	fab = (struct FAB *) e_malloc(sizeof (struct FAB));

	*rab = cc$rms_rab;	/* initialize RAB */
	rab->rab$l_fab = fab;

	*fab = cc$rms_fab;	/* initialize FAB */
	fab->fab$l_fna = fn;
	fab->fab$b_fns = strlen(fn);
	fab->fab$w_mrs = 512;
	fab->fab$b_fac = FAB$M_BIO | FAB$M_GET;
	fab->fab$b_org = FAB$C_SEQ;
	fab->fab$b_rfm = FAB$C_FIX;
	fab->fab$l_xab = (char *) 0;

	rms_status = sys$open(rab->rab$l_fab);
	if (rms_status != RMS$_NORMAL && rms_status != RMS$_CREATED)
		error_exit("$OPEN");
	rms_status = sys$connect(rab);
	if (rms_status != RMS$_NORMAL)
		error_exit("$CONNECT");
	return (1);
}

static
close_file(struct RAB * prab)
{
	rms_status = sys$close(prab->rab$l_fab);
	free(prab->rab$l_fab);
	free(prab);
	if (rms_status != RMS$_NORMAL)
		error_exit("$CLOSE");
}

#define	NSECT 16
extern unsigned int last_extent_written;

int
vms_write_one_file(char *filename, off_t size, FILE * outfile)
{
	int		status,
			i;
	char		buffer[SECTOR_SIZE * NSECT];
	int		count;
	int		use;
	off_t		remain;

	open_file(filename);

	remain = size;

	while (remain > 0) {
		use = (remain > SECTOR_SIZE * NSECT - 1 ? NSECT * SECTOR_SIZE : remain);
		use = ROUND_UP(use);	/* Round up to nearest sector boundary */
		memset(buffer, 0, use);
		rab->rab$l_ubf = buffer;
		rab->rab$w_usz = sizeof (buffer);
		status = sys$read(rab);
		fwrite(buffer, 1, use, outfile);
		last_extent_written += use / SECTOR_SIZE;
		if ((last_extent_written % 1000) < use / SECTOR_SIZE)
			fprintf(stderr, "%d..", last_extent_written);
		remain -= use;
	};

	close_file(rab);
}

#endif
