/*
 *  Project   : tin - a Usenet reader
 *  Module    : win32.c
 *  Author    : S. Lam, D. Derbyshire, T. Loebach
 *  Created   : 01-06-87
 *  Updated   : 05-07-93
 *  Notes     : Berkeley-style directory reading routine on Windows NT
 *  Copyright : (c) Copyright 1987-93 by Sam Lam, Drew Derbyshire, Tom Loebach
 *              You may  freely  copy or  redistribute  this software,
 *              so  long as there is no profit made from its use, sale
 *              trade or  reproduction.  You may not change this copy-
 *              right notice, and it must be included in any copy made
 */

#include "tin.h"

#if defined(WIN32)

#include <assert.h>

/*
 * Windows/NT include files
 */

#define INCL_BASE

#include <WINDOWS.h>
#include <time.h>


/*
 * UUPC/extended include files
 */

#include "win32.h"

#define ERR(s, c)	if(opterr) {\
	    fprintf(stderr, "%s%s%c\n", argv[0], s, c);}

int currentfile ();

static char *pathname = NULL;
static HANDLE dirHandle;
static WIN32_FIND_DATA dirData;
HANDLE coni_handle;
HANDLE cono_handle;

int	opterr = 1;
int	optind = 1;
int	optopt;
char *optarg;

/*
 * Open a directory
 */

DIR *
opendirx (
	const char *dirname, 
	char *pattern)
{
	DIR *dirp;

	pathname = malloc (strlen (dirname) + strlen (pattern) + 2);
	strcpy (pathname, dirname);

	if ((*pattern != '\\') || (dirname[strlen (dirname) - 1] != '\\')) {
		strcat (pathname, "\\");
	}

	strcat (pathname, pattern);

	/*
	 * Read the first file in the directory
	 */
	dirHandle = FindFirstFile (pathname, &dirData);

	if ((int) dirHandle == -1) {
		return NULL;
	} else {
		dirp = malloc (sizeof (DIR));
		dirp->dirfirst = 1;
		strcpy (dirp->dirid, "DIR");
		return dirp;
	}
}

/*
 * Get next entry in a directory
 */

struct direct *
readdir (
	DIR *dirp)
{
	BOOL rc;

	assert(strcmp (dirp->dirid, "DIR") == 0);
	if (dirp->dirfirst) {
		dirp->dirfirst = 0;
	} else {
		rc = FindNextFile (dirHandle, &dirData);
	}

	if (! strcmp (dirData.cFileName, ".")) {
		rc = FindNextFile (dirHandle, &dirData);
	}

	if (! strcmp (dirData.cFileName, "..")) {
		rc = FindNextFile (dirHandle, &dirData);
	}

	if (rc) {
		dirp->dirent.d_ino = -1;   /* no inode information */
		strlwr (strcpy (dirp->dirent.d_name, dirData.cFileName));
		dirp->dirent.d_namlen = strlen (dirData.cFileName);
		dirp->dirent.d_reclen = sizeof (struct direct) - (MAXNAMLEN + 1) +
			((((dirp->dirent.d_namlen + 1) + 3) / 4) * 4);
		return &(dirp->dirent);
	} else {
		return NULL;
	}
}

/*
 * Close a directory
 */

void 
closedir (
	DIR *dirp)
{
	BOOL rc;
   
	assert(strcmp (dirp->dirid, "DIR") == 0);

	rc = FindClose (dirHandle);

	free (dirp);
	dirp = NULL;
	free (pathname);
	pathname = NULL;
}

/*
 * Pretend to do a fork and pipe
 */

FILE *
popen (
	char *cmd, 
	char *mode)
{
	HANDLE	rd_hnd;
	HANDLE	wr_hnd;
	HANDLE	old;
	SECURITY_ATTRIBUTES	security = {
		sizeof(SECURITY_ATTRIBUTES),
		NULL,
		TRUE
	};
    PROCESS_INFORMATION	procinfo;
    STARTUPINFO startup = {
		sizeof(STARTUPINFO),
		0,
		NULL,
		"Tin SubProcess",
		0, 0,
		0, 0,
		0, 0,
		0,
		0, 0,
		0, NULL
	};

	/* 
	 * First, create a pipe 
	 */
    
	if (! CreatePipe (&rd_hnd, &wr_hnd, &security, 0)) {
		return NULL;
	}

	/* 
	 * Swap the standard handle so it points to the pipe 
	 */
	if (strcmp (mode, "r") == 0) {
		old = cono_handle;
		SetStdHandle (STD_OUTPUT_HANDLE, wr_hnd);
	} else if (strcmp (mode, "w") == 0) {
		old = coni_handle;
		SetStdHandle (STD_INPUT_HANDLE, rd_hnd);
	}
    
	/* 
	 * Now fork off the process 
	 */
	if (! CreateProcess (NULL,
			cmd,
			NULL,		/* Process security */
			NULL,		/* Thread security */
			TRUE,		/* Inherit handles */
			0,			/* Create flags */
			NULL,		/* Default environment */
			NULL,		/* Directory */
			&startup,	/* Startup info */
			&procinfo)) {
		return NULL;
	}

	/* 
	 * Restore the original handles 
	 */
    if (strcmp (mode, "r") == 0) {
		CloseHandle (wr_hnd);
		SetStdHandle (STD_OUTPUT_HANDLE, old);
		return rd_hnd;
	} else if (strcmp (mode, "w") == 0) {
		CloseHandle (wr_hnd);
		SetStdHandle (STD_INPUT_HANDLE, old);
		return wr_hnd;
	}
}

/*
 * Sleep for n seconds
 */

int 
sleep (
	long	n)
{
    Sleep (n * CLOCKS_PER_SEC);
}

/*
 * Open a pipe
 */

int 
pipe (
	int *handles)
{
	HANDLE rd_hnd, wr_hnd;

	if (! CreatePipe (&rd_hnd, &wr_hnd, NULL, 0)) {
		return -1;
	}
    
	*handles++ = (int) rd_hnd;
	*handles   = (int) wr_hnd;

	return 0;
}

/*
 * Set default file access rights
 */

int 
umask (
	int newmask)
{
	return newmask;
}

/*
 * Create a directory
 */
    
int 
mkdir (
	char *name)
{
	if (CreateDirectory (name, NULL)) {
		return 0;
	} else {
		return -1;
	}
}

/*
 * Close a pipe
 */

int 
pclose (
	int fd)
{
	if (CloseHandle ((HANDLE)fd)) {
		return 0;
	} else {
		return -1;
	}
}

/*
 * get current process id
 */

long 
getpid ()
{
	return GetCurrentProcessId ();
}

/*
 * getgid	-	get group id
 * getuid	-	get user id
 * setgid	-	set group id
 * setuid	-	set user id
 * getegid	-	get effective group id
 * geteuid	-	get effective user id
 */

int 
getgid ()
{
	return 1;
}

int 
getuid ()
{
	return 1;
}

int 
setgid (
	int id)
{
	return 1;
}

int 
setuid (
	int id)
{
	return 1;
}

int 
getegid ()
{
	return 1;
}

int 
geteuid ()
{
	return 1;
}

/*
 * set new directory
 */

int 
chdir (
	char *dir)
{
	if (SetCurrentDirectory (dir)) {
		return 0;
	} else {
		return -1;
	}
}

/*
 * get current directory
 */

char *
getcwd (
	char *buf, 
	int len)
{
	GetCurrentDirectory (len, buf);
	return buf;
}

/*
 * can I access a file?
 */

int	
access (
	char *name, 
	int mode)
{
	long rights;
    
	rights = GetFileAttributes (name);
	
	if (rights == 0) {
		return -1;
	} else {
		return 0;
	}	
}

/*
 * set file access mode
 */

int 
chmod (
	char *name, 
	int mode)
{
	return 0;
}

/*
 * output a string
 */

tputs (
	char *str, 
	int number, 
	void (*routine)())
{
	long count;
	char *sptr;

	while (number-- > 0) {
		count = strlen (str);
		sptr = str;
		while (count-- > 0) {
			routine (*sptr++);
		}
	}
}

int 
getopt (argc, argv, opts)
	int	argc;
	char **argv;
	char *opts;
{
	static int sp = 1;
	register int c;
	register char *cp;

	if (sp == 1)
		if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0')
			return(EOF);
		else if (strcmp(argv[optind], "--") == 0) {
			optind++;
			return (EOF);
		}
	optopt = c = argv[optind][sp];
	if (c == ':' || (cp=strchr (opts, c)) == NULL) {
		ERR(": illegal option -- ", c);
		if(argv[optind][++sp] == '\0') {
			optind++;
			sp = 1;
		}
		return ('?');
	}
	if (*++cp == ':') {
		if (argv[optind][sp+1] != '\0')
			optarg = &argv[optind++][sp+1];
		else if (++optind >= argc) {
			ERR(": option requires an argument -- ", c);
			sp = 1;
			return ('?');
		} else
			optarg = argv[optind++];
		sp = 1;
	} else {
		if (argv[optind][++sp] == '\0') {
			sp = 1;
			optind++;
		}
		optarg = NULL;
	}
	return (c);
}

/*
 * Redirect all printf's to the console
 */

int 
printf (
	const char *fmt,
	...)
{
	va_list	ap;
	long count;
	static char	buff[2000];
    
	va_start (ap, fmt);
	vsprintf (buff, fmt, ap);
	WriteConsole (cono_handle, buff, strlen (buff), &count, 0);
}

/*
 * Redirect fputs's to the console
 */

int 
fputs (
	const char *str, 
	FILE *fd)
{
	long count;
	
	if (fd == stdout || fd == stderr) {
		WriteConsole (cono_handle, str, strlen (str), &count, 0);
	} else {
		fwrite (str, 1, strlen (str), fd);
	}

	return count;
}

/*
 * Redirect fputc's to the console
 */

int 
fputc (
	const char ch, 
	FILE *fd)
{
	long count;

	if(fd == stdout || fd == stderr) {
		WriteConsole (cono_handle, &ch, 1, &count, 0);
	} else {
		fwrite (&ch, 1, 1, fd);
	}

	return count;
}

#endif	/* WIN32 */
