1254 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			1254 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
/*  Part of SWI-Prolog
 | 
						|
 | 
						|
    Author:        Jan Wielemaker
 | 
						|
    E-mail:        J.Wielemaker@cs.vu.nl
 | 
						|
    WWW:           http://www.swi-prolog.org
 | 
						|
    Copyright (C): 1985-2013, University of Amsterdam
 | 
						|
			      VU University Amsterdam
 | 
						|
 | 
						|
    This library is free software; you can redistribute it and/or
 | 
						|
    modify it under the terms of the GNU Lesser General Public
 | 
						|
    License as published by the Free Software Foundation; either
 | 
						|
    version 2.1 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
 | 
						|
    Lesser General Public License for more details.
 | 
						|
 | 
						|
    You should have received a copy of the GNU Lesser General Public
 | 
						|
    License along with this library; if not, write to the Free Software
 | 
						|
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 | 
						|
*/
 | 
						|
 | 
						|
#define _UNICODE 1
 | 
						|
#define UNICODE 1
 | 
						|
 | 
						|
#ifdef _YAP_NOT_INSTALLED_
 | 
						|
#define MAX_FILE_NAME 1024
 | 
						|
#include "config.h"
 | 
						|
#include "console/LGPL/resource.h"
 | 
						|
#ifdef THREADS
 | 
						|
#define O_PLMT 1
 | 
						|
#endif
 | 
						|
#else
 | 
						|
#ifdef WIN64
 | 
						|
#include "config/win64.h"
 | 
						|
#else
 | 
						|
#include "config/win32.h"
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
 | 
						|
#include <windows.h>
 | 
						|
#include <commctrl.h>
 | 
						|
#include <tchar.h>
 | 
						|
#include <malloc.h>
 | 
						|
#include <stdio.h>
 | 
						|
#include "SWI-Stream.h"
 | 
						|
#include "SWI-Prolog.h"
 | 
						|
#include <ctype.h>
 | 
						|
#ifdef _YAP_NOT_INSTALLED_
 | 
						|
#include "swi/console/console.h"
 | 
						|
#else
 | 
						|
#include "win32/console/console.h"
 | 
						|
#endif
 | 
						|
#include <signal.h>
 | 
						|
#ifdef O_PLMT
 | 
						|
#include <pthread.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#include "pl-utf8.c"			/* we're not in the libpl.dll module */
 | 
						|
 | 
						|
#ifndef streq
 | 
						|
#define streq(s,q) (strcmp((s), (q)) == 0)
 | 
						|
#endif
 | 
						|
 | 
						|
#ifndef _TINT
 | 
						|
typedef wint_t _TINT;
 | 
						|
#endif
 | 
						|
 | 
						|
int win32main(rlc_console c, int argc, TCHAR **argv);
 | 
						|
 | 
						|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
						|
Main program for running SWI-Prolog from   a window. The window provides
 | 
						|
X11-xterm like features: scrollback for a   predefined  number of lines,
 | 
						|
cut/paste and the GNU readline library for command-line editing.
 | 
						|
 | 
						|
This module combines swipl.dll and plterm.dll  with some glue to produce
 | 
						|
the final executable swipl-win.exe.
 | 
						|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | 
						|
 | 
						|
__declspec(dllexport)	rlc_console	PL_current_console(void);
 | 
						|
__declspec(dllexport)	int		PL_set_menu_thread(void);
 | 
						|
static HWND		create_prolog_hidden_window(rlc_console c, int replace);
 | 
						|
static int		get_chars_arg_ex(int a, term_t t, TCHAR **v);
 | 
						|
 | 
						|
#define RLC_PROLOG_WINDOW	RLC_VALUE(0) /* GetCurrentThreadID() */
 | 
						|
#define RLC_PROLOG_INPUT	RLC_VALUE(1) /* Input  stream (IOSTREAM*) */
 | 
						|
#define RLC_PROLOG_OUTPUT	RLC_VALUE(2) /* Output stream (IOSTREAM*) */
 | 
						|
#define RLC_PROLOG_ERROR	RLC_VALUE(3) /* Error  stream (IOSTREAM*) */
 | 
						|
#define RLC_REGISTER		RLC_VALUE(4) /* Trap destruction */
 | 
						|
 | 
						|
		 /*******************************
 | 
						|
		 *	  EXTRA YAP 		*
 | 
						|
		 *******************************/
 | 
						|
#if __YAP_PROLOG__
 | 
						|
static int
 | 
						|
build_filter( term_t list, size_t space, TCHAR *fil )
 | 
						|
{
 | 
						|
  term_t a = PL_new_term_ref();
 | 
						|
  term_t head = PL_new_term_ref();
 | 
						|
  int n;
 | 
						|
  size_t len;
 | 
						|
  TCHAR *s;
 | 
						|
 | 
						|
  while (PL_is_pair( list )) {
 | 
						|
    if (!PL_get_list( list, head, list))
 | 
						|
      return FALSE;
 | 
						|
    for (n=1; n<=2; n++) {
 | 
						|
      if ( !PL_get_arg(n, head, a) )
 | 
						|
	return FALSE;
 | 
						|
      if ( !PL_get_wchars(a, &len, &s, CVT_ATOM|BUF_DISCARDABLE) )
 | 
						|
	return FALSE;
 | 
						|
      if (len >= space)
 | 
						|
	return FALSE;
 | 
						|
      space -= len+1;
 | 
						|
      while ((*fil++ = *s++));
 | 
						|
    }
 | 
						|
  }
 | 
						|
  *fil++ = '\0';
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
// a another memory buffer to contain the file name
 | 
						|
static foreign_t
 | 
						|
pl_win_file_name( term_t mode, term_t list, term_t tit, term_t cwd, term_t hwnd, term_t file )
 | 
						|
{  
 | 
						|
#if 1
 | 
						|
  // open a file name
 | 
						|
  OPENFILENAME ofn ;
 | 
						|
 | 
						|
  TCHAR *szFile = (TCHAR *)malloc(sizeof(TCHAR)*(MAX_FILE_NAME+1));
 | 
						|
  TCHAR *filter = (TCHAR *)malloc(sizeof(TCHAR)*(MAX_FILE_NAME+1));
 | 
						|
  //  TCHAR *file = (TCHAR *)malloc(sizeof(TCHAR)*(MAX_FILE_NAME+1));
 | 
						|
  TCHAR *title, *dir;
 | 
						|
  void *owner;
 | 
						|
  size_t len;
 | 
						|
 | 
						|
  ZeroMemory( &ofn , sizeof( ofn));
 | 
						|
  ofn.lStructSize = sizeof ( ofn );
 | 
						|
  if (!PL_get_pointer(hwnd, &owner))
 | 
						|
    return FALSE;
 | 
						|
  ofn.hwndOwner = owner  ;
 | 
						|
  ofn.lpstrFile = szFile ;
 | 
						|
  ofn.lpstrFile[0] = '\0';
 | 
						|
  ofn.nMaxFile = MAX_FILE_NAME;
 | 
						|
  if (!build_filter( list, MAX_FILE_NAME, filter ))
 | 
						|
    return FALSE;
 | 
						|
  ofn.lpstrFilter = filter;
 | 
						|
  ofn.nFilterIndex =1;
 | 
						|
  if ( !PL_get_wchars(tit, &len, &title, CVT_ATOM|BUF_RING) )
 | 
						|
    return FALSE;
 | 
						|
  ofn.lpstrTitle = title ;
 | 
						|
  ofn.lpstrFileTitle = NULL ;
 | 
						|
  ofn.nMaxFileTitle = 0 ;
 | 
						|
  if ( !PL_get_wchars(cwd, &len, &dir, CVT_ATOM|BUF_RING) )
 | 
						|
    return FALSE;
 | 
						|
  ofn.lpstrInitialDir=dir ;
 | 
						|
  ofn.Flags = OFN_PATHMUSTEXIST|OFN_FILEMUSTEXIST ;
 | 
						|
 
 | 
						|
  GetOpenFileName( &ofn );
 | 
						|
  return PL_unify_wchars( file, PL_ATOM, wcslen(ofn.lpstrFile), ofn.lpstrFile);
 | 
						|
     
 | 
						|
  // Now simpley display the file name
 | 
						|
  // MessageBox ( NULL , ofn.lpstrFile , "File Name" , MB_OK);
 | 
						|
  
 | 
						|
 
 | 
						|
#else  
 | 
						|
  // CoCreate the dialog object.
 | 
						|
  HRESULT hr = CoCreateInstance(CLSID_FileOpenDialog, 
 | 
						|
				NULL, 
 | 
						|
				CLSCTX_INPROC_SERVER, 
 | 
						|
				IID_PPV_ARGS(&pfd));
 | 
						|
 | 
						|
  if (SUCCEEDED(hr))
 | 
						|
    {
 | 
						|
      DWORD dwOptions;
 | 
						|
      // Specify multiselect.
 | 
						|
      hr = pfd->GetOptions(&dwOptions);
 | 
						|
        
 | 
						|
      if (SUCCEEDED(hr))
 | 
						|
        {
 | 
						|
	  hr = pfd->SetOptions(dwOptions | FOS_ALLOWMULTISELECT);
 | 
						|
        }
 | 
						|
 | 
						|
      if (SUCCEEDED(hr))
 | 
						|
        {
 | 
						|
	  // Show the Open dialog.
 | 
						|
	  hr = pfd->Show(NULL);
 | 
						|
 | 
						|
	  if (SUCCEEDED(hr))
 | 
						|
            {
 | 
						|
	      // Obtain the result of the user interaction.
 | 
						|
	      IShellItemArray *psiaResults;
 | 
						|
	      hr = pfd->GetResults(&psiaResults);
 | 
						|
                
 | 
						|
	      if (SUCCEEDED(hr))
 | 
						|
                {
 | 
						|
		  //
 | 
						|
		  // You can add your own code here to handle the results.
 | 
						|
		  //
 | 
						|
		  psiaResults->Release();
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
      pfd->Release();
 | 
						|
    }
 | 
						|
  // Now simpley display the file name
 | 
						|
  MessageBox ( NULL , ofn.lpstrFile , "File Name" , MB_OK);
 | 
						|
#endif
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
		 /*******************************
 | 
						|
		 *	  CONSOLE ADMIN		*
 | 
						|
		 *******************************/
 | 
						|
 | 
						|
static CRITICAL_SECTION mutex;
 | 
						|
#define LOCK()   EnterCriticalSection(&mutex)
 | 
						|
#define UNLOCK() LeaveCriticalSection(&mutex)
 | 
						|
 | 
						|
static rlc_console *consoles;		/* array of consoles */
 | 
						|
static int consoles_length;		/* size of this array */
 | 
						|
 | 
						|
static void
 | 
						|
unregisterConsole(uintptr_t data)
 | 
						|
{ rlc_console c = (rlc_console)data;
 | 
						|
  rlc_console *p;
 | 
						|
  int n;
 | 
						|
 | 
						|
  LOCK();
 | 
						|
  for(p=consoles, n=0; n++<consoles_length; p++)
 | 
						|
  { if ( *p == c )
 | 
						|
    { *p = NULL;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  UNLOCK();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
registerConsole(rlc_console c)
 | 
						|
{ rlc_console *p;
 | 
						|
  int n;
 | 
						|
 | 
						|
  LOCK();
 | 
						|
  for(;;)
 | 
						|
  { for(p=consoles, n=0; n++<consoles_length; p++)
 | 
						|
    { if ( !*p )
 | 
						|
      { *p = c;
 | 
						|
        rlc_set(c, RLC_REGISTER, (uintptr_t)c, unregisterConsole);
 | 
						|
	UNLOCK();
 | 
						|
	return;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    if ( consoles_length )
 | 
						|
    { int bytes = consoles_length*sizeof(rlc_console);
 | 
						|
 | 
						|
      consoles = PL_realloc(consoles, bytes*2);
 | 
						|
      memset(consoles+consoles_length, 0, bytes);
 | 
						|
      consoles_length *= 2;
 | 
						|
    } else
 | 
						|
    { consoles_length = 10;
 | 
						|
      consoles = PL_malloc(consoles_length*sizeof(rlc_console));
 | 
						|
      memset(consoles, 0, consoles_length*sizeof(rlc_console));
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* static void */
 | 
						|
/* closeConsoles(void) */
 | 
						|
/* { int i; */
 | 
						|
/*   rlc_console *p; */
 | 
						|
 | 
						|
/*   LOCK(); */
 | 
						|
/*   for(i=0, p=consoles; i<consoles_length; i++, p++) */
 | 
						|
/*   { if ( *p ) */
 | 
						|
/*       rlc_close(*p); */
 | 
						|
/*   } */
 | 
						|
/*   UNLOCK(); */
 | 
						|
/* } */
 | 
						|
 | 
						|
 | 
						|
		 /*******************************
 | 
						|
		 *	BIND STREAM STUFF	*
 | 
						|
		 *******************************/
 | 
						|
 | 
						|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
						|
First step: bind the  console  I/O   to  the  Sinput/Soutput  and Serror
 | 
						|
streams.
 | 
						|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | 
						|
 | 
						|
static ssize_t
 | 
						|
Srlc_read(void *handle, char *buffer, size_t size)
 | 
						|
{ rlc_console c = handle;
 | 
						|
  size_t bytes;
 | 
						|
  int is_user_input = (Suser_input && Suser_input->handle == c);
 | 
						|
  term_t ex;
 | 
						|
 | 
						|
  PL_write_prompt(TRUE);
 | 
						|
 | 
						|
  if ( is_user_input &&
 | 
						|
       PL_ttymode(Suser_input) == PL_RAWTTY )
 | 
						|
  { int chr = getkey(c);
 | 
						|
    TCHAR *tbuf = (TCHAR*)buffer;
 | 
						|
 | 
						|
    if ( chr == 04 || chr == 26 || chr == -1 )
 | 
						|
    { bytes = 0;
 | 
						|
    } else
 | 
						|
    { tbuf[0] = chr;
 | 
						|
      bytes = sizeof(TCHAR);
 | 
						|
    }
 | 
						|
  } else
 | 
						|
  { bytes = rlc_read(c, (TCHAR*)buffer, size/sizeof(TCHAR));
 | 
						|
    bytes *= sizeof(TCHAR);
 | 
						|
  }
 | 
						|
 | 
						|
  if ( is_user_input && (ex=PL_exception(0)) )
 | 
						|
  { Sset_exception(Suser_input, ex);
 | 
						|
    return -1;
 | 
						|
  }
 | 
						|
 | 
						|
  if ( bytes == 0 || buffer[bytes-1] == '\n' )
 | 
						|
    PL_prompt_next(0);
 | 
						|
 | 
						|
  return bytes;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
						|
The user streams for swipl-win.exe run  using the 'wchar' encoding. This
 | 
						|
means size must be a multiple of   sizeof(wchar_t),  but not if the user
 | 
						|
cheats and either switches the encoding   or uses put_byte/1 or similar.
 | 
						|
The flushing code will remember `half'   characters  and re-send them as
 | 
						|
more data comes ready. This means however  that after a put_byte(X), the
 | 
						|
wchar_t stream is out-of-sync and produces   unreadable  output. We will
 | 
						|
therefore pad it with '?' characters to re-sync the stream.
 | 
						|
 | 
						|
The downside of this is  that  Sputc()   and  Sputcode()  do not work on
 | 
						|
unbuffered streams and thus Serror  must   be  locked before using these
 | 
						|
functions.
 | 
						|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | 
						|
 | 
						|
static ssize_t
 | 
						|
Srlc_write(void *handle, char *buffer, size_t size)
 | 
						|
{ rlc_console c = handle;
 | 
						|
  ssize_t n;
 | 
						|
 | 
						|
  n = rlc_write(c, (TCHAR*)buffer, size/sizeof(TCHAR));
 | 
						|
  n *= sizeof(TCHAR);
 | 
						|
 | 
						|
  if ( n < (ssize_t)size && size-n < sizeof(TCHAR) )
 | 
						|
  { char buf[sizeof(TCHAR)];		/* Pad to TCHAR */
 | 
						|
    size_t i = sizeof(TCHAR) - (size-n);
 | 
						|
 | 
						|
    memcpy(buf, buffer+n, i);
 | 
						|
    for(; i<sizeof(TCHAR); i++)
 | 
						|
      buf[i] = '?';
 | 
						|
    rlc_write(c, (TCHAR*)buffer, 1);
 | 
						|
 | 
						|
    return size;
 | 
						|
  }
 | 
						|
 | 
						|
  return n;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static int
 | 
						|
Srlc_close(void *handle)
 | 
						|
{ rlc_console c = handle;
 | 
						|
  uintptr_t v;
 | 
						|
  int closed = 0;
 | 
						|
 | 
						|
  if ( rlc_get(handle, RLC_PROLOG_INPUT, &v) && v &&
 | 
						|
       ((IOSTREAM *)v)->flags && SIO_CLOSING )
 | 
						|
  { rlc_set(handle, RLC_PROLOG_INPUT, 0L, NULL);
 | 
						|
    closed++;
 | 
						|
  } else if ( rlc_get(handle, RLC_PROLOG_OUTPUT, &v) && v &&
 | 
						|
	      ((IOSTREAM *)v)->flags && SIO_CLOSING )
 | 
						|
  { rlc_set(handle, RLC_PROLOG_OUTPUT, 0L, NULL);
 | 
						|
    closed++;
 | 
						|
  } else if ( rlc_get(handle, RLC_PROLOG_ERROR, &v) && v &&
 | 
						|
	      ((IOSTREAM *)v)->flags && SIO_CLOSING )
 | 
						|
  { rlc_set(handle, RLC_PROLOG_ERROR, 0L, NULL);
 | 
						|
  }
 | 
						|
 | 
						|
  if ( closed &&
 | 
						|
       rlc_get(handle, RLC_PROLOG_INPUT, &v)  && v == 0L &&
 | 
						|
       rlc_get(handle, RLC_PROLOG_OUTPUT, &v) && v == 0L )
 | 
						|
    rlc_close(c);
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
						|
The role of this function is to stop  changing the encoding of the plwin
 | 
						|
output. We must return -1 for  SIO_SETENCODING   for  this. As we do not
 | 
						|
implement any of the other control operations   we  simply return -1 for
 | 
						|
all commands we may be requested to handle.
 | 
						|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | 
						|
 | 
						|
static int
 | 
						|
Srlc_control(void *handle, int cmd, void *closure)
 | 
						|
{ return -1;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static IOFUNCTIONS rlc_functions;
 | 
						|
 | 
						|
static void
 | 
						|
rlc_bind_terminal(rlc_console c)
 | 
						|
{ rlc_functions	        = *Sinput->functions;
 | 
						|
  rlc_functions.read    = Srlc_read;
 | 
						|
  rlc_functions.write	= Srlc_write;
 | 
						|
  rlc_functions.close   = Srlc_close;
 | 
						|
  rlc_functions.control = Srlc_control;
 | 
						|
 | 
						|
  Sinput->functions  = &rlc_functions;
 | 
						|
  Soutput->functions = &rlc_functions;
 | 
						|
  Serror->functions  = &rlc_functions;
 | 
						|
 | 
						|
  Sinput->handle  = c;
 | 
						|
  Soutput->handle = c;
 | 
						|
  Serror->handle  = c;
 | 
						|
 | 
						|
  Sinput->encoding  = ENC_WCHAR;
 | 
						|
  Soutput->encoding = ENC_WCHAR;
 | 
						|
  Serror->encoding  = ENC_WCHAR;
 | 
						|
 | 
						|
  Sinput->flags  &= ~SIO_FILE;
 | 
						|
  Soutput->flags &= ~SIO_FILE;
 | 
						|
  Serror->flags  &= ~SIO_FILE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static int
 | 
						|
process_console_options(rlc_console_attr *attr, term_t options)
 | 
						|
{ term_t tail = PL_copy_term_ref(options);
 | 
						|
  term_t opt = PL_new_term_ref();
 | 
						|
 | 
						|
  while(PL_get_list(tail, opt, tail))
 | 
						|
  { atom_t name;
 | 
						|
    const char *s;
 | 
						|
    int arity;
 | 
						|
 | 
						|
    if ( !PL_get_name_arity(opt, &name, &arity) )
 | 
						|
      return PL_type_error("compound", opt);
 | 
						|
    s = PL_atom_chars(name);
 | 
						|
    if ( streq(s, "registry_key") && arity == 1 )
 | 
						|
    { TCHAR *key;
 | 
						|
 | 
						|
      if ( !get_chars_arg_ex(1, opt, &key) )
 | 
						|
	return FALSE;
 | 
						|
 | 
						|
      attr->key = key;
 | 
						|
    } else
 | 
						|
      return PL_domain_error("window_option", opt);
 | 
						|
  }
 | 
						|
  if ( !PL_get_nil_ex(tail) )
 | 
						|
    return FALSE;
 | 
						|
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void				/* handle console destruction */
 | 
						|
free_stream(uintptr_t handle)
 | 
						|
{ IOSTREAM *s = (IOSTREAM*) handle;
 | 
						|
 | 
						|
  Sclose(s);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static foreign_t
 | 
						|
pl_win_open_console(term_t title, term_t input, term_t output, term_t error,
 | 
						|
		    term_t options)
 | 
						|
{ rlc_console_attr attr;
 | 
						|
  rlc_console c;
 | 
						|
  IOSTREAM *in, *out, *err;
 | 
						|
  TCHAR *s;
 | 
						|
  size_t len;
 | 
						|
 | 
						|
  memset(&attr, 0, sizeof(attr));
 | 
						|
  if ( !PL_get_wchars(title, &len, &s, CVT_ALL|BUF_RING|CVT_EXCEPTION) )
 | 
						|
    return FALSE;
 | 
						|
  attr.title = (const TCHAR*) s;
 | 
						|
 | 
						|
  if ( !process_console_options(&attr, options) )
 | 
						|
    return FALSE;
 | 
						|
 | 
						|
  c = rlc_create_console(&attr);
 | 
						|
  create_prolog_hidden_window(c, FALSE);	/* for sending messages */
 | 
						|
  registerConsole(c);
 | 
						|
 | 
						|
#define STREAM_COMMON (SIO_TEXT|	/* text-stream */		\
 | 
						|
		       SIO_NOCLOSE|	/* do no close on abort */	\
 | 
						|
		       SIO_ISATTY|	/* terminal */			\
 | 
						|
		       SIO_NOFEOF)	/* reset on end-of-file */
 | 
						|
 | 
						|
  in  = Snew(c,  SIO_INPUT|SIO_LBUF|STREAM_COMMON, &rlc_functions);
 | 
						|
  out = Snew(c, SIO_OUTPUT|SIO_LBUF|STREAM_COMMON, &rlc_functions);
 | 
						|
  err = Snew(c, SIO_OUTPUT|SIO_NBUF|STREAM_COMMON, &rlc_functions);
 | 
						|
 | 
						|
  in->position  = &in->posbuf;		/* record position on same stream */
 | 
						|
  out->position = &in->posbuf;
 | 
						|
  err->position = &in->posbuf;
 | 
						|
 | 
						|
  in->encoding  = ENC_WCHAR;
 | 
						|
  out->encoding = ENC_WCHAR;
 | 
						|
  err->encoding = ENC_WCHAR;
 | 
						|
 | 
						|
  if ( !PL_unify_stream(input, in) ||
 | 
						|
       !PL_unify_stream(output, out) ||
 | 
						|
       !PL_unify_stream(error, err) )
 | 
						|
  { Sclose(in);
 | 
						|
    Sclose(out);
 | 
						|
    Sclose(err);
 | 
						|
    rlc_close(c);
 | 
						|
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  rlc_set(c, RLC_PROLOG_INPUT,  (uintptr_t)in,  NULL);
 | 
						|
  rlc_set(c, RLC_PROLOG_OUTPUT, (uintptr_t)out, NULL);
 | 
						|
  rlc_set(c, RLC_PROLOG_ERROR,  (uintptr_t)err, free_stream);
 | 
						|
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
						|
Note: actually rlc_add_history() removes  duplicates   and  empty lines.
 | 
						|
Also, read_line() already updates the history.   Maybe  this should just
 | 
						|
return TRUE? This however would not allow for programmatically inserting
 | 
						|
things in the history. This shouldn't matter.
 | 
						|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | 
						|
 | 
						|
static foreign_t
 | 
						|
pl_rl_add_history(term_t text)
 | 
						|
{ atom_t a;
 | 
						|
  static atom_t last = 0;
 | 
						|
 | 
						|
  if ( PL_get_atom_ex(text, &a) )
 | 
						|
  { if ( a != last )
 | 
						|
    { TCHAR *s;
 | 
						|
 | 
						|
      if ( last )
 | 
						|
	PL_unregister_atom(last);
 | 
						|
      last = a;
 | 
						|
      PL_register_atom(last);
 | 
						|
 | 
						|
      if ( PL_get_wchars(text, NULL, &s, CVT_ATOM) )
 | 
						|
	rlc_add_history(PL_current_console(), s);
 | 
						|
    }
 | 
						|
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static int
 | 
						|
add_line(void *h, int no, const TCHAR *line)
 | 
						|
{ term_t tail = (term_t)h;
 | 
						|
  term_t head = PL_new_term_ref();
 | 
						|
 | 
						|
  if ( !PL_unify_wchars(head, PL_ATOM, (size_t)-1, line) ||
 | 
						|
       !PL_cons_list(tail, head, tail) )
 | 
						|
    return -1;
 | 
						|
 | 
						|
  PL_reset_term_refs(head);
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static foreign_t
 | 
						|
pl_rl_history(term_t list)
 | 
						|
{ term_t tail = PL_new_term_ref();
 | 
						|
 | 
						|
  if ( !PL_unify_nil(tail) )
 | 
						|
    return FALSE;
 | 
						|
 | 
						|
  if ( rlc_for_history(PL_current_console(), add_line, (void*)tail) == 0 )
 | 
						|
    return PL_unify(tail, list);
 | 
						|
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static foreign_t
 | 
						|
pl_rl_read_init_file(term_t file)
 | 
						|
{ PL_succeed;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
		 /*******************************
 | 
						|
		 *	    COMPLETION		*
 | 
						|
		 *******************************/
 | 
						|
 | 
						|
static RlcCompleteFunc file_completer;
 | 
						|
 | 
						|
static int
 | 
						|
prolog_complete(RlcCompleteData data)
 | 
						|
{ Line ln = data->line;
 | 
						|
 | 
						|
  switch(data->call_type)
 | 
						|
  { case COMPLETE_INIT:
 | 
						|
    { size_t start = ln->point;
 | 
						|
      wint_t c;
 | 
						|
 | 
						|
      if ( !ln->data )		/* we donot want to complete on all atoms */
 | 
						|
	return FALSE;
 | 
						|
 | 
						|
      while(start > 0 && (_istalnum((c=ln->data[start-1])) || c == '_') )
 | 
						|
	start--;
 | 
						|
      if ( start > 0 )
 | 
						|
      { _TINT cs = ln->data[start-1];
 | 
						|
 | 
						|
	if ( _tcschr(_T("'/\\.~"), cs) )
 | 
						|
	  return FALSE;			/* treat as a filename */
 | 
						|
      }
 | 
						|
      if ( _istlower(ln->data[start]) )	/* Lower, Aplha ...: an atom */
 | 
						|
      { size_t patlen = ln->point - start;
 | 
						|
 | 
						|
	_tcsncpy(data->buf_handle, &ln->data[start], patlen);
 | 
						|
	data->buf_handle[patlen] = '\0';
 | 
						|
 | 
						|
	if ( PL_atom_generator_w(data->buf_handle,
 | 
						|
				 data->candidate,
 | 
						|
				 sizeof(data->candidate)/sizeof(TCHAR),
 | 
						|
				 FALSE) )
 | 
						|
	{ data->replace_from = (int)start;
 | 
						|
	  data->function = prolog_complete;
 | 
						|
	  return TRUE;
 | 
						|
	}
 | 
						|
      }
 | 
						|
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
    case COMPLETE_ENUMERATE:
 | 
						|
    { if ( PL_atom_generator_w(data->buf_handle,
 | 
						|
			       data->candidate,
 | 
						|
			       sizeof(data->candidate)/sizeof(TCHAR),
 | 
						|
			       TRUE) )
 | 
						|
	return TRUE;
 | 
						|
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
    case COMPLETE_CLOSE:
 | 
						|
      return TRUE;
 | 
						|
    default:
 | 
						|
      return FALSE;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static int
 | 
						|
do_complete(RlcCompleteData data)
 | 
						|
{ if ( prolog_complete(data) )
 | 
						|
    return TRUE;
 | 
						|
 | 
						|
  if ( file_completer )
 | 
						|
    return (*file_completer)(data);
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
		 /*******************************
 | 
						|
		 *	   CONSOLE STUFF	*
 | 
						|
		 *******************************/
 | 
						|
 | 
						|
rlc_console
 | 
						|
PL_current_console(void)
 | 
						|
{ if ( Suser_input->functions->read == Srlc_read )
 | 
						|
    return Suser_input->handle;
 | 
						|
 | 
						|
  return NULL;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static rlc_console main_console;
 | 
						|
 | 
						|
int
 | 
						|
PL_set_menu_thread(void)
 | 
						|
{ if ( main_console )
 | 
						|
  { create_prolog_hidden_window(main_console, TRUE);
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static foreign_t
 | 
						|
pl_window_title(term_t old, term_t new)
 | 
						|
{ TCHAR buf[256];
 | 
						|
  TCHAR *n;
 | 
						|
 | 
						|
  if ( !PL_get_wchars(new, NULL, &n, CVT_ALL|CVT_EXCEPTION) )
 | 
						|
    return FALSE;
 | 
						|
 | 
						|
  rlc_title(PL_current_console(), n, buf, sizeof(buf)/sizeof(TCHAR));
 | 
						|
 | 
						|
  return PL_unify_wchars(old, PL_ATOM, _tcslen(buf), buf);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static int
 | 
						|
get_chars_arg_ex(int a, term_t t, TCHAR **v)
 | 
						|
{ term_t arg = PL_new_term_ref();
 | 
						|
 | 
						|
  if ( PL_get_arg(a, t, arg) &&
 | 
						|
       PL_get_wchars(arg, NULL, v, CVT_ALL|BUF_RING|CVT_EXCEPTION) )
 | 
						|
    return TRUE;
 | 
						|
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static int
 | 
						|
get_int_arg_ex(int a, term_t t, int *v)
 | 
						|
{ term_t arg = PL_new_term_ref();
 | 
						|
 | 
						|
  _PL_get_arg(a, t, arg);
 | 
						|
  if ( PL_get_integer_ex(arg, v) )
 | 
						|
    return TRUE;
 | 
						|
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static int
 | 
						|
get_bool_arg_ex(int a, term_t t, int *v)
 | 
						|
{ term_t arg = PL_new_term_ref();
 | 
						|
 | 
						|
  _PL_get_arg(a, t, arg);
 | 
						|
  if ( PL_get_bool_ex(arg, v) )
 | 
						|
    return TRUE;
 | 
						|
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static foreign_t
 | 
						|
pl_window_pos(term_t options)
 | 
						|
{ int x = 0, y = 0, w = 0, h = 0;
 | 
						|
  HWND z = HWND_TOP;
 | 
						|
  UINT flags = SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOSIZE|SWP_NOMOVE;
 | 
						|
  term_t opt = PL_new_term_ref();
 | 
						|
  term_t tail = PL_copy_term_ref(options);
 | 
						|
 | 
						|
  while(PL_get_list(tail, opt, tail))
 | 
						|
  { atom_t name;
 | 
						|
    const char *s;
 | 
						|
    int arity;
 | 
						|
 | 
						|
    if ( !PL_get_name_arity(opt, &name, &arity) )
 | 
						|
      return PL_type_error("compound", opt);
 | 
						|
    s = PL_atom_chars(name);
 | 
						|
    if ( streq(s, "position") && arity == 2 )
 | 
						|
    { if ( !get_int_arg_ex(1, opt, &x) ||
 | 
						|
	   !get_int_arg_ex(2, opt, &y) )
 | 
						|
	return FALSE;
 | 
						|
      flags &= ~SWP_NOMOVE;
 | 
						|
    } else if ( streq(s, "size") && arity == 2 )
 | 
						|
    { if ( !get_int_arg_ex(1, opt, &w) ||
 | 
						|
	   !get_int_arg_ex(2, opt, &h) )
 | 
						|
	return FALSE;
 | 
						|
      flags &= ~SWP_NOSIZE;
 | 
						|
    } else if ( streq(s, "zorder") && arity == 1 )
 | 
						|
    { term_t t = PL_new_term_ref();
 | 
						|
      char *v;
 | 
						|
 | 
						|
      _PL_get_arg(1, opt, t);
 | 
						|
      if ( !PL_get_chars(t, &v, CVT_ATOM|CVT_EXCEPTION) )
 | 
						|
	return FALSE;
 | 
						|
      if ( streq(v, "top") )
 | 
						|
	z = HWND_TOP;
 | 
						|
      else if ( streq(v, "bottom") )
 | 
						|
	z = HWND_BOTTOM;
 | 
						|
      else if ( streq(v, "topmost") )
 | 
						|
	z = HWND_TOPMOST;
 | 
						|
      else if ( streq(v, "notopmost") )
 | 
						|
	z = HWND_NOTOPMOST;
 | 
						|
      else
 | 
						|
	return PL_domain_error("hwnd_insert_after", t);
 | 
						|
 | 
						|
      flags &= ~SWP_NOZORDER;
 | 
						|
    } else if ( streq(s, "show") && arity == 1 )
 | 
						|
    { int v;
 | 
						|
 | 
						|
      if ( !get_bool_arg_ex(1, opt, &v) )
 | 
						|
	return FALSE;
 | 
						|
      flags &= ~(SWP_SHOWWINDOW|SWP_HIDEWINDOW);
 | 
						|
      if ( v )
 | 
						|
	flags |= SWP_SHOWWINDOW;
 | 
						|
      else
 | 
						|
	flags |= SWP_HIDEWINDOW;
 | 
						|
    } else if ( streq(s, "activate") && arity == 0 )
 | 
						|
    { flags &= ~SWP_NOACTIVATE;
 | 
						|
    } else
 | 
						|
      return PL_domain_error("window_option", opt);
 | 
						|
  }
 | 
						|
  if ( !PL_get_nil_ex(tail) )
 | 
						|
   return FALSE;
 | 
						|
 | 
						|
  rlc_window_pos(PL_current_console(), z, x, y, w, h, flags);
 | 
						|
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
call_menu(const TCHAR *name)
 | 
						|
{ fid_t fid = PL_open_foreign_frame();
 | 
						|
  predicate_t pred = PL_predicate("on_menu", 1, "prolog");
 | 
						|
  module_t m = PL_new_module(PL_new_atom("prolog"));
 | 
						|
  term_t a0 = PL_new_term_ref();
 | 
						|
  size_t len = _tcslen(name);
 | 
						|
 | 
						|
  if ( PL_unify_wchars(a0, PL_ATOM, len, name) )
 | 
						|
    PL_call_predicate(m, PL_Q_NORMAL, pred, a0);
 | 
						|
 | 
						|
  PL_discard_foreign_frame(fid);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static foreign_t
 | 
						|
pl_win_insert_menu_item(term_t menu, term_t label, term_t before)
 | 
						|
{ TCHAR *m, *l, *b;
 | 
						|
 | 
						|
  if ( !PL_get_wchars(menu, NULL, &m, CVT_ATOM) ||
 | 
						|
       !PL_get_wchars(label, NULL, &l, CVT_ATOM) ||
 | 
						|
       !PL_get_wchars(before, NULL, &b, CVT_ATOM) )
 | 
						|
    return FALSE;
 | 
						|
 | 
						|
  if ( _tcscmp(b, _T("-")) == 0 )
 | 
						|
    b = NULL;
 | 
						|
  if ( _tcscmp(l, _T("--")) == 0 )
 | 
						|
    l = NULL;				/* insert a separator */
 | 
						|
 | 
						|
  return rlc_insert_menu_item(PL_current_console(), m, l, b);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static foreign_t
 | 
						|
pl_win_insert_menu(term_t label, term_t before)
 | 
						|
{ TCHAR *l, *b;
 | 
						|
 | 
						|
  if ( !PL_get_wchars(label, NULL, &l, CVT_ATOM) ||
 | 
						|
       !PL_get_wchars(before, NULL, &b, CVT_ATOM) )
 | 
						|
    return FALSE;
 | 
						|
 | 
						|
  if ( _tcscmp(b, _T("-")) == 0 )
 | 
						|
    b = NULL;
 | 
						|
 | 
						|
  return rlc_insert_menu(PL_current_console(), l, b);
 | 
						|
}
 | 
						|
 | 
						|
		 /*******************************
 | 
						|
		 *	      THREADS		*
 | 
						|
		 *******************************/
 | 
						|
 | 
						|
#ifdef O_PLMT
 | 
						|
 | 
						|
static void
 | 
						|
free_interactor(void *closure)
 | 
						|
{ PL_thread_destroy_engine();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void *
 | 
						|
run_interactor(void *closure)
 | 
						|
{ predicate_t pred;
 | 
						|
  PL_thread_attr_t attr = {0};
 | 
						|
 | 
						|
  attr.flags = PL_THREAD_NO_DEBUG;
 | 
						|
  PL_thread_attach_engine(&attr);
 | 
						|
  pthread_cleanup_push(free_interactor, NULL);
 | 
						|
 | 
						|
 | 
						|
  pred = PL_predicate("thread_run_interactor", 0, "user");
 | 
						|
  PL_call_predicate(NULL, PL_Q_NORMAL, pred, 0);
 | 
						|
 | 
						|
  pthread_cleanup_pop(1);
 | 
						|
 | 
						|
  return NULL;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
create_interactor(void)
 | 
						|
{ pthread_attr_t attr;
 | 
						|
  pthread_t child;
 | 
						|
 | 
						|
  pthread_attr_init(&attr);
 | 
						|
  pthread_create(&child, &attr, run_interactor, NULL);
 | 
						|
}
 | 
						|
 | 
						|
#endif /*O_PLMT*/
 | 
						|
 | 
						|
		 /*******************************
 | 
						|
		 *	      SIGNALS		*
 | 
						|
		 *******************************/
 | 
						|
 | 
						|
#define WM_SIGNALLED (WM_USER+1)
 | 
						|
#define WM_MENU	     (WM_USER+2)
 | 
						|
 | 
						|
static LRESULT WINAPI
 | 
						|
pl_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 | 
						|
{ switch(message)
 | 
						|
  { case WM_SIGNALLED:
 | 
						|
      PL_handle_signals();
 | 
						|
      return 0;
 | 
						|
    case WM_MENU:
 | 
						|
    { const TCHAR *name = (const TCHAR *)lParam;
 | 
						|
 | 
						|
      call_menu(name);
 | 
						|
 | 
						|
      return 0;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return DefWindowProc(hwnd, message, wParam, lParam);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static TCHAR *
 | 
						|
HiddenFrameClass(void)
 | 
						|
{ static TCHAR winclassname[32];
 | 
						|
  static WNDCLASS wndClass;
 | 
						|
  HINSTANCE instance = rlc_hinstance();
 | 
						|
 | 
						|
  if ( !winclassname[0] )
 | 
						|
  { snwprintf(winclassname, sizeof(winclassname)/sizeof(TCHAR),
 | 
						|
	      _T("YAP-Prolog-hidden-win%d"), instance);
 | 
						|
 | 
						|
    wndClass.style		= 0;
 | 
						|
    wndClass.lpfnWndProc	= (LPVOID) pl_wnd_proc;
 | 
						|
    wndClass.cbClsExtra		= 0;
 | 
						|
    wndClass.cbWndExtra		= 0;
 | 
						|
    wndClass.hInstance		= instance;
 | 
						|
    wndClass.hIcon		= (HICON) LoadImage(instance, MAKEINTRESOURCE(IDI_APPICON), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_DEFAULTCOLOR | LR_SHARED);
 | 
						|
    // wndClass.hIconSm       = (HICON) LoadImage(instance, MAKEINTRESOURCE(IDI_APPICON), IMAGE_ICON,
 | 
						|
    //                                    GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
 | 
						|
    //                                       LR_DEFAULTCOLOR | LR_SHARED);
 | 
						|
    wndClass.hCursor		= NULL;
 | 
						|
    wndClass.hbrBackground	= GetStockObject(WHITE_BRUSH);
 | 
						|
    wndClass.lpszMenuName	= MAKEINTRESOURCE(IDR_MAINMENU);
 | 
						|
    wndClass.lpszClassName	= winclassname;
 | 
						|
 | 
						|
    RegisterClass(&wndClass);
 | 
						|
  }
 | 
						|
 | 
						|
  return winclassname;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
destroy_hidden_window(uintptr_t hwnd)
 | 
						|
{ DestroyWindow((HWND)hwnd);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static HWND
 | 
						|
create_prolog_hidden_window(rlc_console c, int replace)
 | 
						|
{ uintptr_t hwnd;
 | 
						|
 | 
						|
  if ( rlc_get(c, RLC_PROLOG_WINDOW, &hwnd) && hwnd )
 | 
						|
  { if ( replace )
 | 
						|
      DestroyWindow((HWND)hwnd);
 | 
						|
    else
 | 
						|
      return (HWND)hwnd;
 | 
						|
  }
 | 
						|
 | 
						|
  hwnd = (uintptr_t)CreateWindow(HiddenFrameClass(),
 | 
						|
				     _T("YAP hidden window"),
 | 
						|
				     0,
 | 
						|
				     0, 0, 32, 32,
 | 
						|
				     NULL, NULL, rlc_hinstance(), NULL);
 | 
						|
 | 
						|
  rlc_set(c, RLC_PROLOG_WINDOW, hwnd, destroy_hidden_window);
 | 
						|
 | 
						|
  return (HWND)hwnd;
 | 
						|
}
 | 
						|
 | 
						|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
						|
Capturing fatal signals doesn't appear to work   inside  a DLL, hence we
 | 
						|
capture them in the application and tell   Prolog to print the stack and
 | 
						|
abort.
 | 
						|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | 
						|
 | 
						|
static void
 | 
						|
fatalSignal(int sig)
 | 
						|
{ char *name;
 | 
						|
 | 
						|
  switch(sig)
 | 
						|
  { case SIGABRT:	name = "abort"; break;
 | 
						|
    case SIGFPE:	name = "floating point exeception"; break;
 | 
						|
    case SIGILL:	name = "illegal instruction"; break;
 | 
						|
    case SIGSEGV:	name = "general protection fault"; break;
 | 
						|
    default:		name = "(unknown)"; break;
 | 
						|
  }
 | 
						|
 | 
						|
  PL_warning("Trapped signal %d (%s), aborting ...", sig, name);
 | 
						|
 | 
						|
  PL_action(PL_ACTION_BACKTRACE, (void *)10);
 | 
						|
  signal(sig, fatalSignal);
 | 
						|
  PL_action(PL_ACTION_ABORT, NULL);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
initSignals(void)
 | 
						|
{ signal(SIGABRT, fatalSignal);
 | 
						|
  signal(SIGFPE,  fatalSignal);
 | 
						|
  signal(SIGILL,  fatalSignal);
 | 
						|
  signal(SIGSEGV, fatalSignal);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
						|
Callbacks from the console. Trouble is that these routines are called in
 | 
						|
the thread updating the console rather   than the thread running Prolog.
 | 
						|
We can inform Prolog using  the  hidden   window  which  is  in Prolog's
 | 
						|
thread. For the interrupt to work if Prolog   is  working we need to set
 | 
						|
the signalled mask in the  proper   thread.  This  is accomplished using
 | 
						|
PL_w32thread_raise(ID, sig). In the single-threaded   version  this call
 | 
						|
simply calls PL_raise(sig).
 | 
						|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | 
						|
 | 
						|
static void
 | 
						|
interrupt(rlc_console c, int sig)
 | 
						|
{ uintptr_t val;
 | 
						|
 | 
						|
  if ( rlc_get(c, RLC_APPLICATION_THREAD_ID, &val) )
 | 
						|
  { DWORD tid = (DWORD)val;
 | 
						|
 | 
						|
    PL_w32thread_raise(tid, sig);
 | 
						|
    if ( rlc_get(c, RLC_PROLOG_WINDOW, &val) )
 | 
						|
    { HWND hwnd = (HWND)val;
 | 
						|
 | 
						|
      PostMessage((HWND)hwnd, WM_SIGNALLED, 0, 0);
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
menu_select(rlc_console c, const TCHAR *name)
 | 
						|
{
 | 
						|
#ifdef O_PLMT
 | 
						|
  if ( _tcscmp(name, _T("&New thread")) == 0 )
 | 
						|
  { create_interactor();
 | 
						|
  } else
 | 
						|
#endif /*O_PLMT*/
 | 
						|
  { uintptr_t hwnd;
 | 
						|
 | 
						|
    if ( rlc_get(c, RLC_PROLOG_WINDOW, &hwnd) )
 | 
						|
      PostMessage((HWND)hwnd, WM_MENU, 0, (LPARAM)name);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static LRESULT
 | 
						|
message_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 | 
						|
{ switch( PL_win_message_proc(hwnd, message, wParam, lParam) )
 | 
						|
  { case PL_MSG_HANDLED:
 | 
						|
      return TRUE;
 | 
						|
    default:
 | 
						|
      return FALSE;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
		 /*******************************
 | 
						|
		 *	       MAIN		*
 | 
						|
		 *******************************/
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
set_window_title(rlc_console c)
 | 
						|
{ TCHAR title[256];
 | 
						|
  int v = (int)PL_query(PL_QUERY_VERSION);
 | 
						|
  int major = v / 10000;
 | 
						|
  int minor = (v / 100) % 100;
 | 
						|
  int patch = v / 100;
 | 
						|
#ifdef O_PLMT
 | 
						|
  TCHAR *mt = _T("Multi-threaded, ");
 | 
						|
#else
 | 
						|
  TCHAR *mt = _T("");
 | 
						|
#endif
 | 
						|
#ifdef WIN64
 | 
						|
  TCHAR *w64 = _T("AMD64, ");			/* TBD: IA64 */
 | 
						|
#else
 | 
						|
  TCHAR *w64 = _T("");
 | 
						|
#endif
 | 
						|
 | 
						|
  snwprintf(title, sizeof(title)/sizeof(TCHAR),
 | 
						|
	    _T("YAP-Prolog (%s%sversion %d.%d.%d)"),
 | 
						|
	    w64, mt, major, minor, patch);
 | 
						|
 | 
						|
  rlc_title(c, title, NULL, 0);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
PL_extension extensions[] =
 | 
						|
{
 | 
						|
/*{ "name",	arity,  function,	PL_FA_<flags> },*/
 | 
						|
 | 
						|
  { "window_title",          2, pl_window_title,         0 },
 | 
						|
  { "$win_insert_menu_item", 3, pl_win_insert_menu_item, 0 },
 | 
						|
  { "win_insert_menu",       2, pl_win_insert_menu,      0 },
 | 
						|
  { "win_window_pos",        1, pl_window_pos,           0 },
 | 
						|
#if __YAP_PROLOG__
 | 
						|
  { "win_file_name",         6, pl_win_file_name,        0 },
 | 
						|
#endif
 | 
						|
  { NULL,                    0, NULL,                    0 }
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
						|
win32main() is called back from the plterm.dll  main loop to provide the
 | 
						|
main for the application.
 | 
						|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | 
						|
 | 
						|
static void
 | 
						|
install_readline(rlc_console c)
 | 
						|
{ rlc_init_history(c, 50);
 | 
						|
  file_completer = rlc_complete_hook(do_complete);
 | 
						|
 | 
						|
  PL_register_foreign_in_module(
 | 
						|
      "system", "rl_add_history",    1, pl_rl_add_history,    0);
 | 
						|
  PL_register_foreign_in_module(
 | 
						|
      "system", "rl_read_init_file", 1, pl_rl_read_init_file, 0);
 | 
						|
  PL_register_foreign_in_module(
 | 
						|
      "system", "$rl_history",       1, pl_rl_history,        0);
 | 
						|
 | 
						|
  PL_set_prolog_flag("tty_control", PL_BOOL, TRUE);
 | 
						|
  PL_set_prolog_flag("readline",    PL_BOOL, TRUE);
 | 
						|
}
 | 
						|
 | 
						|
/* destroy the console on exit.  Using PL_on_halt() is the clean, but somewhat
 | 
						|
   uncertain way.  using atexit() is more reliable, but we must be sure we don't
 | 
						|
   do it twice.
 | 
						|
*/
 | 
						|
 | 
						|
static rlc_console main_console;
 | 
						|
 | 
						|
static int
 | 
						|
closeWin(int s, void *a)
 | 
						|
{ rlc_console c = a;
 | 
						|
 | 
						|
//  closeConsoles();
 | 
						|
 | 
						|
  if ( c == main_console )
 | 
						|
  { main_console = NULL;
 | 
						|
    rlc_close(c);
 | 
						|
  }
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
#define MAX_ARGC 100
 | 
						|
 | 
						|
static size_t
 | 
						|
utf8_required_len(const wchar_t *s)
 | 
						|
{ size_t l = 0;
 | 
						|
  char tmp[6];
 | 
						|
  char *q;
 | 
						|
 | 
						|
  for( ; *s; s++)
 | 
						|
  { q = utf8_put_char(tmp, *s);
 | 
						|
    l += q-tmp;
 | 
						|
  }
 | 
						|
 | 
						|
  return l;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int
 | 
						|
win32main(rlc_console c, int argc, TCHAR **argv)
 | 
						|
{ char *av[MAX_ARGC+1];
 | 
						|
  int i;
 | 
						|
 | 
						|
  main_console = c;
 | 
						|
  set_window_title(c);
 | 
						|
  rlc_bind_terminal(c);
 | 
						|
 | 
						|
  if ( argc > MAX_ARGC )
 | 
						|
    argc = MAX_ARGC;
 | 
						|
  for(i=0; i<argc; i++)
 | 
						|
  { char *s;
 | 
						|
    TCHAR *q;
 | 
						|
 | 
						|
    av[i] = alloca(utf8_required_len(argv[i])+1);
 | 
						|
    for(s=av[i], q=argv[i]; *q; q++)
 | 
						|
    { s = utf8_put_char(s, *q);
 | 
						|
    }
 | 
						|
    *s = '\0';
 | 
						|
  }
 | 
						|
  av[i] = NULL;
 | 
						|
 | 
						|
  if ( !PL_initialise(argc, av) )
 | 
						|
    PL_halt(1);
 | 
						|
 | 
						|
  PL_register_extensions_in_module("system", extensions);
 | 
						|
  install_readline(c);
 | 
						|
  PL_action(PL_ACTION_GUIAPP, TRUE);
 | 
						|
  main_console = c;
 | 
						|
  PL_on_halt(closeWin, c);
 | 
						|
 | 
						|
  create_prolog_hidden_window(c, FALSE);
 | 
						|
  PL_set_prolog_flag("hwnd", PL_INTEGER, (intptr_t)rlc_hwnd(c));
 | 
						|
  rlc_interrupt_hook(interrupt);
 | 
						|
  rlc_menu_hook(menu_select);
 | 
						|
  rlc_message_hook(message_proc);
 | 
						|
  PL_set_prolog_flag("console_menu", PL_BOOL, TRUE);
 | 
						|
#ifdef O_PLMT
 | 
						|
  rlc_insert_menu_item(c, _T("&Run"), _T("&New thread"), NULL);
 | 
						|
#endif
 | 
						|
#if !defined(O_DEBUG) && !defined(_DEBUG)
 | 
						|
  initSignals();
 | 
						|
#endif
 | 
						|
  PL_register_foreign_in_module("system", "win_open_console", 5,
 | 
						|
				pl_win_open_console, 0);
 | 
						|
 | 
						|
  PL_halt(PL_toplevel() ? 0 : 1);
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
						|
And this is the  real  application's  main   as  Windows  sees  it.  See
 | 
						|
console.c for further details.
 | 
						|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | 
						|
 | 
						|
int WINAPI
 | 
						|
wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
 | 
						|
	LPWSTR lpCmdLine, int nShowCmd)
 | 
						|
{ LPTSTR cmdline;
 | 
						|
 | 
						|
  InitializeCriticalSection(&mutex);
 | 
						|
 | 
						|
  cmdline = GetCommandLine();
 | 
						|
 | 
						|
  return rlc_main(hInstance, hPrevInstance, cmdline, nShowCmd,
 | 
						|
		  win32main, LoadIcon(hInstance, _T("YAP_Icon")));
 | 
						|
}
 |