#define I_IOCTL
#define I_ERRNO
#define I_TYPES

#include "includes.h"

#include "debug.h"

#ifdef SCO
#include <sys/socket.h>
#endif

int term_errno = 0;
/*-----------------------------------------------------------------------*/
void set_nonblock(int fd) {
#ifdef SCO
   int one = 1;
#endif
#ifdef USE_FCNTL
#ifdef USE_NONBLOCK
  if (!(fcntl (fd, F_GETFL) & O_NONBLOCK)) {
    fcntl (fd, F_SETFL, (fcntl(fd, F_GETFL) | O_NONBLOCK));
  }
#ifdef SCO
  ioctl(fd, FIONBIO, &one);
#endif
#else
  if (!(fcntl (fd, F_GETFL) & FNDELAY)) {
    fcntl (fd, F_SETFL, (fcntl(fd, F_GETFL) | FNDELAY));
  }
#endif
#else
  int one = 1;
  ioctl( fd, FIONBIO, &one);
#endif
}

void set_block(int fd) { 
#ifdef SCO
  int zero = 0;
#endif
#ifdef USE_FCNTL
#ifdef USE_NONBLOCK
  fcntl (fd, F_SETFL, (fcntl(fd, F_GETFL) & ~O_NONBLOCK));
#ifdef SCO
  ioctl(fd, FIONBIO, &zero);
#endif
#else
  fcntl (fd, F_SETFL, (fcntl(fd, F_GETFL) & ~FNDELAY));
#endif
#else
  int zero = 0;
  ioctl(fd, FIONBIO, &zero);
#endif
}
/*------------------------------------------------------------------------*/
/* Do a partial read into the buffer. */
int do_read_into_buff(int fd, struct Buffer *b, int size) {
  int r = 0, t;
  
  if (!size || size > b->alloced - 1 - b->size)
    size = b->alloced - 1 - b->size;
  term_errno = 0;
  t = b->alloced - b->start;
  if (t > size) t = size;
  r = read(fd, b->data + b->start, t);
  DEBUG_LL(stderr, "%s: d_r_i_b: read1 from %d (%d) did %d\n", 
	   term_server, fd, t, r);
  if (r <= 0)  {
    if (!r) term_errno = 1;
    else 
#ifndef SVR4
      if (errno != ERR_BLOCK)
#endif /* SVR4 */
        term_errno = errno + 1;
    return r;
  }
  
  b->start += r;
  b->size += r;
  SANITY(b->start <= b->alloced);
  if (b->start == b->alloced)
    b->start = 0;
  size -= r;
  if (!size || b->start != 0) return r;
  
  t = b->alloced - b->start;
  if (t > size) t = size;
  t = read(fd, b->data + b->start, t);
  DEBUG_LL(stderr, "%s: d_r_i_b: read2 from %d (%d) did %d\n", 
	   term_server, fd, t, t);
  if (t <= 0) {
    if (!t) term_errno = 1;
    else if(errno != ERR_BLOCK)
      term_errno = errno+1;
    return r;
  }
  
  b->start += t;
  b->size += t;
  if (b->start == b->alloced)
    b->start = 0;
  size -= t;
  r += t;
  return r;
}

/* Read from a file-descriptor into a ring buffer. Read atmost size bytes */
int read_into_buff(int fd, struct Buffer *b, int size) {
  int ret, l = 0;
  if (!size) size = b->alloced - 1 - b->size;

  do {
    ret = do_read_into_buff(fd, b, size);
    if (ret < 1) break;
    l += ret;
    size -= ret;
  } while (!term_errno && size);
  if (!l) return ret;
  return l;
}

/*------------------------------------------------------------------------*/
/* Write from ring buffer to file descriptor. Write at most size bytes    */

int write_from_buff(int fd, struct Buffer *b, int size) {
  int r = 0, t;
  if (!size) size = b->size;
  t = b->alloced - b->end;
  if (t > size) t = size;
  
  r = write(fd, b->data + b->end, t);
  DEBUG_LL(stderr, "%s: d_w_f_b: write1 from %d (%d) did %d\n", 
	   term_server, fd, t, r);
  if (r <= 0) {
    if (!r) term_errno = 1;
    else if (errno != ERR_BLOCK)
      term_errno = errno+1;
    return r;
  }

  b->end += r;
  b->size -= r;
  SANITY(b->end <= b->alloced);

  if (b->end >= b->alloced)
    b->end -= b->alloced;
  size -= r;
  if (!size || b->end != 0) 
    return r;
  
  t = b->alloced - b->end;
  if (t > size) t = size;
  t = write(fd, b->data + b->end, t);
  DEBUG_LL(stderr, "%s: d_w_f_b: write2 from %d (%d) did %d\n", 
	   term_server, fd, t, r);

  if (t <= 0) {
    if (!t) term_errno = 1;
    else if (errno != ERR_BLOCK)
      term_errno = errno+1;
    return r;
  }
  
  b->end += t;
  b->size -= t;
  SANITY(b->end <= b->alloced);
  if (b->end >= b->alloced)
    b->end -= b->alloced;
  r += t;
  return r;
}

#define BUFF_INC_SIZE 1024

int add_to_buffer(struct Buffer *B, un_char c)
{
  if (B->size >= B->alloced - 2) {
    
    DEBUG_LL (stderr, "growing buffer: add_to_buffer %d, %d\n",
	     B->size, B->alloced);

    if (!B->data || !B->alloced){
      B->data = (un_char *) malloc( B->alloced + BUFF_INC_SIZE );
      if(B->data==NULL){
         perror("Term: malloc");
         return -1;
      };
    }else if((B->data = (un_char *) realloc(B->data, B->alloced + BUFF_INC_SIZE)) == NULL){
      perror("Term: realloc");
      return -1;
    };
    B->alloced += BUFF_INC_SIZE;
    if (B->end > B->start) {	/* curses. need to move data. */
      int i; char *p, *q;
      p = (caddr_t)B->data + B->alloced - 1;
      q = (caddr_t)B->data + B->alloced - BUFF_INC_SIZE - 1;
      for (i = B->alloced - BUFF_INC_SIZE - B->end; i > 0; --i)
	*p-- = *q--;
      B->end += BUFF_INC_SIZE;
    }
  }
  B->data[B->start++] = (c);
  B->start == B->alloced ? B->start = 0 : 0; 
  B->size++;
  return 0;
}

int get_from_buffer(struct Buffer *b) {
  un_char c;
  if (b->size < 1)
    return -1;
  c = b->data[b->end++];
  --b->size;
  if (b->end >= b->alloced)
    b->end = 0;
  return (int) c&255;
}
/*-----------------------------------------------------------------------*/

	/* KLUDGE. suns always need stderr, so ignore the config.h if */
	/* it says otherwise. This is mostly just a sanity check */
#if !defined(USE_STRERROR) || defined(sun)
char *strerror(int errno) {
  extern char *sys_errlist[];
  
  return sys_errlist[errno];
}
#endif
