/* $Id: vms.c,v 1.11 1999/06/22 12:32:07 levitte Exp $ */

/* This file contains all the VMS-specific things we might need */

#include "gnu_extras.h"

#include <string.h>
#include <descrip.h>
#include <ttdef.h>
#include <iodef.h>
#include <stsdef.h>
#include <syidef.h>
#include <lib$routines.h>
#include <starlet.h>
#include "fish.h"
#include "vms.h"
#include "util.h"

/* TTY specific things */

tty_s *tty_open(const char *name, int *status)
{
    tty_s *tty = xmalloc(sizeof(tty_s));
    tty->name.dsc$w_length = strlen(name);
    tty->name.dsc$b_dtype = DSC$K_DTYPE_T;
    tty->name.dsc$b_class = DSC$K_CLASS_S;
    tty->name.dsc$a_pointer = xstrdup(name);
    *status = sys$assign(&(tty->name),&(tty->channel),0,0);
    if (!(*status & 1)) {
	xfree(tty);
    }
    return tty;
}
int tty_close(tty_s *tty, int *status)
{
    sys$dassgn(tty->channel);
    tty_release(tty,status);
    return 1;
}
int tty_release(tty_s *tty, int *status)
{
    xfree(tty->name.dsc$a_pointer);
    xfree(tty);
    return 1;
}

int tty_io_cancel(tty_s *tty, int *status)
{
    return (*status = sys$cancel(tty->channel)) & 1;
}

tty_s *tty_dup(tty_s *tty)
{
    tty_s *tty2 = xmalloc(sizeof(tty_s));
    memcpy(tty2, tty, sizeof(tty_s));
    tty2->name.dsc$a_pointer = xstrdup(tty->name.dsc$a_pointer);
    return tty2;
}

int tty_setflags(tty_s *tty, int flags, int flags2, int *status)
{
    tty->tty_char.basic_chars |= flags;
    tty->tty_char.extended_chars |= flags2;
    return 1;
}

int tty_clearflags(tty_s *tty, int flags, int flags2, int *status)
{
    tty->tty_char.basic_chars &= ~(flags);
    tty->tty_char.extended_chars &= ~(flags2);
    return 1;
}

int tty_copychar(tty_s *tty, tty_s *from)
{
    memcpy(&tty->tty_char,&from->tty_char,sizeof(from->tty_char));
    return 1;
}

int tty_sensemode(tty_s *tty, int *status)
{
    return (*status = sys$qiow(0, tty->channel, IO$_SENSEMODE, 0, 0, 0,
			       &tty->tty_char, sizeof(tty->tty_char),
			       0, 0, 0, 0)) & 1;
}

int tty_setmode(tty_s *tty, int *status)
{
    return (*status = sys$qiow(0, tty->channel, IO$_SETMODE, 0, 0, 0,
			       &tty->tty_char, sizeof(tty->tty_char),
			       0, 0, 0, 0)) & 1;
}

tty_s *tty_noecho(const char *name, int *status)
{
    tty_s *tty = tty_open(name, status);
    tty_s *tty2 = 0;
    int dummy;
    if (!tty_sensemode(tty, status)) {
	tty_release(tty, &dummy);
	tty_close(tty2, &dummy);
	return 0;
    }
    tty2 = tty_dup(tty);
    tty_setflags(tty,TT$M_NOECHO,0,&dummy);
    if (!tty_setmode(tty, status)) {
	tty_release(tty, &dummy);
	tty_close(tty2, &dummy);
	return 0;
    }
    tty_release(tty, &dummy);
    return tty2;
}

tty_s *tty_echo(const char *name, int *status)
{
    tty_s *tty = tty_open(name, status);
    tty_s *tty2 = 0;
    int dummy;
    if (!tty_sensemode(tty, status)) {
	tty_release(tty, &dummy);
	tty_close(tty2, &dummy);
	return 0;
    }
    tty2 = tty_dup(tty);
    tty_clearflags(tty,TT$M_NOECHO,0,&dummy);
    if (!tty_setmode(tty, status)) {
	tty_release(tty, &dummy);
	tty_close(tty2, &dummy);
	return 0;
    }
    tty_release(tty, &dummy);
    return tty2;
}

int read_prompted(const char *name, const char *prompt,
		  char *bufaddr, unsigned long bufsize,
		  int purged, int echo, int *status)
{
    tty_s *tty = tty_open(name, status);
    int dummy;
    int function = (purged ? IO$M_PURGE : 0) | (echo ? 0 : IO$M_NOECHO)
	| IO$_READPROMPT;
    unsigned long buflen;
    struct {
	unsigned short status;
	unsigned short buflen;
	unsigned short terminator;
	unsigned short terminatorsize;
    } iosb;
    struct itemlist3 {
	unsigned short buflen;
	unsigned short itemcode;
	void *bufaddr;
	unsigned long *resultlen;
    } il3[] = {
	{ 0, SYI$_MAXBUF, 0, 0 },
	{ 0, 0, 0, 0 },
	};

    il3[0].buflen = sizeof(dummy);
    il3[0].bufaddr = &dummy;
    il3[0].resultlen = 0;
    *status = sys$getsyiw(0, 0, 0, il3, 0, 0, 0);
    if (bufsize > dummy)
	bufsize = dummy;

    /* The logic above should give me what I want, but doesn't, so let's
       settle for something low. */
    if (bufsize > 500)
	bufsize = 500;

    *status = sys$qiow(0, tty->channel, function, &iosb, 0, 0,
		       /* P1 */ bufaddr,
		       /* P2 */ bufsize,
		       /* P3 */ 0,
		       /* P4 */ 0,
		       /* P5 */ prompt,
		       /* P6 */ strlen(prompt));
    tty_close(tty, &dummy);
    tty_release(tty, &dummy);
    if (!$VMS_STATUS_SUCCESS(*status))
	lib$signal(*status);

    *status = iosb.status;
    bufaddr[iosb.buflen] = '\0';
    return $VMS_STATUS_SUCCESS(*status);
}

/* C correspondents to certain VMS routines */

/* like lib$put_output(), but takes a NUL-terminated char* instead of a string
   descriptor */
int lib_put_output(char *str)
{
    struct dsc$descriptor_s dsc;

    dsc.dsc$b_dtype = DSC$K_DTYPE_T;
    dsc.dsc$b_class = DSC$K_CLASS_S;
    dsc.dsc$w_length = strlen(str);
    dsc.dsc$a_pointer = str;

    return lib$put_output(&dsc);
}

/* Emacs local variables

Local variables:
eval: (set-c-style "BSD")
end:

*/
