#ifndef lint
static char *RCSid = "$Id: w32cmd.c,v $";
#endif

/*
 *  The Regina Rexx Interpreter
 *  Copyright (C) 1995  Ataman Software, Inc. <info@ataman.com>
 *  Portions, Copyright (C) 1992-1994  Anders Christensen <anders@pvv.unit.no>
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public
 *  License along with this library; if not, write to the Free
 *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#define STRICT
#include <windows.h>

#include "rexx.h"
#include <sys/timeb.h>
#include <io.h>

unsigned int sleep(unsigned int time_to_sleep)
{
	Sleep(time_to_sleep*1000);
	return(0);
}


int ftruncate( int fd, fpos_t pos )
{
	HANDLE h = (HANDLE)_get_osfhandle( fd ) ;
	if (SetFilePointer( h, pos, NULL, FILE_BEGIN) == 0xFFFFFFFF) {
		return -1;
	}	
	if ( !SetEndOfFile( h ) ) {
		return -1;
	}
	return 0;
}

/* Next 3 defines must be kept in sync with files.c */
#define COMMAND_READABLE    11
#define COMMAND_WRITABLE    12
#define COMMAND_EXECUTABLE  13

int is_accessable( streng *filename, int mode )
{
   /* Implementation of this routine is simplistic.
      All regular files are considered executable.
	  Only the old-DOS style attribute is looked to
	  determine read-only.  NT security considerations
	  under NTFS is ignored.
	*/

   int attrs, ret;
   
   filename = Str_ify( filename ) ;

   attrs = GetFileAttributes( filename->value );

   if (attrs == 0xFFFFFFFF || ( attrs & FILE_ATTRIBUTE_DIRECTORY ) )
   		return 0;
   /*
    * First, call access() with the 'correct' parameters, and store
    * the result in 'res'. If 'mode' had an "impossible" value, give 
    * an error.
    */
   if (mode == COMMAND_READABLE)
      ret = 1 ;
   else if (mode == COMMAND_WRITABLE)
      ret = !(attrs & FILE_ATTRIBUTE_READONLY) ;
   else if (mode == COMMAND_EXECUTABLE)
      ret = 1 ;
   else
      exiterror( ERR_INTERPRETER_FAILURE ) ;

   /*
    * Perhaps we should analyze the output a bit before returning? 
    * If res==EACCES, that is not really an error, while other errno
    * code _do_ signify an error. However ... since the return code 
    * a boolean variable, just return it.
    */
   return (ret) ;
}

char *Win32UserName(void)
{
	static char username[256];
	unsigned char tubuf[1024];
	char chDomain[120];
	char chUser[120];
	TOKEN_USER *ptu = (TOKEN_USER *)tubuf;
	SID_NAME_USE snu;
	DWORD cbUser, cbDomain, cbDummy;
	HANDLE hAccessToken;

	if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hAccessToken)) {
		fprintf(stderr, "Can't open process token: error = %lu.\n", GetLastError());
		exit(1);
	}

	if (!GetTokenInformation(hAccessToken, TokenUser, ptu, sizeof tubuf, &cbDummy)) {
		fprintf(stderr, "Can't get user sid: error = %lu.\n", GetLastError());
		exit(1);
	}

	cbUser = sizeof chUser;
	cbDomain = sizeof chDomain;
	if (!LookupAccountSid(NULL, ptu->User.Sid, chUser, &cbUser, chDomain, &cbDomain, &snu)) {
		fprintf(stderr, "Can't get user name: error = %lu.\n", GetLastError());
		exit(1);
	}

	(void)CloseHandle(hAccessToken);

	sprintf(username, "%s\\%s", chDomain, chUser);

	return username;
}


void getsecs( time_t *secs, time_t *usecs )
{
	struct _timeb timeptr;
    _ftime( &timeptr );
   *secs = timeptr.time ;
   *usecs = timeptr.millitm*1000 ;
}

streng *run_popen( streng *command, streng *envir )
{
   char cbuffer[512] ;
   streng *nresult=NULL ;
   streng *result=NULL ;
   int rc ;
   DWORD i ;
   static int child, status=0, running=0 ;
   struct envir ;
   int length=0 ;
   int envirno ;
   int print() ;
   HANDLE hRead, hWrite ;
   char cmdbuf[20*1024];
   STARTUPINFO si;
   PROCESS_INFORMATION pi;
   DWORD dwRC;
   int getenvir( streng *envir ) ;
   SECURITY_ATTRIBUTES sa;

   fflush(stdout) ;
   fflush(stderr) ;

   envirno = getenvir( envir ) ;

   sa.nLength = sizeof sa;
   sa.lpSecurityDescriptor = NULL;
   sa.bInheritHandle = TRUE;

   if (!CreatePipe(&hRead, &hWrite, &sa, 0))
   {
      return NULL ;
   }


   command = Str_ify(command);

   if (envirno==SUBENVIR_SYSTEM)
   {
   		char comspec[1024] ;
		if (GetEnvironmentVariable("COMSPEC", comspec, sizeof comspec) == 0)
		{
		   strcpy(comspec, "CMD.EXE");
		}
        sprintf( cmdbuf, "%s /c \"%s\"", comspec, command->value ) ;
   }
   else 
   {
		strcpy(cmdbuf, command->value ) ;
   }


   memset(&si, '\0', sizeof si);
   si.cb = sizeof si;
   si.dwFlags = STARTF_USESTDHANDLES ;
   si.hStdInput = GetStdHandle( STD_INPUT_HANDLE ) ;
   si.hStdOutput = hWrite ;
   si.hStdError = GetStdHandle( STD_ERROR_HANDLE ) ;

   if (!CreateProcess(NULL, cmdbuf, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
   {
      return NULL ;
   }

   CloseHandle(hWrite);

   for (;;) {
      DWORD dwRead;
      if (!ReadFile( hRead, cbuffer, sizeof cbuffer, &dwRead, NULL ) )
      {
	     if (GetLastError() != ERROR_BROKEN_PIPE)
		 {
		 	return NULL;
		 }
         dwRead = 0;
      }
      
      for (i=0; (cbuffer[i])&&(i<dwRead); i++) 
         if ((cbuffer[i]==0x0a)||(cbuffer[i]==0x0d))
            cbuffer[i] = ' ' ;

      nresult = Str_make((length=((result)?(Str_len(result)):0))+dwRead+1) ;
      if (result)
      {
         nresult = Str_ncpy( nresult, result, length ) ;
         nresult = Str_ify(nresult) ; 
         Free( result ) ; 
      }
      else
         nresult->len = 0 ;

      if (dwRead>=0)
         result = nresult = Str_ncatstr( nresult, cbuffer, dwRead ) ;
      else
         result = nresult ;

      result = Str_ify( result ) ;
      if (dwRead==0) 
         break ;
   }
      
   CloseHandle(hRead);
   
   if (result->value[length-1] == ' ')
   {
      result->len-- ;
	  length--;
   }
      
   if (result->value[length-1] == ' ')
   {
      result->len-- ;
	  length--;
   }

   result = Str_ify( result ) ;
      
   WaitForSingleObject( pi.hProcess, INFINITE ) ;

   if (!GetExitCodeProcess(pi.hProcess,	&dwRC ))
       dwRC = (DWORD)-1;

   CloseHandle(hRead);
   CloseHandle(hRead);

   rc = (int)dwRC;

/*  should this be set ?  */
   {
      static streng RC_name = { 2, 3, "RC" } ;
      setvalue( &RC_name, int_to_streng(rc) ) ; 
   }

   return(((rc>=0))?result:NULL) ; 
}
