#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "c370.h"

void printhex( void *buf, int len )
{  int i;
   char *s = buf;
   while (len >= 0) {
      for (i=0;i < 16 && len >= 0; s++,i++,len--) {
         int ch = (*s) & 0xff;
         printf( "%3d ", ch );
      }
      printf( "\n" );
   }
   printf( "\n" );
}

#undef fseek
int myfseek( FILE *stream, long int offset, int origin )
{  int i;
   i = fseek( stream, offset, origin );
   if (i != 0 && origin == SEEK_CUR) {
      i = fseek( stream, ftell(stream) + offset, SEEK_SET );
      if (i != 0)
         printf("myfseek: ftell=%i, orig=%i, offset=%i, ret=%i\n",
                ftell(stream), origin, offset, i );
   }
   return i;
}

#undef fread
int myfread( void *buffer, size_t size, size_t count, FILE *stream )
{  size_t i;
   i = fread( buffer, size, count, stream );
   if (count == 1 && size == 1 && i == 1) {  /* skip padding zeroes */
      char ch = *(char *)buffer;
      fpos_t pos;
      fgetpos( stream, &pos );
      while ( ch == '\0' && fread(&ch, 1, 1, stream) == 1);
      fsetpos( stream, &pos );
      if (ch == '\0')
         return 0;
   }
   return i;
}

int      fileno( FILE *fp )
{
   return (int)fp;
}

int      access( const char *filename, int how )
{
   struct stat buf;
   return stat( filename, &buf );       /* dummy 'access' */
}

int      close( int fd )
{
   return fclose( (FILE *)fd );
}

int      isatty( int fd )
{
   return (fd==((int)stdin) || fd==((int)stdout) || fd==((int)stderr));
}

off_t    lseek( int fd, off_t offset, int whence )
{
   return fseek( (FILE *)fd, offset, whence );
}

size_t   read( int fd, void *buf, size_t size )
{
   return fread( buf, 1, size, (FILE *)fd );
}

int      unlink( char *filename )
{
   return remove( filename );
}

int      write( int fd, void *buf, size_t len )
{
   return fwrite( buf, 1, len, (FILE *)fd );
}

char dcb_flags[50];

static void access2mode( int access, char *mode)
{
   /* O_EXCL not supported */
   switch (access & ~(O_BINARY | O_MEMORY | O_EXCL | O_DCB)) {
      case O_RDONLY                       : strcpy( mode, "r" ); break;
      case O_RDWR                         : strcpy( mode, "r+" ); break;
      case O_WRONLY                       :
      case O_CREAT | O_WRONLY             : strcpy( mode, "w" ); break;
      case O_CREAT | O_RDWR               : strcpy( mode, "w+" ); break;
      case O_APPEND | O_WRONLY            :
      case O_APPEND | O_CREAT | O_WRONLY  : strcpy( mode, "a" ); break;
      case O_APPEND | O_RDWR              :
      case O_APPEND | O_CREAT | O_RDWR    : strcpy( mode, "a+" ); break;
      default                             : strcpy( mode, "" );
   }
   if (access & O_BINARY) strcat( mode, "b" );
   if (access & O_MEMORY) strcat( mode, ",type=memory" );
   if (access & O_RECORD) strcat( mode, ",type=record" );
   if (access & O_DCB) strcat( mode, dcb_flags );
}

int  open(const char *path, int access)
{
   char mode[30];
   FILE *f;
   access2mode( access, mode );
   f = fopen( path, mode );
   return (f == NULL ? -1 : fileno(f) );
}

int  eof( int fd )
{
    return feof( (FILE *)fd );
}

int  tell( int fd )
{
    return ftell( (FILE *)fd );
}

int  setmode(int fd, int access)
{
   char mode[30];
   FILE *f;

   switch (fd) {
      case 0: access |= O_RDONLY; fd = fileno(stdin);  break;
      case 1: access |= O_WRONLY; fd = fileno(stdout); break;
      case 2: access |= O_WRONLY; fd = fileno(stderr); break;
   }
   access2mode( access, mode );
   f = freopen( "", mode, (FILE *)fd );
   return (f == NULL ? -1 : fileno(f) );
}

int    chmod( const char* filename, mode_t mode )
{
   return 0;
}

int    stat(const char *filename, struct stat *buf )
{
   if ((buf->fp = fopen(filename, "r")) != NULL) {
      fldata_t fdata;
      if (fldata( buf->fp, buf->fname, &fdata ) == 0) {
         buf->st_dev  = fdata.__device;
         buf->st_mode = *(short *)(&fdata);
      }
      strcpy( buf->fname, filename );
      fseek( buf->fp, 0, SEEK_END );
      buf->st_size = ftell( buf->fp );
      fclose(buf->fp);
   }
   return (buf->fp != NULL ? 0 : -1);
}

int    fstat(int fd, struct stat *buf )
{
   fldata_t fdata;

   if ((fd != -1) && (fldata( (FILE *)fd, buf->fname, &fdata ) == 0))
   {
      buf->st_dev  = fdata.__device;
      buf->st_mode = *(short *)(&fdata);
      buf->fp      = (FILE *)fd;
      return 0;
   }
   return -1;
}


#define ALIAS_MASK  (unsigned int) 0x80
#define SKIP_MASK   (unsigned int) 0x1F
#define TTRLEN      3
#define RECLEN      254
typedef _Packed struct {
   unsigned short int count;
   char rest[RECLEN];
} RECORD;
char    *endmark = "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF";

static int gen_node( DIR *dirp, RECORD *recptr )
{
   char *ptr, *name, ttr[TTRLEN];
   int skip, count = 2;
   unsigned int info_byte, alias, ttrn;
   struct dirent *new;

   ptr = recptr->rest;
   while (count < recptr->count) {
      if (!memcmp( ptr, endmark, NAMELEN ))
         return 1;
      name = ptr;                    /* member name */
      ptr += NAMELEN;
      memcpy( ttr, ptr, TTRLEN );    /* ttr name    */
      ptr += TTRLEN;
      info_byte = (unsigned int) (*ptr);   /* info byte */
      if ( !(info_byte & ALIAS_MASK) ) {   /* no alias  */
         new = malloc( sizeof(struct dirent) );
         if (dirp->D_list == NULL)
            dirp->D_list = dirp->D_curpos = new;
         else
            dirp->D_curpos = (dirp->D_curpos->d_next = new);
         new->d_next = NULL;
         memcpy( new->d_name, name, NAMELEN );
         new->d_name[NAMELEN] = '\0';
         if ((name = strchr( new->d_name, ' ' )) != NULL)
            *name = '\0';      /* skip trailing blanks */
      }
      skip = (info_byte & SKIP_MASK) * 2 + 1;
      ptr += skip;
      count += (TTRLEN + NAMELEN + skip);
   }
   return 0;
}

DIR *opendir(const char *dirname)
{
   int bytes, list_end = 0;
   DIR *dirp;
   FILE *fp;
   RECORD rec;

   fp = fopen( dirname, "rb" );
   if (fp != NULL) {
      dirp = malloc( sizeof(DIR) );
      if (dirp != NULL) {
         dirp->D_list = dirp->D_curpos = NULL;
         strcpy( dirp->D_path, dirname );
         do {
            bytes = fread( &rec, 1, sizeof(rec), fp );
            if (bytes == sizeof(rec))
               list_end = gen_node( dirp, &rec );
         } while (!feof(fp) && !list_end);
         fclose( fp );
         dirp->D_curpos = dirp->D_list;
         return dirp;
      }
      fclose( fp );
   }
   return NULL;
}

struct dirent *readdir(DIR *dirp)
{
   struct dirent *cur;

   cur = dirp->D_curpos;
   if (cur != NULL)
      dirp->D_curpos = cur->d_next;
   return cur;
}

void rewinddir(DIR *dirp)
{
   dirp->D_curpos = dirp->D_list;
}

int closedir(DIR *dirp)
{
   struct dirent *node;

   while (dirp->D_list != NULL) {
      node = dirp->D_list;
      dirp->D_list = dirp->D_list->d_next;
      free( node );
   }
   free( dirp );
   return 0;
}




/* ebcdic-ascii converting, accustom to your local MVS-settings */

unsigned char ebcdic_ascii[] = {
	0x00,0x00,0x00,0x00,0x00,0x09,0x00,0x00, 0x00,0x00,0x00,0x0b,0x0c,0x0d,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x0a,0x08,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x2e,0x3c,0x28,0x2b,0x7c,
	0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x21,0x24,0x2a,0x29,0x3b,0x5e,
	0x2d,0x2f,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x7c,0x2c,0x25,0x5f,0x3e,0x3f,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x60,0x3a,0x23,0x40,0x27,0x3d,0x22,
	0x00,0x61,0x62,0x63,0x64,0x65,0x66,0x67, 0x68,0x69,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70, 0x71,0x72,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x7e,0x73,0x74,0x75,0x76,0x77,0x78, 0x79,0x7a,0x00,0x00,0x00,0x5b,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x5d,0x00,0x00,
	0x7b,0x41,0x42,0x43,0x44,0x45,0x46,0x47, 0x48,0x49,0x00,0x00,0x00,0x00,0x00,0x00,
	0x7d,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50, 0x51,0x52,0x00,0x00,0x00,0x00,0x00,0x00,
	0x5c,0x00,0x53,0x54,0x55,0x56,0x57,0x58, 0x59,0x5a,0x00,0x00,0x00,0x00,0x00,0x00,
	0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37, 0x38,0x39,0x00,0x00,0x00,0x00,0x00,0x00
};

unsigned char ascii_ebcdic[] = {
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2f, 0x16,0x05,0x15,0x0b,0x0c,0x0d,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x40,0x5a,0x7f,0x7b,0x5b,0x6c,0x50,0x7d, 0x4d,0x5d,0x5c,0x4e,0x6b,0x60,0x4b,0x61,
	0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7, 0xf8,0xf9,0x7a,0x5e,0x4c,0x7e,0x6e,0x6f,
	0x7c,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7, 0xc8,0xc9,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,
	0xd7,0xd8,0xd9,0xe2,0xe3,0xe4,0xe5,0xe6, 0xe7,0xe8,0xe9,0xad,0xe0,0xbd,0x5f,0x6d,
	0x79,0x81,0x82,0x83,0x84,0x85,0x86,0x87, 0x88,0x89,0x91,0x92,0x93,0x94,0x95,0x96,
	0x97,0x98,0x99,0xa2,0xa3,0xa4,0xa5,0xa6, 0xa7,0xa8,0xa9,0xc0,0x6a,0xd0,0xa1,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};

void ebcdic2ascii( unsigned char *buf, unsigned size )
{
   while (size--)
     *(buf+size) = ebcdic_ascii[ *(buf+size) ];
}

void ascii2ebcdic( unsigned char *buf, unsigned size )
{
   while (size--)
     *(buf+size) = ascii_ebcdic[ *(buf+size) ];
}

