/*
 * File vms.c - assorted bletcherous hacks for VMS.

   Written by Eric Youngdale (1993).

 */

#ifdef VMS
#include <rms.h>
#include <descrip.h>
#include <ssdef.h>
#include <sys/types.h>
#include <sys/stat.h>
#define opendir fake_opendir
#include "mkisofs.h"
#undef opendir
#include <stdio.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);

char * strdup(char * source){
  char * pnt;
  pnt = (char *) e_malloc(strlen(source) + 1);
  strcpy(pnt, source);
  return pnt;
}

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(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, int size, FILE * outfile){
	int status, i;
	char buffer[SECTOR_SIZE * NSECT];
	int count;
	int use;
	int 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
