diff options
Diffstat (limited to 'ocaml-binary-annot/win32caml')
| -rw-r--r-- | ocaml-binary-annot/win32caml/Makefile | 57 | ||||
| -rw-r--r-- | ocaml-binary-annot/win32caml/editbuffer.c | 514 | ||||
| -rw-r--r-- | ocaml-binary-annot/win32caml/editbuffer.h | 47 | ||||
| -rw-r--r-- | ocaml-binary-annot/win32caml/history.c | 98 | ||||
| -rw-r--r-- | ocaml-binary-annot/win32caml/history.h | 35 | ||||
| -rw-r--r-- | ocaml-binary-annot/win32caml/inria.h | 134 | ||||
| -rw-r--r-- | ocaml-binary-annot/win32caml/inriares.h | 48 | ||||
| -rw-r--r-- | ocaml-binary-annot/win32caml/libgraph.h | 108 | ||||
| -rw-r--r-- | ocaml-binary-annot/win32caml/menu.c | 830 | ||||
| -rw-r--r-- | ocaml-binary-annot/win32caml/ocaml.c | 1599 | ||||
| -rw-r--r-- | ocaml-binary-annot/win32caml/ocaml.ico | bin | 0 -> 766 bytes | |||
| -rw-r--r-- | ocaml-binary-annot/win32caml/ocaml.rc | 255 | ||||
| -rw-r--r-- | ocaml-binary-annot/win32caml/resource.h | 16 | ||||
| -rw-r--r-- | ocaml-binary-annot/win32caml/startocaml.c | 362 |
14 files changed, 4103 insertions, 0 deletions
diff --git a/ocaml-binary-annot/win32caml/Makefile b/ocaml-binary-annot/win32caml/Makefile new file mode 100644 index 0000000000..a73b731521 --- /dev/null +++ b/ocaml-binary-annot/win32caml/Makefile @@ -0,0 +1,57 @@ +######################################################################### +# # +# Objective Caml # +# # +# Xavier Leroy, projet Cristal, INRIA Rocquencourt # +# # +# Copyright 2001 Institut National de Recherche en Informatique et # +# en Automatique. All rights reserved. This file is distributed # +# under the terms of the GNU Library General Public License, with # +# the special exception on linking described in file ../LICENSE. # +# # +######################################################################### + +# $Id$ + +include ../config/Makefile + +CC=$(BYTECC) +CFLAGS=$(BYTECCCOMPOPTS) + +OBJS=startocaml.$(O) ocamlres.$(O) ocaml.$(O) menu.$(O) \ + history.$(O) editbuffer.$(O) + +LIBS=$(call SYSLIB,kernel32) $(call SYSLIB,advapi32) $(call SYSLIB,gdi32) \ + $(call SYSLIB,user32) $(call SYSLIB,comdlg32) $(call SYSLIB,comctl32) + +all: ocamlwin.exe + +ocamlwin.exe: $(OBJS) + $(MKEXE) -o ocamlwin.exe $(OBJS) $(LIBS) $(EXTRALIBS) -subsystem windows + +ocamlres.$(O): ocaml.rc ocaml.ico +ifeq ($(TOOLCHAIN),msvc) + rc ocaml.rc +ifeq ($(ARCH),amd64) + cvtres /nologo /machine:amd64 /out:$@ ocaml.res +else + cvtres /nologo /machine:ix86 /out:$@ ocaml.res +endif + rm -f ocaml.res +endif +ifeq ($(TOOLCHAIN),mingw) + windres -i ocaml.rc -o $@ +endif + +$(OBJS): inria.h inriares.h history.h editbuffer.h + +clean: + rm -f ocamlwin.exe *.$(O) *.pdb ocamlwin.ilk + +install: + cp ocamlwin.exe $(PREFIX)/OCamlWin.exe + +.SUFFIXES: .c .$(O) + +.c.$(O): + $(CC) $(CFLAGS) -c $*.c diff --git a/ocaml-binary-annot/win32caml/editbuffer.c b/ocaml-binary-annot/win32caml/editbuffer.c new file mode 100644 index 0000000000..480d22d86a --- /dev/null +++ b/ocaml-binary-annot/win32caml/editbuffer.c @@ -0,0 +1,514 @@ +/***********************************************************************/ +/* */ +/* Objective Caml */ +/* */ +/* Developed by Jacob Navia. */ +/* Copyright 2001 Institut National de Recherche en Informatique et */ +/* en Automatique. All rights reserved. This file is distributed */ +/* under the terms of the GNU Library General Public License, with */ +/* the special exception on linking described in file ../LICENSE. */ +/* */ +/***********************************************************************/ + +/***********************************************************************/ +/* Changes made by Chris Watford to enhance the source editor */ +/* Began 14 Sept 2003 - watford@uiuc.edu */ +/***********************************************************************/ + +#include <string.h> +#include <stdlib.h> +#include "inriares.h" +#include "inria.h" + +/*------------------------------------------------------------------------ + Procedure: editbuffer_addline ID:1 + Author: Chris Watford watford@uiuc.edu + Purpose: Adds a line to the current edit buffer + Input: Line of text to append to the end + Output: + Errors: +-------------------------------------------------------------------------- + Edit History: + 18 Sept 2003 - Chris Watford watford@uiuc.edu + - Corrected doubly linked list issue +------------------------------------------------------------------------*/ +BOOL editbuffer_addline(EditBuffer* edBuf, char* line) +{ + LineList *tail = NULL; //head of the edit buffer line list + LineList *newline = NULL; + + // sanity check + if(edBuf == NULL) + { + return FALSE; + } + + // perform edit buffer sanity checks + if((edBuf->LineCount < 0) || (edBuf->Lines == NULL)) + { + edBuf->LineCount = 0; + } + + // move to the end of the line list in the edit buffer + if((tail = edBuf->Lines) != NULL) + for( ; tail->Next != NULL; tail = tail->Next); + + // create the new line entry + newline = (LineList*)SafeMalloc(sizeof(LineList)); + newline->Next = NULL; + newline->Prev = tail; + newline->Text = (char*)SafeMalloc(strlen(line)+1); + strncpy(newline->Text, line, strlen(line)+1); + newline->Text[strlen(line)] = '\0'; + + // add it to the list as the head or the tail + if(tail != NULL) + { + tail->Next = newline; + } else { + edBuf->Lines = newline; + } + + // update the number of lines in the buffer + edBuf->LineCount++; + + return TRUE; +} + +/*------------------------------------------------------------------------ + Procedure: editbuffer_updateline ID:1 + Author: Chris Watford watford@uiuc.edu + Purpose: Updates the edit buffer's internal contents for a line + Input: idx - Line index + line - String to add + Output: if the line was updated or not + Errors: +------------------------------------------------------------------------*/ +BOOL editbuffer_updateline(EditBuffer* edBuf, int idx, char* line) +{ + LineList *update = edBuf->Lines; //head of the edit buffer line list + LineList *newline = NULL; + int i; + + // sanity checks + if(edBuf == NULL) + { + return FALSE; + } else if( (edBuf->LineCount == 0) || + (edBuf->Lines == NULL) || + (idx >= edBuf->LineCount) || + (idx < 0) ) { + return FALSE; + } + + // move to the index in the line list + // i left in update != NULL as a sanity check + for(i = 0; ((update != NULL) && (i != idx)); update = update->Next, i++); + + // did things mess up? + if( (update == NULL) || (i != idx) ) + { + return FALSE; + } + + // get rid of the old line + free(update->Text); + + // get the new line updated + update->Text = (char*)SafeMalloc(strlen(line)+1); + strncpy(update->Text, line, strlen(line)+1); + update->Text[strlen(line)] = '\0'; + + return TRUE; +} + +/*------------------------------------------------------------------------ + Procedure: editbuffer_updateoraddline ID:1 + Author: Chris Watford watford@uiuc.edu + Purpose: Updates the edit buffer's internal contents for a line + Input: idx - Line index + line - String to add + Output: if the line was updated or not + Errors: +------------------------------------------------------------------------*/ +BOOL editbuffer_updateoraddline(EditBuffer* edBuf, int idx, char* line) +{ + LineList *update; + + // sanity checks + if(edBuf == NULL) + { + return FALSE; + } else if((idx > edBuf->LineCount) || (idx < 0)) { + return FALSE; + } + + update = edBuf->Lines; //head of the edit buffer line list + + // do we update or add? + if((idx < edBuf->LineCount) && (edBuf->Lines != NULL)) + { //interior line, update + return editbuffer_updateline(edBuf, idx, line); + } else { + //fence line, add + return editbuffer_addline(edBuf, line); + } +} + +/*------------------------------------------------------------------------ + Procedure: editbuffer_removeline ID:1 + Author: Chris Watford watford@uiuc.edu + Purpose: Removes a line from the edit buffer + Input: idx - Line index to remove + Output: if the line was removed or not + Errors: +-------------------------------------------------------------------------- + Edit History: + 18 Sept 2003 - Chris Watford watford@uiuc.edu + - Added to allow backspace and delete support + - Corrected doubly linked list issue +------------------------------------------------------------------------*/ +BOOL editbuffer_removeline(EditBuffer* edBuf, int idx) +{ + LineList *update = NULL; + int i = 0; + + // sanity checks + if(edBuf == NULL) + { + return FALSE; + } else if( (edBuf->LineCount == 0) || + (edBuf->Lines == NULL) || + (idx >= edBuf->LineCount) || + (idx < 0) ) { + return FALSE; + } + + // move to the index in the line list + // i left in update != NULL as a sanity check + for(i = 0, update = edBuf->Lines; ((update != NULL) && (i != idx)); update = update->Next, i++); + + // remove this line + if(update != NULL) + { + // break links, removing our line + if(update->Prev != NULL) + { + // we're not the first so just break the link + update->Prev->Next = update->Next; + + // fix the prev check + if(update->Next != NULL) + update->Next->Prev = update->Prev; + } else { + // we're the first, attach the next guy to lines + edBuf->Lines = update->Next; + } + + // one less line to worry about + edBuf->LineCount--; + + // get rid of the text + if(update->Text != NULL) + free(update->Text); + + // get rid of us + free(update); + + return TRUE; + } + + return FALSE; +} + +/*------------------------------------------------------------------------ + Procedure: editbuffer_getasline ID:1 + Author: Chris Watford watford@uiuc.edu + Purpose: Returns the edit buffer as one big line, \n's and \t's + become spaces. + Input: + Output: + Errors: +------------------------------------------------------------------------*/ +char* editbuffer_getasline(EditBuffer* edBuf) +{ + LineList *line = NULL; //head of the edit buffer line list + char* retline = (char*)realloc(NULL, 1); + unsigned int i = 0; + + // fix retline bug + retline[0] = '\0'; + + // sanity checks + if(edBuf == NULL) + { + return NULL; + } else if (edBuf->LineCount == 0 || edBuf->Lines == NULL) { + // fix any possible errors that may come from this + edBuf->LineCount = 0; + edBuf->Lines = NULL; + return NULL; + } + + // get the big line + for(line = edBuf->Lines; line != NULL; line = line->Next) + { + if(line->Text != NULL) + { + retline = (char*)realloc(retline, (strlen(retline) + strlen(line->Text) + (strlen(retline) > 0 ? 2 : 1))); + + if(strlen(retline) > 0) + retline = strcat(retline, " "); + + retline = strcat(retline, line->Text); + + //concat in the hoouuusssseee! + } + } + + // now we have the big line, so lets ditch all \n's \t's and \r's + for(i = 0; i < strlen(retline); i++) + { + switch(retline[i]) + { + case '\n': + case '\t': + case '\r': + retline[i] = ' '; + } + } + + return retline; +} + +/*------------------------------------------------------------------------ + Procedure: editbuffer_getasbuffer ID:1 + Author: Chris Watford watford@uiuc.edu + Purpose: Returns the edit buffer as one big line, \n's and \t's + become spaces. + Input: + Output: + Errors: +------------------------------------------------------------------------*/ +char* editbuffer_getasbuffer(EditBuffer* edBuf) +{ + LineList *line = NULL; //head of the edit buffer line list + char* retbuf = (char*)realloc(NULL, 1); + unsigned int i = 0; + + // fix retline bug + retbuf[0] = '\0'; + + // sanity checks + if(edBuf == NULL) + { + return NULL; + } else if (edBuf->LineCount == 0 || edBuf->Lines == NULL) { + // fix any possible errors that may come from this + edBuf->LineCount = 0; + edBuf->Lines = NULL; + return NULL; + } + + // get the big line + for(line = edBuf->Lines; line != NULL; line = line->Next) + { + if(line->Text != NULL) + { + int len = strlen(retbuf); + len += strlen(line->Text) + (len > 0 ? 3 : 1); + + retbuf = (char*)realloc(retbuf, len); + + if(strlen(retbuf) > 0) + retbuf = strcat(retbuf, "\r\n"); + + retbuf = strcat(retbuf, line->Text); + + retbuf[len-1] = '\0'; + + //concat in the hoouuusssseee! + } + } + + return retbuf; +} + +/*------------------------------------------------------------------------ + Procedure: editbuffer_lastline ID:1 + Author: Chris Watford watford@uiuc.edu + Purpose: Returns the last line in the edit buffer + Input: + Output: + Errors: +------------------------------------------------------------------------*/ +char* editbuffer_lastline(EditBuffer* edBuf) +{ + LineList *line = NULL; //head of the edit buffer line list + + // sanity checks + if(edBuf == NULL) + { + return NULL; + } else if (edBuf->LineCount == 0 || edBuf->Lines == NULL) { + // fix any possible errors that may come from this + edBuf->LineCount = 0; + edBuf->Lines = NULL; + return NULL; + } + + // go to the last line + for(line = edBuf->Lines; line->Next != NULL; line = line->Next); + + return line->Text; +} + +/*------------------------------------------------------------------------ + Procedure: editbuffer_copy ID:1 + Author: Chris Watford watford@uiuc.edu + Purpose: Makes an exact copy of an edit buffer + Input: + Output: + Errors: +-------------------------------------------------------------------------- + Edit History: + 16 Sept 2003 - Chris Watford watford@uiuc.edu + - Added to make copies of history entries + 18 Sept 2003 - Chris Watford watford@uiuc.edu + - Corrected doubly linked list issue + 06 Oct 2003 - Chris Watford watford@uiuc.edu + - Added isCorrect flag +------------------------------------------------------------------------*/ +EditBuffer* editbuffer_copy(EditBuffer* edBuf) +{ + // sanity checks + if(edBuf == NULL) + { + return NULL; + } else { + EditBuffer* copy = (EditBuffer*)SafeMalloc(sizeof(EditBuffer)); + LineList* lines = edBuf->Lines; + LineList* lastLine = NULL; + + // clear its initial values + copy->LineCount = 0; + copy->Lines = NULL; + copy->isCorrect = FALSE; + + // well we don't have to copy much + if((lines == NULL) || (edBuf->LineCount <= 0)) + { + return copy; + } + + // get if its correct + copy->isCorrect = edBuf->isCorrect; + + // go through each line, malloc it and add it + for( ; lines != NULL; lines = lines->Next) + { + LineList* curline = (LineList*)SafeMalloc(sizeof(LineList)); + curline->Next = NULL; + curline->Prev = NULL; + + // if there was a last line, link them to us + if(lastLine != NULL) + { + lastLine->Next = curline; + curline->Prev = lastLine; + } + + // are we the first line? add us to the edit buffer as the first + if(copy->Lines == NULL) + { + copy->Lines = curline; + } + + // check if there is text on the line + if(lines->Text == NULL) + { // no text, make it blankz0r + curline->Text = (char*)SafeMalloc(sizeof(char)); + curline->Text[0] = '\0'; + } else { + // there is text, copy it and null-terminate + curline->Text = (char*)SafeMalloc(strlen(lines->Text) + 1); + strncpy(curline->Text, lines->Text, strlen(lines->Text)); + curline->Text[strlen(lines->Text)] = '\0'; + } + + // up the line count and make us the last line + copy->LineCount++; + lastLine = curline; + } + + // return our new copy + return copy; + } +} + +/*------------------------------------------------------------------------ + Procedure: editbuffer_destroy ID:1 + Author: Chris Watford watford@uiuc.edu + Purpose: Destroys an edit buffer + Input: + Output: + Errors: +------------------------------------------------------------------------*/ +void editbuffer_destroy(EditBuffer* edBuf) +{ + // sanity checks + if(edBuf == NULL) + { // nothing to do + return; + } else if(edBuf->Lines != NULL) { + LineList* lastline = NULL; + + // loop through each line free'ing its text + for( ; edBuf->Lines != NULL; edBuf->Lines = edBuf->Lines->Next) + { + if(edBuf->Lines->Text != NULL) + free(edBuf->Lines->Text); + + // if there was a line before us, free it + if(lastline != NULL) + { + free(lastline); + lastline = NULL; + } + + lastline = edBuf->Lines; + } + + // free the last line + free(lastline); + } + + // free ourself + free(edBuf); +} + +/*------------------------------------------------------------------------ + Procedure: editbuffer_new ID:1 + Author: Chris Watford watford@uiuc.edu + Purpose: Creates an edit buffer + Input: + Output: + Errors: +-------------------------------------------------------------------------- + Edit History: + 06 Oct 2003 - Chris Watford watford@uiuc.edu + - Added isCorrect flag +------------------------------------------------------------------------*/ +EditBuffer* editbuffer_new(void) +{ + // create a new one + EditBuffer *edBuf = (EditBuffer*)SafeMalloc(sizeof(EditBuffer)); + + // default vals + edBuf->LineCount = 0; + edBuf->Lines = NULL; + edBuf->isCorrect = FALSE; + + // return it + return edBuf; +} diff --git a/ocaml-binary-annot/win32caml/editbuffer.h b/ocaml-binary-annot/win32caml/editbuffer.h new file mode 100644 index 0000000000..91e2999c31 --- /dev/null +++ b/ocaml-binary-annot/win32caml/editbuffer.h @@ -0,0 +1,47 @@ +/***********************************************************************/ +/* */ +/* Objective Caml */ +/* */ +/* Jacob Navia, after Xavier Leroy */ +/* */ +/* Copyright 2001 Institut National de Recherche en Informatique et */ +/* en Automatique. All rights reserved. This file is distributed */ +/* under the terms of the GNU Library General Public License, with */ +/* the special exception on linking described in file ../LICENSE. */ +/* */ +/***********************************************************************/ + +/***********************************************************************/ +/* Changes made by Chris Watford to enhance the source editor */ +/* Began 14 Sept 2003 - watford@uiuc.edu */ +/***********************************************************************/ + +#ifndef _EDITBUFFER_H_ +#define _EDITBUFFER_H_ + +// All the below was added by Chris Watford watford@uiuc.edu + +typedef struct tagLineList { + struct tagLineList *Next; + struct tagLineList *Prev; + char *Text; +} LineList; + +typedef struct tagEditBuffer { + int LineCount; + struct tagLineList *Lines; + BOOL isCorrect; +} EditBuffer; + +BOOL editbuffer_addline (EditBuffer* edBuf, char* line); +BOOL editbuffer_updateline (EditBuffer* edBuf, int idx, char* line); +BOOL editbuffer_updateoraddline (EditBuffer* edBuf, int idx, char* line); +BOOL editbuffer_removeline (EditBuffer* edBuf, int idx); +char* editbuffer_getasline (EditBuffer* edBuf); +char* editbuffer_getasbuffer (EditBuffer* edBuf); +char* editbuffer_lastline (EditBuffer* edBuf); +EditBuffer* editbuffer_copy (EditBuffer* edBuf); +void editbuffer_destroy (EditBuffer* edBuf); +EditBuffer* editbuffer_new (void); + +#endif diff --git a/ocaml-binary-annot/win32caml/history.c b/ocaml-binary-annot/win32caml/history.c new file mode 100644 index 0000000000..11397ac66a --- /dev/null +++ b/ocaml-binary-annot/win32caml/history.c @@ -0,0 +1,98 @@ +/***********************************************************************/ +/* */ +/* Objective Caml */ +/* */ +/* Jacob Navia, after Xavier Leroy */ +/* */ +/* Copyright 2001 Institut National de Recherche en Informatique et */ +/* en Automatique. All rights reserved. This file is distributed */ +/* under the terms of the GNU Library General Public License, with */ +/* the special exception on linking described in file ../LICENSE. */ +/* */ +/***********************************************************************/ + +/***********************************************************************/ +/* Changes made by Chris Watford to enhance the source editor */ +/* Began 14 Sept 2003 - watford@uiuc.edu */ +/***********************************************************************/ + +#include "inria.h" +#include "history.h" + +/*------------------------------------------------------------------------ +Procedure: AddToHistory ID:2 +Author: Chris Watford watford@uiuc.edu +Purpose: Adds an edit buffer to the history control +Input: Pointer to the edit buffer to add +Output: +Errors: +-------------------------------------------------------------------------- +Edit History: + 15 Sept 2003 - Chris Watford watford@uiuc.edu + - Complete rewrite + - Got it to add the edit buffer to the history + 17 Sept 2003 - Chris Watford watford@uiuc.edu + - Added doubly link list support +------------------------------------------------------------------------*/ +void AddToHistory(EditBuffer *edBuf) +{ + StatementHistory *newLine; + + // sanity checks + if(edBuf == NULL) + { + return; + } else if (edBuf->LineCount == 0 || edBuf->Lines == NULL) { + // fix any possible errors that may come from this + edBuf->LineCount = 0; + edBuf->Lines = NULL; + return; + } + + // setup newline and add as the front of the linked list + newLine = SafeMalloc(sizeof(StatementHistory)); + newLine->Next = History; + newLine->Prev = NULL; + newLine->Statement = edBuf; + + // setup back linking + if(History != NULL) + History->Prev = newLine; + + // set the history up + History = newLine; + + // search for the new history tail + for(HistoryTail = (HistoryTail != NULL ? HistoryTail : History); HistoryTail->Next != NULL; HistoryTail = HistoryTail->Next); +} + +/*------------------------------------------------------------------------ +Procedure: GetHistoryLine ID:2 +Author: Chris Watford watford@uiuc.edu +Purpose: Returns an entry from the history table +Input: Index of the history entry to return +Output: The history entry as a single line +Errors: +-------------------------------------------------------------------------- +Edit History: + 15 Sept 2003 - Chris Watford watford@uiuc.edu + - Complete rewrite + 17 Sept 2003 - Chris Watford watford@uiuc.edu + - Added doubly link list support +------------------------------------------------------------------------*/ +char *GetHistoryLine(int n) +{ + StatementHistory *histentry = History; + int i; + + // traverse linked list looking for member n + for (i = 0; ((i < n) && (histentry != NULL)); i++, histentry = histentry->Next); + + // figure out what to return + if (histentry != NULL) + { + return editbuffer_getasline(histentry->Statement); + } else { + return ""; + } +} diff --git a/ocaml-binary-annot/win32caml/history.h b/ocaml-binary-annot/win32caml/history.h new file mode 100644 index 0000000000..a9ba85841b --- /dev/null +++ b/ocaml-binary-annot/win32caml/history.h @@ -0,0 +1,35 @@ +/***********************************************************************/ +/* */ +/* Objective Caml */ +/* */ +/* Jacob Navia, after Xavier Leroy */ +/* */ +/* Copyright 2001 Institut National de Recherche en Informatique et */ +/* en Automatique. All rights reserved. This file is distributed */ +/* under the terms of the GNU Library General Public License, with */ +/* the special exception on linking described in file ../LICENSE. */ +/* */ +/***********************************************************************/ + +/***********************************************************************/ +/* Changes made by Chris Watford to enhance the source editor */ +/* Began 14 Sept 2003 - watford@uiuc.edu */ +/***********************************************************************/ + +#ifndef _HISTORY_H_ +#define _HISTORY_H_ + +#include "editbuffer.h" + +// Simple linked list for holding the history lines +typedef struct tagStatementHistory { + struct tagStatementHistory *Next; + struct tagStatementHistory *Prev; + EditBuffer *Statement; +} StatementHistory; + +void AddToHistory (EditBuffer *edBuf); +char *GetHistoryLine (int n); +static BOOL CALLBACK HistoryDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); + +#endif diff --git a/ocaml-binary-annot/win32caml/inria.h b/ocaml-binary-annot/win32caml/inria.h new file mode 100644 index 0000000000..095cbcc750 --- /dev/null +++ b/ocaml-binary-annot/win32caml/inria.h @@ -0,0 +1,134 @@ +/***********************************************************************/ +/* */ +/* Objective Caml */ +/* */ +/* Developed by Jacob Navia. */ +/* Copyright 2001 Institut National de Recherche en Informatique et */ +/* en Automatique. All rights reserved. This file is distributed */ +/* under the terms of the GNU Library General Public License, with */ +/* the special exception on linking described in file ../LICENSE. */ +/* */ +/***********************************************************************/ + +/* $Id$ */ + +/*------------------------------------------------------------------------ + Module: D:\lcc\inria\inria.h + Author: Jacob + Project: + State: + Creation Date: June 2001 + Description: The user interface works as follows: + 1: At startup it will look for the path to the + ocaml interpreter in the registry using the + key HKEY_CURRENT_USER\SOFTWARE\ocaml. If not + found will prompt the user. + 2: It will start the ocaml interpreter with + its standard output and standard input + connected to two pipes in a dedicated thread. + 3: It will open a window containing an edit + field. The output from the interpreter will be + shown in the edit field, and the input of the + user in the edit field will be sent to the + interpreter when the user types return. + 4: Line editing is provided by moving to the + desired line with the arrows, then pressing + return; If we aren't in the last input line, + the input will be copied to the last line and + sent to the interpreter. + 5: The GUI ensures that when we exit the ocaml + interpreter is stopped by sending the + character string "#quit;;\nCtrl-Z" + 6: A history of all lines sent to the interpreter + is maintained in a simple linked list. The + History dialog box shows that, and allows the + user to choose a given input line. + 7: Memory limits. The edit buffer can be of an + arbitrary length, i.e. maybe 7-8MB or more, + there are no fixed limits. The History list + will always grow too, so memory consumption + could be "high" after several days of + uninterrupted typing at the keyboard. For that + cases it is recommended to stop the GUI and + get some sleep... + 9: The GUI will start a timer, looking 4 times a + second if the interpreter has written + something in the pipe. This is enough for most + applications. +------------------------------------------------------------------------*/ +#ifndef _INRIA_H_ +#define _INRIA_H_ + +#include <windows.h> +#include "editbuffer.h" +#include "history.h" + +#if _MSC_VER <= 1200 && !defined(__MINGW32__) +#define GetWindowLongPtr GetWindowLong +#define SetWindowLongPtr SetWindowLong +#define DWLP_USER DWL_USER +#define GWLP_WNDPROC GWL_WNDPROC +#define LONG_PTR DWORD +#endif + +// In this structure should go eventually all global variables scattered +// through the program. +typedef struct _programParams { + HFONT hFont; // The handle of the current font + COLORREF TextColor; // The text color + char CurrentWorkingDir[MAX_PATH];// The current directory +} PROGRAM_PARAMS; + +//**************** Global variables *********************** +extern PROGRAM_PARAMS ProgramParams; + +extern COLORREF BackColor; // The background color +extern HBRUSH BackgroundBrush; // A brush built with the background color +extern char LibDir[]; // The lib directory +extern char OcamlPath[]; // The Path to ocaml.exe +extern HANDLE hInst; // The instance handle for this application +extern HWND hwndSession; // The current session window handle +extern LOGFONT CurrentFont; // The current font characteristics +extern HWND hwndMain,hwndMDIClient; // Window handles of frame and mdi window + +// ***************** Function prototypes ****************** +int WriteToPipe(char *data); // Writes to the pipe +int ReadFromPipe(char *data,int len);// Reads from the pipe +int AskYesOrNo(char *msg); //Ditto! +int BrowseForFile(char *fname,char *path); +void GotoEOF(void); // Positions the cursor at the end of the text +void ShowDbgMsg(char *msg); // Shows an error message +void HandleCommand(HWND hwnd, WPARAM wParam,LPARAM lParam); +int GetOcamlPath(void); // Finds where ocaml.exe is +void ForceRepaint(void); // Ditto. +void AddLineToControl(char *buf); +void AddStringToControl(char* buf); +char *GetHistoryLine(int n); // Gets the nth history line base 1. +int StartOcaml(void); +void InterruptOcaml(void); +int ResetText(void); +BOOL SendingFullCommand(void); +void RewriteCurrentEditBuffer(void); +void RefreshCurrentEditBuffer(void); + +// **************** User defined window messages ************* +#define WM_NEWLINE (WM_USER+6000) +#define WM_TIMERTICK (WM_USER+6001) +#define WM_QUITOCAML (WM_USER+6002) +#define WM_SYNTAXERROR (WM_USER+6003) +#define WM_UNBOUNDVAL (WM_USER+6004) +#define WM_ILLEGALCHAR (WM_USER+6005) + +// ********************** Structures *********************** +typedef struct tagPosition { + int line; + int col; +} POSITION; + +extern void *SafeMalloc(int); +extern StatementHistory *History; // The root of the history lines +extern StatementHistory *HistoryTail; // The tail of the history lines +extern EditBuffer *CurrentEditBuffer; // current edit buffer + +#define IDEDITCONTROL 15432 +#endif diff --git a/ocaml-binary-annot/win32caml/inriares.h b/ocaml-binary-annot/win32caml/inriares.h new file mode 100644 index 0000000000..2043a37d79 --- /dev/null +++ b/ocaml-binary-annot/win32caml/inriares.h @@ -0,0 +1,48 @@ +/* Weditres generated include file. Do NOT edit */ +#define IDD_ABOUT 100 +#define IDM_NEW 200 +#define IDM_OPEN 210 +#define IDM_SAVE 220 +#define IDM_SAVEAS 230 +#define IDM_CLOSE 240 +#define IDM_PRINT 250 +#define IDM_PRINTSU 260 +#define IDM_PRINTPRE 265 +#define IDM_PAGESETUP 267 +#define IDM_EXIT 270 +#define IDM_HISTORY 281 +#define IDM_GC 282 +#define IDCTRLC 283 +#define IDD_HISTORY 300 +#define IDLIST 301 +#define IDM_EDITUNDO 310 +#define IDM_EDITCUT 320 +#define IDM_EDITCOPY 330 +#define IDM_EDITPASTE 340 +#define IDM_EDITCLEAR 350 +#define IDM_EDITDELETE 360 +#define IDM_EDITREPLACE 370 +#define IDM_EDITREDO 380 +#define IDM_WINDOWTILE 410 +#define IDM_WINDOWCASCADE 420 +#define IDM_WINDOWICONS 430 +#define IDM_WINDOWCLOSEALL 440 +#define IDM_PROPERTIES 450 +#define IDM_ABOUT 500 +#define IDM_HELP 510 +#define IDMAINMENU 600 +#define IDM_FIND 700 +#define IDAPPLICON 710 +#define IDI_CHILDICON 800 +#define IDAPPLCURSOR 810 +#define OCAML_ICON 1000 +#define IDS_FILEMENU 2000 +#define IDS_HELPMENU 2010 +#define IDS_SYSMENU 2030 +#define IDM_STATUSBAR 3000 +#define IDM_WINDOWCHILD 3010 +#define ID_TOOLBAR 5000 +#define IDACCEL 10000 +#define IDM_FONT 40002 +#define IDM_COLORTEXT 40004 +#define IDM_BACKCOLOR 40005 diff --git a/ocaml-binary-annot/win32caml/libgraph.h b/ocaml-binary-annot/win32caml/libgraph.h new file mode 100644 index 0000000000..3bfaff301f --- /dev/null +++ b/ocaml-binary-annot/win32caml/libgraph.h @@ -0,0 +1,108 @@ +/***********************************************************************/ +/* */ +/* Objective Caml */ +/* */ +/* Jacob Navia, after Xavier Leroy */ +/* */ +/* Copyright 2001 Institut National de Recherche en Informatique et */ +/* en Automatique. All rights reserved. This file is distributed */ +/* under the terms of the GNU Library General Public License, with */ +/* the special exception on linking described in file ../LICENSE. */ +/* */ +/***********************************************************************/ + +/* $Id$ */ + +#include <stdio.h> +#include <windows.h> + +struct canvas { + int w, h; /* Dimensions of the drawable */ + HWND win; /* The drawable itself */ + HDC gc; /* The associated graphics context */ +}; + +extern HWND grdisplay; /* The display connection */ +//extern int grscreen; /* The screen number */ +//extern Colormap grcolormap; /* The color map */ +//extern struct canvas grwindow; /* The graphics window */ +//extern struct canvas grbstore; /* The pixmap used for backing store */ +//extern int grwhite, grblack; /* Black and white pixels for X */ +//extern int grbackground; /* Background color for X +// (used for CAML color -1) */ +extern COLORREF grbackground; +extern BOOL grdisplay_mode; /* Display-mode flag */ +extern BOOL grremember_mode; /* Remember-mode flag */ +extern int grx, gry; /* Coordinates of the current point */ +extern int grcolor; /* Current *CAML* drawing color (can be -1) */ +extern HFONT * grfont; /* Current font */ + +extern BOOL direct_rgb; +extern int byte_order; +extern int bitmap_unit; +extern int bits_per_pixel; + +#define Wcvt(y) (grwindow.height - 1 - (y)) +#define Bcvt(y) (grwindow.height - 1 - (y)) +#define WtoB(y) ((y) + WindowRect.bottom - grwindow.h) +//#define BtoW(y) ((y) + WindowRect.bottom - grbstore.h) + +#define DEFAULT_SCREEN_WIDTH 1024 +#define DEFAULT_SCREEN_HEIGHT 768 +#define BORDER_WIDTH 2 +#define WINDOW_NAME "Caml graphics" +#define ICON_NAME "Caml graphics" +#define DEFAULT_EVENT_MASK \ + (ExposureMask | KeyPressMask | StructureNotifyMask) +#define DEFAULT_FONT "fixed" +#define SIZE_QUEUE 256 + +/* To handle events asynchronously */ +#ifdef HAS_ASYNC_IO +#define USE_ASYNC_IO +#define EVENT_SIGNAL SIGIO +#else +#ifdef HAS_SETITIMER +#define USE_INTERVAL_TIMER +#define EVENT_SIGNAL SIGALRM +#else +#define USE_ALARM +#define EVENT_SIGNAL SIGALRM +#endif +#endif + +void gr_fail(char *fmt, char *arg); +void gr_check_open(void); +unsigned long gr_pixel_rgb(int rgb); +int gr_rgb_pixel(long unsigned int pixel); +void gr_enqueue_char(unsigned char c); +void gr_init_color_cache(void); + +// Windows specific definitions +extern RECT WindowRect; +extern int grCurrentColor; + +typedef struct tagWindow { + HDC gc; + HDC gcBitmap; + HWND hwnd; + HBRUSH CurrentBrush; + HPEN CurrentPen; + DWORD CurrentColor; + int width; + int height; + int grx; + int gry; + HBITMAP hBitmap; + HFONT CurrentFont; + int CurrentFontSize; + HDC tempDC; // For image operations; +} GR_WINDOW; + +extern GR_WINDOW grwindow; +HFONT CreationFont(char *name); +extern int MouseLbuttonDown,MouseMbuttonDown,MouseRbuttonDown; +extern HANDLE EventHandle; +extern int InspectMessages; +extern MSG msg; + diff --git a/ocaml-binary-annot/win32caml/menu.c b/ocaml-binary-annot/win32caml/menu.c new file mode 100644 index 0000000000..9ab0f5f37e --- /dev/null +++ b/ocaml-binary-annot/win32caml/menu.c @@ -0,0 +1,830 @@ +/***********************************************************************/ +/* */ +/* Objective Caml */ +/* */ +/* Developed by Jacob Navia. */ +/* Copyright 2001 Institut National de Recherche en Informatique et */ +/* en Automatique. All rights reserved. This file is distributed */ +/* under the terms of the GNU Library General Public License, with */ +/* the special exception on linking described in file ../LICENSE. */ +/* */ +/***********************************************************************/ + +/***********************************************************************/ +/* Changes made by Chris Watford to enhance the source editor */ +/* Began 14 Sept 2003 - watford@uiuc.edu */ +/***********************************************************************/ + +/* $Id$ */ + +#include <stdio.h> +#include <windows.h> +#include <Richedit.h> +#include "inria.h" +#include "inriares.h" +#include "history.h" + +LOGFONT CurrentFont; +int CurrentFontFamily = (FIXED_PITCH | FF_MODERN); +int CurrentFontStyle; +char CurrentFontName[64] = "Courier"; + +/*------------------------------------------------------------------------ + Procedure: OpenMlFile ID:1 + Purpose: Opens a file, either a source file (*.ml) or an *.cmo + file. + Input: A buffer where the name will be stored, and its + length + Output: The user's choice will be stored in the buffer. + Errors: None +------------------------------------------------------------------------*/ +int OpenMlFile(char *fname,int lenbuf) +{ + OPENFILENAME ofn; + int r; + char *p,defext[5],tmp[512]; + + memset(&ofn,0,sizeof(OPENFILENAME)); + memset(tmp,0,sizeof(tmp)); + fname[0] = 0; + strcpy(tmp,"ocaml sources|*.ml|bytecode object files|*.cmo|All files|*.*"); + p = tmp; + while (*p) { + if (*p == '|') + *p = 0; + p++; + } + strcpy(defext,"ml"); + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = hwndMain; + ofn.lpstrFilter = tmp; + ofn.nFilterIndex = 1; + ofn.hInstance = hInst; + ofn.lpstrFile = fname; + ofn.lpstrTitle = "Open file"; + ofn.lpstrInitialDir = LibDir; + ofn.nMaxFile = lenbuf; + ofn.Flags = OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR | OFN_LONGNAMES | + OFN_HIDEREADONLY |OFN_EXPLORER; + r = GetOpenFileName(&ofn); + if (r) { + /* Replace backslashes by forward slashes in file name */ + for (p = fname; *p != 0; p++) + if (*p == '\\') *p = '/'; + } + return r; +} + +/*------------------------------------------------------------------------ + Procedure: GetSaveName ID:1 + Purpose: Get a name to save the current session (Save as menu + item) + Input: A buffer where the name of the file will be stored, + and its length + Output: The name of the file choosen by the user will be + stored in the buffer + Errors: none +------------------------------------------------------------------------*/ +int GetSaveName(char *fname,int lenbuf) +{ + OPENFILENAME ofn; + int r; + char *p,defext[5],tmp[512]; + + memset(&ofn,0,sizeof(OPENFILENAME)); + memset(tmp,0,sizeof(tmp)); + fname[0] = 0; + strcpy(tmp,"Text files|*.txt"); + p = tmp; + while (*p) { + if (*p == '|') + *p = 0; + p++; + } + strcpy(defext,"txt"); + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = hwndMain; + ofn.lpstrFilter = tmp; + ofn.nFilterIndex = 1; + ofn.hInstance = hInst; + ofn.lpstrFile = fname; + ofn.lpstrTitle = "Save as"; + ofn.lpstrInitialDir = LibDir; + ofn.nMaxFile = lenbuf; + ofn.Flags = OFN_NOCHANGEDIR | OFN_LONGNAMES | + OFN_HIDEREADONLY |OFN_EXPLORER; + r = GetSaveFileName(&ofn); + if (r == 0) + return 0; + else return 1; +} + +/*------------------------------------------------------------------------ + Procedure: GetSaveMLName ID:1 + Purpose: Get a name to save the current OCaml code to (Save as menu + item) + Input: A buffer where the name of the file will be stored, + and its length + Output: The name of the file choosen by the user will be + stored in the buffer + Errors: none +------------------------------------------------------------------------*/ +int GetSaveMLName(char *fname, int lenbuf) +{ + OPENFILENAME ofn; + int r; + char *p,defext[5],tmp[512]; + + memset(&ofn,0,sizeof(OPENFILENAME)); + memset(tmp,0,sizeof(tmp)); + fname[0] = 0; + strcpy(tmp,"OCaml Source Files|*.ml"); + p = tmp; + while (*p) { + if (*p == '|') + *p = 0; + p++; + } + strcpy(defext,"ml"); + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = hwndMain; + ofn.lpstrFilter = tmp; + ofn.nFilterIndex = 1; + ofn.hInstance = hInst; + ofn.lpstrFile = fname; + ofn.lpstrTitle = "Save as"; + ofn.lpstrInitialDir = LibDir; + ofn.nMaxFile = lenbuf; + ofn.Flags = OFN_NOCHANGEDIR | OFN_LONGNAMES | + OFN_HIDEREADONLY |OFN_EXPLORER; + r = GetSaveFileName(&ofn); + if (r == 0) + return 0; + else return 1; +} + +/*------------------------------------------------------------------------ + Procedure: BrowseForFile ID:1 + Purpose: Let's the user browse for a certain kind of file. + Currently this is only used when browsing for + ocaml.exe. + Input: The name of the file to browse for, and the path + where the user's choice will be stored. + Output: 1 if user choosed a path, zero otherwise + Errors: None +------------------------------------------------------------------------*/ +int BrowseForFile(char *fname,char *path) +{ + OPENFILENAME ofn; + char *p,tmp[512],browsefor[512]; + int r; + + memset(tmp,0,sizeof(tmp)); + strncpy(tmp,fname,sizeof(tmp)-1); + p = tmp; + while (*p) { + if (*p == '|') + *p = 0; + p++; + } + memset(&ofn,0,sizeof(OPENFILENAME)); + ofn.lpstrFilter = tmp; + ofn.nFilterIndex = 1; + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = hwndMain; + ofn.hInstance = hInst; + ofn.lpstrFilter = tmp; + ofn.lpstrFile = path; + wsprintf(browsefor,"Open %s",fname); + ofn.lpstrTitle = browsefor; + ofn.lpstrInitialDir = "c:\\"; + ofn.nMaxFile = MAX_PATH; + ofn.Flags = OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR | OFN_LONGNAMES | + OFN_HIDEREADONLY |OFN_EXPLORER; + r = GetOpenFileName(&ofn); + if (r == 0) + return 0; + else return 1; +} + +/*------------------------------------------------------------------------ + Procedure: CallChangeFont ID:1 + Purpose: Calls the standard windows font change dialog. If the + user validates a font, it will destroy the current + font, and recreate a new font with the given + parameters. + Input: The calling window handle + Output: Zero if the user cancelled, 1 otherwise. + Errors: None +------------------------------------------------------------------------*/ +static int CallChangeFont(HWND hwnd) +{ + LOGFONT lf; + CHOOSEFONT cf; + int r; + HWND hwndChild; + + memset(&cf, 0, sizeof(CHOOSEFONT)); + memcpy(&lf, &CurrentFont, sizeof(LOGFONT)); + cf.lStructSize = sizeof(CHOOSEFONT); + cf.hwndOwner = hwnd; + cf.lpLogFont = &lf; + cf.Flags = CF_SCREENFONTS | CF_EFFECTS | CF_APPLY | CF_INITTOLOGFONTSTRUCT; + cf.nFontType = SCREEN_FONTTYPE; + r = ChooseFont(&cf); + if (!r) + return (0); + DeleteObject(ProgramParams.hFont); + memcpy(&CurrentFont, &lf, sizeof(LOGFONT)); + ProgramParams.hFont = CreateFontIndirect(&CurrentFont); + strcpy(CurrentFontName, CurrentFont.lfFaceName); + CurrentFontFamily = lf.lfPitchAndFamily; + CurrentFontStyle = lf.lfWeight; + hwndChild = (HWND) GetWindowLongPtr(hwndSession, DWLP_USER); + SendMessage(hwndChild,WM_SETFONT,(WPARAM)ProgramParams.hFont,0); + ForceRepaint(); + return (1); +} + +/*------------------------------------------------------------------------ + Procedure: CallDlgProc ID:1 + Purpose: Calls a dialog box procedure + Input: The function to call, and the numerical ID of the + resource where the dialog box is stored + Output: Returns the result of the dialog box. + Errors: None +------------------------------------------------------------------------*/ +int CallDlgProc(BOOL (CALLBACK *fn)(HWND,UINT,WPARAM,LPARAM), int id) +{ + int result; + + result = DialogBoxParam(hInst, MAKEINTRESOURCE(id), GetActiveWindow(), + fn, 0); + return result; +} + + +/*------------------------------------------------------------------------ + Procedure: CallChangeColor ID:1 + Purpose: Calls the standard color dialog of windows, starting + with the given color reference. The result is the + same as the input if the user cancels, or another + color if the user validates another one. + Input: The starting color + Output: The color the user has choosen. + Errors: None +------------------------------------------------------------------------*/ +static COLORREF CallChangeColor(COLORREF InitialColor) +{ + CHOOSECOLOR CC; + COLORREF CustColors[16]; + int r, g, b, i; + memset(&CC, 0, sizeof(CHOOSECOLOR)); + r = g = b = 0; + for (i = 0; i < 16; i++) { + CustColors[i] = RGB(r, g, b); + if (r < 255) + r += 127; + else if (g < 255) + g += 127; + else if (b < 255) + g += 127; + } + CC.lStructSize = sizeof(CHOOSECOLOR); + CC.hwndOwner = hwndMain; + CC.hInstance = hInst; + CC.rgbResult = InitialColor; + CC.lpCustColors = CustColors; + CC.Flags = CC_RGBINIT; + if (!ChooseColor(&CC)) + return (InitialColor); + return (CC.rgbResult); +} + +/*------------------------------------------------------------------------ + Procedure: CallPrintSetup ID:1 + Purpose: Calls the printer setup dialog. Currently it is not + connected to the rest of the software, since printing + is not done yet + Input: None + Output: 1 if OK, 0, user cancelled + Errors: None +------------------------------------------------------------------------*/ +static int CallPrintSetup(void) +{ + PAGESETUPDLG sd; + int r; + + memset(&sd,0,sizeof(sd)); + sd.lStructSize = sizeof(sd); + sd.Flags = PSD_RETURNDEFAULT; + r = PageSetupDlg(&sd); + if (!r) + return 0; + sd.Flags = 0; + r = PageSetupDlg(&sd); + return r; +} + + +/*------------------------------------------------------------------------ + Procedure: Undo ID:1 + Purpose: Send an UNDO command to the edit field. + Input: The parent window of the control + Output: None + Errors: None +------------------------------------------------------------------------*/ +void Undo(HWND hwnd) +{ + HWND hEdit; + + hEdit = (HWND)GetWindowLongPtr(hwnd,DWLP_USER); + SendMessage(hEdit,EM_UNDO,0,0); +} + +/*------------------------------------------------------------------------ + Procedure: ForceRepaint ID:1 + Purpose: Forces a complete redraw of the edit control of the + current session. + Input: None + Output: None + Errors: None +------------------------------------------------------------------------*/ +void ForceRepaint(void) +{ + HWND hwndEdit = (HWND)GetWindowLongPtr(hwndSession,DWLP_USER); + InvalidateRect(hwndEdit,NULL,1); +} + +/*------------------------------------------------------------------------ + Procedure: Add_Char_To_Queue ID:1 + Purpose: Puts a character onto the buffer + Input: The char to be added + Output: None + Errors: +------------------------------------------------------------------------*/ +static void Add_Char_To_Queue(int c) +{ + HWND hwndEdit = (HWND)GetWindowLongPtr(hwndSession,DWLP_USER); + SendMessage(hwndEdit,WM_CHAR,c,1); +} + +/*------------------------------------------------------------------------ + Procedure: AddLineToControl ID:1 + Purpose: It will ad the given text at the end of the edit + control, then it will send a return character to it. + This simulates user input. The history will not be + modified by this procedure. + Input: The text to be added + Output: None + Errors: If the line is empty, nothing will be done +------------------------------------------------------------------------*/ +void AddLineToControl(char *buf) +{ + HWND hEditCtrl; + + if (*buf == 0) + return; + + hEditCtrl = (HWND)GetWindowLongPtr(hwndSession,DWLP_USER); + + GotoEOF(); + + SendMessage(hEditCtrl,EM_REPLACESEL,0,(LPARAM)buf); + SendMessage(hEditCtrl,WM_CHAR,'\r',0); +} + +/*------------------------------------------------------------------------ + Procedure: AddStringToControl ID:1 + Author: Chris Watford watford@uiuc.edu + Purpose: It will ad the given text at the end of the edit + control. This simulates user input. The history will not + be modified by this procedure. + Input: The text to be added + Output: None + Errors: If the line is empty, nothing will be done +-------------------------------------------------------------------------- +Edit History: + 16 Sept 2003 - Chris Watford watford@uiuc.edu + - Basically this is AddLineToControl, but without appending a + newline +------------------------------------------------------------------------*/ +void AddStringToControl(char* buf) +{ + HWND hEditCtrl; + + if(buf == NULL) + return; + + if((*buf) == 0) + return; + + hEditCtrl = (HWND)GetWindowLongPtr(hwndSession, DWLP_USER); + GotoEOF(); + + SendMessage(hEditCtrl ,EM_REPLACESEL, (WPARAM)FALSE, (LPARAM)buf); +} + +/*------------------------------------------------------------------------ + Procedure: AboutDlgProc ID:1 + Purpose: Shows the "About" dialog box + Input: + Output: + Errors: +------------------------------------------------------------------------*/ +static BOOL CALLBACK AboutDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + if (message == WM_CLOSE) + EndDialog(hDlg,1); + return 0; +} + +/*------------------------------------------------------------------------ + Procedure: HistoryDlgProc ID:1 + Purpose: Shows the history of the session. Only input lines + are shown. A double click in a line will make this + dialog box procedure return the index of the selected + line (1 based). If the windows is closed (what is + equivalent to cancel), the return value is zero. + Input: Normal windows callback + Output: + Errors: +-------------------------------------------------------------------------- +Edit History: + 15 Sept 2003 - Chris Watford watford@uiuc.edu + - Added support for my StatementHistory structure + - Added the ability to export it as its exact entry, rather than + just a 1 liner +------------------------------------------------------------------------*/ +static BOOL CALLBACK HistoryDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + StatementHistory *histentry; + int idx; + RECT rc; + + switch (message) { + case WM_INITDIALOG: + SendDlgItemMessage(hDlg,IDLIST,WM_SETFONT,(WPARAM)ProgramParams.hFont,0); + histentry = History; // get our statement history object + idx = 0; + + // loop through each history entry adding it to the dialog + while (histentry != NULL) { + SendDlgItemMessage(hDlg,IDLIST,LB_INSERTSTRING,0,(LPARAM)editbuffer_getasline(histentry->Statement)); + SendDlgItemMessage(hDlg,IDLIST,LB_SETITEMDATA,0,(LPARAM)idx); + histentry = histentry->Next; + idx++; + } + + SendDlgItemMessage(hDlg,IDLIST,LB_SETCURSEL,(LPARAM)idx-1,0); + return 1; + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDLIST: + switch(HIWORD(wParam)) { + case LBN_DBLCLK: + idx = SendDlgItemMessage(hDlg,IDLIST,LB_GETCURSEL,0,0); + if (idx == LB_ERR) + break; + idx = SendDlgItemMessage(hDlg,IDLIST,LB_GETITEMDATA,idx,0); + EndDialog(hDlg,idx+1); + return 1; + } + break; + } + break; + case WM_SIZE: + GetClientRect(hDlg,&rc); + MoveWindow(GetDlgItem(hDlg,IDLIST),0,0,rc.right,rc.bottom,1); + break; + + case WM_CLOSE: + EndDialog(hDlg,0); + break; + } + return 0; +} + +/*------------------------------------------------------------------------ + Procedure: SaveText ID:1 + Purpose: Saves the contents of the session transcript. It will + loop for each line and write it to the specified file + Input: The name of the file where the session will be saved + Output: The session is saved + Errors: If it can't open the file for writing it will show an + error box +-------------------------------------------------------------------------- + Edit History: + 06 Oct 2003 - Chris Watford watford@uiuc.edu + - Corrected wsprintf error +------------------------------------------------------------------------*/ +static void SaveText(char *fname) +{ + int i,len; + HWND hEdit = (HWND)GetWindowLongPtr(hwndSession,DWLP_USER); + int linesCount = SendMessage(hEdit,EM_GETLINECOUNT,0,0); + FILE *f; + char *buf = SafeMalloc(8192); + + f = fopen(fname,"wb"); + if (f == NULL) + { + // corrected error using wsprintf + wsprintf(buf, "Impossible to open %s for writing", fname); + + ShowDbgMsg(buf); + return; + } + + for (i = 0; i < linesCount; i++) + { + *(unsigned short *)buf = 8100; + len = SendMessage(hEdit, EM_GETLINE, i, (LPARAM)buf); + buf[len] = '\0'; + fprintf(f, "%s\r\n", buf+1); + //fwrite(buf,1,len+2,f); + } + + fclose(f); + free(buf); +} + +/*------------------------------------------------------------------------ + Procedure: SaveML ID:1 + Author: Chris Watford watford@uiuc.edu + Purpose: Saves the ML source to a file, commenting out functions + that contained errors + Input: The name of the file where the session will be saved + Output: The session is saved + Errors: If it can't open the file for writing it will show an + error box +------------------------------------------------------------------------*/ +static void SaveML(char *fname) +{ + FILE *f; + char *buf = SafeMalloc(8192); + + f = fopen(fname, "wb"); + + if(f == NULL) + { + wsprintf(buf, "Impossible to open %s for writing", fname); + ShowDbgMsg(buf); + return; + } + + fprintf(f, "(* %s *)\r\n\r\n", fname); + + if(History != NULL) + { + StatementHistory *h = NULL; + EditBuffer *stmt = NULL; + + // get to the end + for(h = History; h->Next != NULL; h = h->Next); + + // go back :( + // this is NOT the fastest method, BUT this is the easiest + // on the subsystem + for(; h != NULL; h = h->Prev) + { + stmt = h->Statement; + + if(stmt != NULL) + { + // comment out incorrect lines + if(stmt->isCorrect) + { + char *buff = editbuffer_getasbuffer(stmt); + fprintf(f, "%s\r\n", buff); + free(buff); + } else { + char *buff = editbuffer_getasbuffer(stmt); + fprintf(f, "(* Syntax Error or Unbound Value\r\n%s\r\n *)\r\n", buff); + free(buff); + } + } + + fprintf(f, "\r\n"); + } + } + + fclose(f); + free(buf); +} + +/*------------------------------------------------------------------------ + Procedure: Add_Clipboard_To_Queue ID:1 + Author: Chris Watford watford@uiuc.edu + Purpose: Adds the clipboard text to the control + Input: + Output: + Errors: +-------------------------------------------------------------------------- + Edit History: + 16 Sept 2003 - Chris Watford watford@uiuc.edu + - Added method to update edit buffer with paste contents +------------------------------------------------------------------------*/ +static void Add_Clipboard_To_Queue(void) +{ + if (IsClipboardFormatAvailable(CF_TEXT) && OpenClipboard(hwndMain)) + { + HANDLE hClipData = GetClipboardData(CF_TEXT); + + if (hClipData != NULL) + { + char *str = GlobalLock(hClipData); + + if (str != NULL) + { + while ((*str) != 0) + { + if (*str != '\r') + Add_Char_To_Queue(*str); + + str++; + } + + // added to fix odd errors + RefreshCurrentEditBuffer(); + } + + GlobalUnlock(hClipData); + } + + CloseClipboard(); + } +} + +/*------------------------------------------------------------------------ + Procedure: CopyToClipboard ID:1 + Purpose: Copies text to the clipboard + Input: Window with the edit control + Output: + Errors: +------------------------------------------------------------------------*/ +static void CopyToClipboard(HWND hwnd) +{ + HWND hwndEdit = (HWND)GetWindowLongPtr(hwndSession,DWLP_USER); + SendMessage(hwndEdit,WM_COPY,0,0); +} + +/*------------------------------------------------------------------------ + Procedure: ResetText ID:1 + Purpose: Resets the text? I'm not really sure + Input: + Output: Always returns 0 + Errors: +------------------------------------------------------------------------*/ +int ResetText(void) +{ + HWND hwndEdit = (HWND) GetWindowLongPtr(hwndSession,DWLP_USER); + TEXTRANGE cr; + int len = SendMessage(hwndEdit,WM_GETTEXTLENGTH,0,0); + char *tmp = malloc(len+10),*p; + + memset(tmp,0,len+10); + cr.chrg.cpMin = 0; + cr.chrg.cpMax = -1; + cr.lpstrText = tmp; + SendMessage(hwndEdit,EM_GETTEXTRANGE,0,(LPARAM)&cr); + p = tmp+len/2; + while (*p && *p != '\r') + p++; + SendMessage(hwndEdit,EM_SETSEL,0,(LPARAM)-1); + SendMessage(hwndEdit,EM_REPLACESEL,0,(LPARAM)p); + InvalidateRect(hwndEdit,0,1); + free(tmp); + return 0; +} + +/*------------------------------------------------------------------------ + Procedure: HandleCommand ID:1 + Purpose: Handles all menu commands. + Input: + Output: + Errors: +-------------------------------------------------------------------------- + Edit History: + 06 Oct 2003 - Chris Watford watford@uiuc.edu + - Removed entries that crashed OCaml + - Removed useless entries + - Added Save ML and Save Transcript +------------------------------------------------------------------------*/ +void HandleCommand(HWND hwnd, WPARAM wParam,LPARAM lParam) +{ + char *fname; + int r; + + switch(LOWORD(wParam)) { + case IDM_OPEN: + fname = SafeMalloc(512); + if (OpenMlFile(fname,512)) { + char *buf = SafeMalloc(512); + char *p = strrchr(fname,'.'); + if (p && !stricmp(p,".ml")) { + wsprintf(buf, "#use \"%s\";;", fname); + AddLineToControl(buf); + } + else if (p && !stricmp(p,".cmo")) { + wsprintf(buf, "#load \"%s\";;", fname); + AddLineToControl(buf); + } + free(buf); + } + free(fname); + break; + case IDM_GC: + AddLineToControl("Gc.full_major();;"); + break; + case IDCTRLC: + InterruptOcaml(); + break; + case IDM_EDITPASTE: + Add_Clipboard_To_Queue(); + break; + case IDM_EDITCOPY: + CopyToClipboard(hwnd); + break; + + // updated to save a transcript + case IDM_SAVEAS: + fname = SafeMalloc(512); + if (GetSaveName(fname,512)) { + SaveText(fname); + } + free(fname); + break; + + // updated to save an ML file + case IDM_SAVE: + fname = SafeMalloc(512); + if (GetSaveMLName(fname,512)) + { + SaveML(fname); + } + free(fname); + break; + + // updated to work with new history system + case IDM_HISTORY: + r = CallDlgProc(HistoryDlgProc,IDD_HISTORY); + + if (r) + { + AddLineToControl(GetHistoryLine(r-1)); + } + break; + + case IDM_PRINTSU: + // Removed by Chris Watford + // seems to die + // CallPrintSetup(); + break; + + case IDM_FONT: + CallChangeFont(hwndMain); + break; + case IDM_COLORTEXT: + ProgramParams.TextColor = CallChangeColor(ProgramParams.TextColor); + ForceRepaint(); + break; + case IDM_BACKCOLOR: + BackColor = CallChangeColor(BackColor); + DeleteObject(BackgroundBrush); + BackgroundBrush = CreateSolidBrush(BackColor); + ForceRepaint(); + break; + case IDM_EDITUNDO: + Undo(hwnd); + break; + + /* Removed, really not very useful in this IDE + case IDM_WINDOWTILE: + SendMessage(hwndMDIClient,WM_MDITILE,0,0); + break; + case IDM_WINDOWCASCADE: + SendMessage(hwndMDIClient,WM_MDICASCADE,0,0); + break; + case IDM_WINDOWICONS: + SendMessage(hwndMDIClient,WM_MDIICONARRANGE,0,0); + break; + */ + + case IDM_EXIT: + PostMessage(hwnd,WM_CLOSE,0,0); + break; + case IDM_ABOUT: + CallDlgProc(AboutDlgProc,IDD_ABOUT); + break; + default: + if (LOWORD(wParam) >= IDEDITCONTROL && LOWORD(wParam) < IDEDITCONTROL+5) { + switch (HIWORD(wParam)) { + case EN_ERRSPACE: + ResetText(); + break; + } + } + break; + } +} diff --git a/ocaml-binary-annot/win32caml/ocaml.c b/ocaml-binary-annot/win32caml/ocaml.c new file mode 100644 index 0000000000..2a2e04a545 --- /dev/null +++ b/ocaml-binary-annot/win32caml/ocaml.c @@ -0,0 +1,1599 @@ +/* */ +/* Objective Caml */ +/* */ +/* Developed by Jacob Navia. */ +/* Copyright 2001 Institut National de Recherche en Informatique et */ +/* en Automatique. All rights reserved. This file is distributed */ +/* under the terms of the GNU Library General Public License, with */ +/* the special exception on linking described in file ../LICENSE. */ +/* */ +/***********************************************************************/ + +/***********************************************************************/ +/* Changes made by Chris Watford to enhance the source editor */ +/* Began 14 Sept 2003 - watford@uiuc.edu */ +/***********************************************************************/ + +/* $Id$ */ + +/*@@ Wedit generated application. Written Sat Jun 02 18:22:38 2001 +@@header: D:\lcc\inria\inriares.h +@@resources: D:\lcc\inria\inria.rc +Do not edit outside the indicated areas */ +/*<---------------------------------------------------------------------->*/ + +#include <stdio.h> +#include <windows.h> +#include <windowsx.h> +#include <commctrl.h> +#include <string.h> +#include <direct.h> +#include <Richedit.h> +#include "inriares.h" +#include "inria.h" + +#define VK_BACKSPACE 0x108 + +/*<---------------------------------------------------------------------->*/ +int EditControls = IDEDITCONTROL; +static WNDPROC lpEProc; +static char lineBuffer[1024*32]; +int ReadToLineBuffer(void); +int AddLineBuffer(void); +static int busy; +static DWORD TimerId; +POSITION LastPromptPosition; +char LibDir[512]; +char OcamlPath[512]; +HBRUSH BackgroundBrush; +COLORREF BackColor = RGB(255,255,255); +PROGRAM_PARAMS ProgramParams; +StatementHistory *History = NULL; +StatementHistory *HistoryTail = NULL; +StatementHistory *historyEntry = NULL; +EditBuffer *CurrentEditBuffer = NULL; // current edit buffer + +/*<----------------- global variables --------------------------------------->*/ +HANDLE hInst; // Instance handle +HWND hwndMain; //Main window handle +HWND hwndSession; +HWND hwndMDIClient; //Mdi client window handle +static LRESULT CALLBACK MainWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); +static LRESULT CALLBACK MdiChildWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); +PROCESS_INFORMATION pi; +HWND hWndStatusbar; + +/*------------------------------------------------------------------------ +Procedure: UpdateStatusBar ID:1 +Purpose: Updates the statusbar control with the appropiate +text +Input: lpszStatusString: Charactar string that will be shown +partNumber: index of the status bar part number. +displayFlags: Decoration flags +Output: none +Errors: none + +------------------------------------------------------------------------*/ +void UpdateStatusBar(LPSTR lpszStatusString, WORD partNumber, WORD displayFlags) +{ + SendMessage(hWndStatusbar, + SB_SETTEXT, + partNumber | displayFlags, + (LPARAM)lpszStatusString); +} + + +/*------------------------------------------------------------------------ +Procedure: MsgMenuSelect ID:1 +Purpose: Shows in the status bar a descriptive explaation of +the purpose of each menu item.The message +WM_MENUSELECT is sent when the user starts browsing +the menu for each menu item where the mouse passes. +Input: Standard windows. +Output: The string from the resources string table is shown +Errors: If the string is not found nothing will be shown. +------------------------------------------------------------------------*/ +LRESULT MsgMenuSelect(HWND hwnd, UINT uMessage, WPARAM wparam, LPARAM lparam) +{ + static char szBuffer[256]; + UINT nStringID = 0; + UINT fuFlags = GET_WM_MENUSELECT_FLAGS(wparam, lparam) & 0xffff; + UINT uCmd = GET_WM_MENUSELECT_CMD(wparam, lparam); + HMENU hMenu = GET_WM_MENUSELECT_HMENU(wparam, lparam); + + szBuffer[0] = 0; // First reset the buffer + if (fuFlags == 0xffff && hMenu == NULL) // Menu has been closed + nStringID = 0; + + else if (fuFlags & MFT_SEPARATOR) // Ignore separators + nStringID = 0; + + else if (fuFlags & MF_POPUP) // Popup menu + { + if (fuFlags & MF_SYSMENU) // System menu + nStringID = IDS_SYSMENU; + else + // Get string ID for popup menu from idPopup array. + nStringID = 0; + } // for MF_POPUP + else // Must be a command item + nStringID = uCmd; // String ID == Command ID + + // Load the string if we have an ID + if (0 != nStringID) + LoadString(hInst, nStringID, szBuffer, sizeof(szBuffer)); + // Finally... send the string to the status bar + UpdateStatusBar(szBuffer, 0, 0); + return 0; +} + +/*------------------------------------------------------------------------ +Procedure: TimerProc ID:1 +Purpose: This procedure will be called by windows about 4 +times a second. It will just send a message to the +mdi child window to look at the pipe. +Input: +Output: +Errors: +------------------------------------------------------------------------*/ +static VOID CALLBACK TimerProc(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime) +{ + SendMessage(hwndSession, WM_TIMERTICK, 0, 0); +} + +/*------------------------------------------------------------------------ +Procedure: InitializeStatusBar ID:1 +Purpose: Initialize the status bar +Input: hwndParent: the parent window +nrOfParts: The status bar can contain more than one +part. What is difficult, is to figure out how this +should be drawn. So, for the time being only one is +being used... +Output: The status bar is created +Errors: +------------------------------------------------------------------------*/ +void InitializeStatusBar(HWND hwndParent,int nrOfParts) +{ + const int cSpaceInBetween = 8; + int ptArray[40]; // Array defining the number of parts/sections + RECT rect; + HDC hDC; + + /* * Fill in the ptArray... */ + + hDC = GetDC(hwndParent); + GetClientRect(hwndParent, &rect); + + ptArray[nrOfParts-1] = rect.right; + //---TODO--- Add code to calculate the size of each part of the status + // bar here. + + ReleaseDC(hwndParent, hDC); + SendMessage(hWndStatusbar, + SB_SETPARTS, + nrOfParts, + (LPARAM)(LPINT)ptArray); + + UpdateStatusBar("Ready", 0, 0); +} + + +/*------------------------------------------------------------------------ +Procedure: CreateSBar ID:1 +Purpose: Calls CreateStatusWindow to create the status bar +Input: hwndParent: the parent window +initial text: the initial contents of the status bar +Output: +Errors: +------------------------------------------------------------------------*/ +static BOOL CreateSBar(HWND hwndParent,char *initialText,int nrOfParts) +{ + hWndStatusbar = CreateStatusWindow(WS_CHILD | WS_VISIBLE | WS_BORDER|SBARS_SIZEGRIP, + initialText, + hwndParent, + IDM_STATUSBAR); + if(hWndStatusbar) + { + InitializeStatusBar(hwndParent,nrOfParts); + return TRUE; + } + + return FALSE; +} +/*------------------------------------------------------------------------ +Procedure: InitApplication ID:1 +Purpose: Registers two window classes: the "inria" window +class with the main window, and the mdi child +window's window class. +Input: +Output: +Errors: +------------------------------------------------------------------------*/ +static BOOL InitApplication(void) +{ + WNDCLASS wc; + + memset(&wc,0,sizeof(WNDCLASS)); + wc.style = CS_HREDRAW|CS_VREDRAW |CS_DBLCLKS ; + wc.lpfnWndProc = (WNDPROC)MainWndProc; + wc.hInstance = hInst; + wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + wc.lpszClassName = "inriaWndClass"; + wc.lpszMenuName = MAKEINTRESOURCE(IDMAINMENU); + wc.hCursor = LoadCursor(NULL,IDC_ARROW); + wc.hIcon = LoadIcon(hInst,MAKEINTRESOURCE(OCAML_ICON)); + if (!RegisterClass(&wc)) + return 0; + wc.style = 0; + wc.lpfnWndProc = (WNDPROC)MdiChildWndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 20; + wc.hInstance = hInst; // Owner of this class + wc.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(OCAML_ICON)); + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); // Default color + wc.lpszMenuName = NULL; + wc.lpszClassName = "MdiChildWndClass"; + if (!RegisterClass((LPWNDCLASS)&wc)) + return FALSE; + return 1; +} + +/*------------------------------------------------------------------------ +Procedure: CreateinriaWndClassWnd ID:1 +Purpose: Creates the main window +Input: +Output: +Errors: +------------------------------------------------------------------------*/ +HWND CreateinriaWndClassWnd(void) +{ + return CreateWindow("inriaWndClass","OCamlWinPlus v1.9RC4", + WS_MINIMIZEBOX|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CLIPCHILDREN|WS_MAXIMIZEBOX|WS_CAPTION|WS_BORDER|WS_SYSMENU|WS_THICKFRAME, + CW_USEDEFAULT,0,CW_USEDEFAULT,0, + NULL, + NULL, + hInst, + NULL); +} + +/*------------------------------------------------------------------------ +Procedure: MDICmdFileNew ID:1 +Purpose: Creates a new session window. Note that multiple +windows with multiple sessions are possible. +Input: +Output: +Errors: +------------------------------------------------------------------------*/ +static HWND MDICmdFileNew(char *title, int show) +{ + HWND hwndChild; + char rgch[150]; + static int cUntitled; + MDICREATESTRUCT mcs; + + if (title == NULL) + wsprintf(rgch,"Session%d", cUntitled++); + else { + strncpy(rgch,title,149); + rgch[149] = 0; + } + + // Create the MDI child window + + mcs.szClass = "MdiChildWndClass"; // window class name + mcs.szTitle = rgch; // window title + mcs.hOwner = hInst; // owner + mcs.x = CW_USEDEFAULT; // x position + mcs.y = CW_USEDEFAULT; // y position + mcs.cx = CW_USEDEFAULT; // width + mcs.cy = CW_USEDEFAULT; // height + mcs.style = 0; // window style + mcs.lParam = 0; // lparam + + hwndChild = (HWND) SendMessage(hwndMDIClient, + WM_MDICREATE, + 0, + (LPARAM)(LPMDICREATESTRUCT) &mcs); + + if (hwndChild != NULL && show) + ShowWindow(hwndChild, SW_SHOW); + + return hwndChild; +} +static HWND CreateMdiClient(HWND hwndparent) +{ + CLIENTCREATESTRUCT ccs = {0}; + HWND hwndMDIClient; + int icount = GetMenuItemCount(GetMenu(hwndparent)); + + // Find window menu where children will be listed + ccs.hWindowMenu = GetSubMenu(GetMenu(hwndparent), icount-2); + ccs.idFirstChild = IDM_WINDOWCHILD; + + // Create the MDI client filling the client area + hwndMDIClient = CreateWindow("mdiclient", + NULL, + WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | + WS_HSCROLL, + 0, 0, 0, 0, + hwndparent, + (HMENU)0xCAC, + hInst, + (LPVOID)&ccs); + + ShowWindow(hwndMDIClient, SW_SHOW); + + return hwndMDIClient; +} + +void GotoEOF(void) +{ + HWND hEdit = (HWND)GetWindowLongPtr(hwndSession,DWLP_USER); + int linesCount = SendMessage(hEdit,EM_GETLINECOUNT,0,0); + int lineindex = SendMessage(hEdit,EM_LINEINDEX,linesCount-1,0); + int lastLineLength = SendMessage(hEdit,EM_LINELENGTH,linesCount-1,0); + + lineindex += lastLineLength; + SendMessage(hEdit,EM_SETSEL,lineindex,lineindex); +} + +/*------------------------------------------------------------------------ +Procedure: GotoPrompt ID:1 +Author: Chris Watford watford@uiuc.edu +Purpose: Puts the cursor on the prompt line right after the '# ' +Input: +Output: +Errors: +------------------------------------------------------------------------*/ +void GotoPrompt(void) +{ + HWND hEdit = (HWND)GetWindowLongPtr(hwndSession,DWLP_USER); + int lineindex = SendMessage(hEdit,EM_LINEINDEX,LastPromptPosition.line,0)+2; + SendMessage(hEdit,EM_SETSEL,lineindex,lineindex); +} + +int GetCurLineIndex(HWND hEdit) +{ + return SendMessage(hEdit,EM_LINEFROMCHAR,(WPARAM)-1,0); +} + +int GetNumberOfLines(HWND hEdit) +{ + return SendMessage(hEdit,EM_GETLINECOUNT,0,0); +} + +static int GetWordUnderCursor(HWND hwndEditControl,char *buf,int len) +{ + char *line,*p,*pstart,*pend; + int lineidx,start,end,length,offset,cursorpos,startingChar; + + SendMessage(hwndEditControl,EM_GETSEL,(WPARAM)&start,(LPARAM)&end); + lineidx = SendMessage(hwndEditControl,EM_EXLINEFROMCHAR,0,start); + startingChar = SendMessage(hwndEditControl,EM_LINEINDEX,lineidx,0); + start -= startingChar; + end -= startingChar; + lineidx = SendMessage(hwndEditControl,EM_LINEFROMCHAR,start,0); + length = SendMessage(hwndEditControl,EM_LINELENGTH,lineidx,0); + offset = SendMessage(hwndEditControl,EM_LINEINDEX,lineidx,0); + line = SafeMalloc(length+1); + memset(line,0,length+1); + *(unsigned short *)line = length; + SendMessage(hwndEditControl,EM_GETLINE,lineidx,(LPARAM)line); + cursorpos = start-offset; + p = line + cursorpos; + pstart = p; + while (*pstart + && *pstart != ' ' + && *pstart != '\t' + && *pstart != '(' + && pstart > line) + pstart--; + pend = p; + while (*pend + && *pend != ' ' + && *pend != '\t' + && *pend != '(' + && pend < line + length) + pend++; + if (*pstart == ' ' || *pstart == '\t') + pstart++; + if (*pend == ' ' || *pend == '\t') + pend--; + memcpy(buf,pstart,1+pend-pstart); + buf[pend-pstart] = 0; + free(line); + return 1; +} + +/*------------------------------------------------------------------------ +Procedure: GetLastLine ID:1 +Purpose: Gets the data in the line containing the cursor to + the interpreter. +Input: The edit control window handle +Output: None explicit +Errors: None +------------------------------------------------------------------------*/ +char* GetLastLine(HWND hEdit) +{ + int curline = GetCurLineIndex(hEdit); + char *linebuffer = (char*)SafeMalloc(2048*sizeof(char)); + int n; + int linescount = GetNumberOfLines(hEdit); + + *(unsigned short *)linebuffer = 2047; + n = SendMessage(hEdit,EM_GETLINE,curline,(LPARAM)linebuffer); + + if (n >= 2 && linebuffer[0] == '#' && linebuffer[1] == ' ') { + n -= 2; + memmove(linebuffer, linebuffer+2, n); + } + + linebuffer[n] = '\0'; + + return linebuffer; +} + +void DoHelp(HWND hwnd) +{ + char word[256]; + GetWordUnderCursor(hwnd,word,sizeof(word)); + MessageBox(NULL,word,"Aide pour:",MB_OK); +} + +/*------------------------------------------------------------------------ +Procedure: RewriteCurrentEditBuffer ID:1 +Purpose: Rewrites what is at the prompt with the current contents of + the edit buffer +Input: None +Output: None explicit +Errors: None +------------------------------------------------------------------------*/ +void RewriteCurrentEditBuffer(void) +{ + // get the editbox's handle + HWND hEdit = (HWND)GetWindowLongPtr(hwndSession,DWLP_USER); + + // calculate what to highlight + int linesCount = SendMessage(hEdit,EM_GETLINECOUNT,0,0); + int lineindex = SendMessage(hEdit,EM_LINEINDEX,LastPromptPosition.line,0) + 2; + int lastLine = SendMessage(hEdit,EM_LINEINDEX,linesCount-1,0) + SendMessage(hEdit,EM_LINELENGTH,linesCount-1,0) + 100; + + // delete the current text + SendMessage(hEdit, EM_SETSEL, (WPARAM)lineindex, (LPARAM)lastLine); + SendMessage(hEdit, EM_REPLACESEL, (WPARAM)TRUE, (LPARAM)""); + + { + // loop through each line in the edit buffer and add it to the control + LineList* line = CurrentEditBuffer->Lines; + for(; line != NULL; line = line->Next) + { + // if there is a line before me, add a newline + if(line->Prev != NULL) + SendMessage(hEdit, EM_REPLACESEL, (WPARAM)TRUE, (LPARAM)"\r\n"); + + // add the line + SendMessage(hEdit, EM_REPLACESEL, (WPARAM)TRUE, (LPARAM)line->Text); + } + } +} + +/*------------------------------------------------------------------------ +Procedure: RefreshCurrentEditBuffer ID:1 +Purpose: Rewrites what is in the CurrentEditBuffer with what is + actually there +Input: None +Output: None explicit +Errors: None +------------------------------------------------------------------------*/ +void RefreshCurrentEditBuffer(void) +{ + // get the editbox's handle + HWND hEdit = (HWND)GetWindowLongPtr(hwndSession,DWLP_USER); + + // get the last line index + int linesCount = SendMessage(hEdit,EM_GETLINECOUNT,0,0) - 1; + int i = 0, n = 0; + + // where to hold the line we grab + char *linebuffer = (char*)SafeMalloc(2048*sizeof(char)); + *(unsigned short *)linebuffer = 2047; + + editbuffer_destroy(CurrentEditBuffer); + CurrentEditBuffer = editbuffer_new(); + + // loop through each line updating or adding it to the current edit buffer + for( ; (i + LastPromptPosition.line) <= linesCount; i++) + { + n = SendMessage(hEdit, EM_GETLINE, (i + LastPromptPosition.line), (LPARAM)linebuffer); + + if ((n >= 2) && (linebuffer[0] == '#') && (linebuffer[1] == ' ')) { + n -= 2; + memmove(linebuffer, linebuffer+2, n); + } + + linebuffer[n] = '\0'; + + { // remove line breaks and feeds + char* ln = linebuffer; + + while((*ln) != 0) + { + switch((*ln)) + { + case '\r': + case '\n': + (*ln) = ' '; + } + + ln++; + } + } + + editbuffer_addline(CurrentEditBuffer, linebuffer); + } +} + +/*------------------------------------------------------------------------ +Procedure: NextHistoryEntry ID:1 +Purpose: Scrolls to the next history entry +Input: None +Output: None explicit +Errors: None +-------------------------------------------------------------------------- +Edit History: + 17 Sept 2003 - Chris Watford watford@uiuc.edu + - Added this as a helper function + 18 Sept 2003 - Chris Watford watford@uiuc.edu + - Corrected doubly linked list problems +------------------------------------------------------------------------*/ +void NextHistoryEntry(void) +{ + // out of bounds, put it back into bounds + if(historyEntry == NULL && History == NULL) + { + return; + } else if (historyEntry == NULL && History != NULL) { + historyEntry = History; + } else { + if(historyEntry->Next == NULL) + return; + + historyEntry = historyEntry->Next; + } + + // if its valid + if(historyEntry != NULL) + { + // copy the history entry to a new buffer + EditBuffer* newBuf = editbuffer_copy(historyEntry->Statement); + + // destroy the old buffer + editbuffer_destroy(CurrentEditBuffer); + + // setup the current one to the copy + CurrentEditBuffer = newBuf; + + // rewrite the old one and go to the prompt + RewriteCurrentEditBuffer(); + GotoPrompt(); + } +} + +/*------------------------------------------------------------------------ +Procedure: PrevHistoryEntry ID:1 +Purpose: Scrolls to the previous history entry +Input: None +Output: None explicit +Errors: None +-------------------------------------------------------------------------- +Edit History: + 17 Sept 2003 - Chris Watford watford@uiuc.edu + - Added this as a helper function + 18 Sept 2003 - Chris Watford watford@uiuc.edu + - Corrected doubly linked list problems +------------------------------------------------------------------------*/ +void PrevHistoryEntry(void) +{ + // out of bounds, put it back into bounds + if(historyEntry == NULL || History == NULL) + { + return; + } else { + if(historyEntry->Prev == NULL) + return; + + historyEntry = historyEntry->Prev; + } + + // if its valid + if(historyEntry != NULL) + { + // copy the history entry to a new buffer + EditBuffer* newBuf = editbuffer_copy(historyEntry->Statement); + + // destroy the old buffer + editbuffer_destroy(CurrentEditBuffer); + + // setup the current one to the copy + CurrentEditBuffer = newBuf; + + // rewrite the old one and go to the prompt + RewriteCurrentEditBuffer(); + GotoPrompt(); + } +} + +/*------------------------------------------------------------------------ +Procedure: SubClassEdit ID:1 +Purpose: Handles messages to the editbox +Input: +Output: +Errors: +-------------------------------------------------------------------------- +Edit History: + 14 Sept 2003 - Chris Watford watford@uiuc.edu + - Setup handler for up and down arrows + 15 Sept 2003 - Chris Watford watford@uiuc.edu + - Setup framework for history on up arrow + - Saves lines you move off of in the edit buffer + 16 Sept 2003 - Chris Watford watford@uiuc.edu + - Proper handling of newline message finished + - Fixed ENTER on middle of interior line, moves cursor to the end + and sends the line + - Setup the copying and destroying of the old buffer + - Included buffer rewrite + 17 Sept 2003 - Chris Watford watford@uiuc.edu + - Added C-p/C-n support + - Changed UpArrow to C-UpArrow so as to not confuse users + 18 Sept 2003 - Chris Watford watford@uiuc.edu + - Added Left and Right arrow line saving + - Added backspace and delete line saving and removing + - Fixed history scrolling + 21 Sept 2003 - Chris Watford watford@uiuc.edu + - Fixed pasting errors associated with lines being out of bounds + for the buffer + - Added error handling, possibly able to handle it diff down the + line + - Removed C-Up/C-Dn for history scrolling, buggy at best on my + machine +------------------------------------------------------------------------*/ +static LRESULT CALLBACK SubClassEdit(HWND hwnd, UINT msg, WPARAM mp1, LPARAM mp2) +{ + LRESULT r; + int postit=0,nl; + + if (msg == WM_CHAR && mp1 == '\r') { + if (!busy) { + r = GetCurLineIndex(hwnd); + nl = GetNumberOfLines(hwnd); + + // if we're not the last line + if (r != nl-1) + { + // update or add us, we might not have any lines in the edit buffer + editbuffer_updateoraddline(CurrentEditBuffer, r-LastPromptPosition.line, GetLastLine(hwnd)); + + // scroll to the end, add CrLf then post the newline message + GotoEOF(); + AddStringToControl("\r\n"); + PostMessage(GetParent(hwnd),WM_NEWLINE,0,0); + return 0; + } + + CallWindowProc(lpEProc,hwnd,WM_KEYDOWN,VK_END,1); + CallWindowProc(lpEProc,hwnd,WM_KEYUP,VK_END,1); + + postit = 1; + } + + } + else if (msg == WM_CHAR && mp1 == (char)0x08) { + int lineindex = SendMessage(hwnd, EM_LINEINDEX, LastPromptPosition.line, 0) + 2; + int curline = SendMessage(hwnd,EM_LINEFROMCHAR,(WPARAM)-1,0); + int nextline = 0; + int curpoint = 0; + + SendMessage(hwnd, EM_GETSEL, (WPARAM)&curpoint, (LPARAM)NULL); + nextline = SendMessage(hwnd,EM_LINEFROMCHAR,(WPARAM)(curpoint - 1),0); + + if(curpoint <= lineindex) + { + return 0; + } else if(nextline != curline) { + // delete the line we're on + + // grab the index + curline -= LastPromptPosition.line; + + // kill it + editbuffer_removeline(CurrentEditBuffer, curline); + } + } + else if (msg == WM_KEYDOWN && mp1 == VK_F1) { + DoHelp(hwnd); + } + else if ((msg == WM_KEYDOWN || msg == WM_KEYUP) && mp1 == VK_UP) { + int curline = GetCurLineIndex(hwnd); + + /*if((msg == WM_KEYDOWN) && (GetKeyState(VK_CONTROL) && 0x8000)) + { // go forward once in history + NextHistoryEntry(); + return 0; + } else */ + if((curline > LastPromptPosition.line) && (curline <= (LastPromptPosition.line + CurrentEditBuffer->LineCount))) + { + // update current line + if (msg == WM_KEYDOWN) + { + int lineidx = (curline - LastPromptPosition.line); + + CallWindowProc(lpEProc,hwnd,WM_KEYDOWN,VK_END,1); + CallWindowProc(lpEProc,hwnd,WM_KEYUP,VK_END,1); + + // we may have to add this line, otherwise update it + editbuffer_updateoraddline(CurrentEditBuffer, lineidx, GetLastLine(hwnd)); + } + } else { + return 0; + } + } + else if ((msg == WM_KEYDOWN || msg == WM_KEYUP) && (mp1 == VK_LEFT)) { + int lineindex = SendMessage(hwnd, EM_LINEINDEX, LastPromptPosition.line, 0) + 2; + int curline = SendMessage(hwnd,EM_LINEFROMCHAR,(WPARAM)-1,0); + int nextline = 0; + int curpoint = 0; + + SendMessage(hwnd, EM_GETSEL, (WPARAM)&curpoint, (LPARAM)NULL); + nextline = SendMessage(hwnd,EM_LINEFROMCHAR,(WPARAM)(curpoint - 1),0); + + if(curpoint <= lineindex) + { // no left arrow to the left of the prompt + return 0; + } else if(nextline != curline) { + // update current line + if (msg == WM_KEYDOWN) + { + int lineidx = (curline - LastPromptPosition.line); + + CallWindowProc(lpEProc,hwnd,WM_KEYDOWN,VK_END,1); + CallWindowProc(lpEProc,hwnd,WM_KEYUP,VK_END,1); + + // we may have to add this line, otherwise update it + editbuffer_updateoraddline(CurrentEditBuffer, lineidx, GetLastLine(hwnd)); + + CallWindowProc(lpEProc,hwnd,WM_KEYDOWN,VK_HOME,1); + CallWindowProc(lpEProc,hwnd,WM_KEYUP,VK_HOME,1); + } + } + } + else if ((msg == WM_KEYDOWN || msg == WM_KEYUP) && (mp1 == VK_DOWN)) { + int curline = GetCurLineIndex(hwnd); + + /*if((msg == WM_KEYDOWN) && (GetKeyState(VK_CONTROL) && 0x8000)) + { // go back once in history + PrevHistoryEntry(); + return 0; + } else*/ + if((curline >= LastPromptPosition.line) && (curline < (LastPromptPosition.line + CurrentEditBuffer->LineCount))) + { + // We don't post the newline, but instead update the current line + if (msg == WM_KEYDOWN) + { + int lineidx = (curline - LastPromptPosition.line); + + CallWindowProc(lpEProc,hwnd,WM_KEYDOWN,VK_END,1); + CallWindowProc(lpEProc,hwnd,WM_KEYUP,VK_END,1); + + editbuffer_updateline(CurrentEditBuffer, lineidx, GetLastLine(hwnd)); + } + } else { + return 0; + } + } + else if ((msg == WM_KEYDOWN || msg == WM_KEYUP) && (mp1 == VK_RIGHT)) { + int lineindex = SendMessage(hwnd, EM_LINEINDEX, LastPromptPosition.line, 0) + 1; + int curline = SendMessage(hwnd,EM_LINEFROMCHAR,(WPARAM)-1,0); + int nextline = 0; + int curpoint = 0; + + SendMessage(hwnd, EM_GETSEL, (WPARAM)&curpoint, (LPARAM)NULL); + nextline = SendMessage(hwnd,EM_LINEFROMCHAR,(WPARAM)(curpoint + 2),0); + + if(curpoint <= lineindex) + { // no movement behind the prompt + return 0; + } else if((nextline != curline) && (msg = WM_KEYDOWN)) { + int lineidx = (curline - LastPromptPosition.line); + + CallWindowProc(lpEProc,hwnd,WM_KEYDOWN,VK_END,1); + CallWindowProc(lpEProc,hwnd,WM_KEYUP,VK_END,1); + + editbuffer_updateline(CurrentEditBuffer, lineidx, GetLastLine(hwnd)); + } + } + else if ((msg == WM_KEYDOWN) && (mp1 == VK_PRIOR) && (GetKeyState(VK_CONTROL) && 0x8000)) { + // C-p + NextHistoryEntry(); + return 0; + } + else if ((msg == WM_KEYDOWN) && (mp1 == VK_NEXT) && (GetKeyState(VK_CONTROL) && 0x8000)) { + // C-n + PrevHistoryEntry(); + return 0; + } + else if ((msg == WM_KEYDOWN || msg == WM_KEYUP) && (mp1 == VK_DELETE)) { + // see if we're the last char on the line, if so delete the next line + // don't allow deleting left of the prompt + int lineindex = SendMessage(hwnd, EM_LINEINDEX, LastPromptPosition.line, 0) + 2; + int curline = SendMessage(hwnd,EM_LINEFROMCHAR,(WPARAM)-1,0); + int nextline = 0; + int curpoint = 0; + + SendMessage(hwnd, EM_GETSEL, (WPARAM)&curpoint, (LPARAM)NULL); + nextline = SendMessage(hwnd,EM_LINEFROMCHAR,(WPARAM)(curpoint + 2),0); + + if(curpoint < lineindex) + { // no chomping behind the prompt + return 0; + } else if(nextline != curline) { + // deleting + // grab the next line index + curline -= LastPromptPosition.line; + + // kill it + editbuffer_removeline(CurrentEditBuffer, curline+1); + } + } + else if (msg == WM_PASTE) { + // if they paste text, allow it + r = CallWindowProc(lpEProc, hwnd, msg, mp1, mp2); + + // update the current edit buffer + RefreshCurrentEditBuffer(); + + return r; + } + + // handle errors + switch(msg) + { + case WM_SYNTAXERROR: + case WM_ILLEGALCHAR: + case WM_UNBOUNDVAL: + { // currently I handle them all the same + // get the start of the line + int start = SendMessage(hwnd, EM_LINEINDEX, LastPromptPosition.line, 0) + 2; + + // get the statement that error'd + NextHistoryEntry(); + + // tell the history that the last line errored + if(History != NULL) + if(History->Statement != NULL) + History->Statement->isCorrect = FALSE; + + // highlight the offending chars + SendMessage(hwnd,EM_SETSEL,(WPARAM)(start + mp1), (LPARAM)(start + mp2)); + + return 0; + } + } + + r = CallWindowProc(lpEProc, hwnd, msg, mp1, mp2); + + if (postit) + PostMessage(GetParent(hwnd),WM_NEWLINE,0,0); + + return r; +} + +static void SubClassEditField(HWND hwnd) +{ + if (lpEProc == NULL) { + lpEProc = (WNDPROC) GetWindowLongPtr(hwnd, GWLP_WNDPROC); + } + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR) SubClassEdit); +} + +/*------------------------------------------------------------------------ +Procedure: SendLastLine ID:1 +Purpose: Sends the data in the line containing the cursor to +the interpreter. If this is NOT the last line, copy +the line to the end of the text. +Input: The edit control window handle +Output: None explicit +Errors: None + +REMOVED! +------------------------------------------------------------------------*/ +void SendLastLine(HWND hEdit) +{ +/* int curline = GetCurLineIndex(hEdit); + char *p,linebuffer[2048]; + int n; + int linescount = GetNumberOfLines(hEdit); + + *(unsigned short *)linebuffer = sizeof(linebuffer)-1; + if (curline != linescount-1) + n = SendMessage(hEdit,EM_GETLINE,curline,(LPARAM)linebuffer); + else + n = SendMessage(hEdit,EM_GETLINE,curline-1,(LPARAM)linebuffer); + if (n >= 2 && linebuffer[0] == '#' && linebuffer[1] == ' ') { + n -= 2; + memmove(linebuffer, linebuffer+2, n); + } + linebuffer[n] = 0; + + // Record user input! + AddToHistory(linebuffer); + linebuffer[n] = '\n'; + linebuffer[n+1] = 0; + WriteToPipe(linebuffer); + if (curline != linescount-1) { + // Copy the line sent to the end of the text + p = strrchr(linebuffer,'\n'); + if (p) { + *p = 0; + } + busy = 1; + AddLineToControl(linebuffer); + busy = 0; + }*/ +} + +/*------------------------------------------------------------------------ +Procedure: SendLastEditBuffer ID:1 +Author: Chris Watford watford@uiuc.edu +Purpose: Sends an edit buffer to the pipe +Input: +Output: +Errors: +-------------------------------------------------------------------------- +Edit History: + 7 Aug 2004 - Chris Watford christopher.watford@gmail.com + - Fixed error where SendLastEditBuffer sent waaaay too many + newlines which completely broke the underlying connection to the + ocaml.exe pipe + 15 Sept 2003 - Chris Watford watford@uiuc.edu + - Sends line to the pipe and adds newline to the end +------------------------------------------------------------------------*/ +void SendLastEditBuffer(HWND hwndChild) +{ + char* line = editbuffer_getasbuffer(CurrentEditBuffer); + int l = strlen(line) - 1; + char* linebuffer = (char*)SafeMalloc(l+2); + + // save current edit buffer to history and create a new blank edit buffer + CurrentEditBuffer->isCorrect = TRUE; + AddToHistory(CurrentEditBuffer); + CurrentEditBuffer = (EditBuffer*)SafeMalloc(sizeof(EditBuffer)); + CurrentEditBuffer->LineCount = 0; + CurrentEditBuffer->Lines = NULL; + + // trim and add the newline to the end + strncpy(linebuffer, line, l+1); + while((linebuffer[l] == '\n' || linebuffer[l] == '\r') && (l >= 0)) + { + linebuffer[l--] = '\0'; + } + + linebuffer[l+1] = '\n'; + linebuffer[l+2] = '\0'; + + // save line to the pipe + WriteToPipe(linebuffer); +} + +/*------------------------------------------------------------------------ +Procedure: SendingFullCommand ID:1 +Author: Chris Watford watford@uiuc.edu +Purpose: Returns if the command being sent +Input: The edit control window handle +Output: None explicit +Errors: None +-------------------------------------------------------------------------- +Edit History: + 7 Aug 2004 - Chris Watford christopher.watford@gmail.com + - Fixed bug #2932 where many carraige returns were sent and it came + back with a null pointer error due to a fault of not checking if + the line returned was NULL + 13 Oct 2003 - Chris Watford watford@uiuc.edu + - Solved the error when you have a malformed comment in the buffer +------------------------------------------------------------------------*/ +BOOL SendingFullCommand(void) +{ + // if there is a ;; on the line, return true + char *line = editbuffer_getasline(CurrentEditBuffer); + char *firstComment, *firstSemiColonSemiColon, *firstQuote; + + if(line == NULL) + { + return FALSE; + } + + firstComment = strstr(line, "(*"); + firstSemiColonSemiColon = strstr(line, ";;"); + firstQuote = strstr(line, "\""); + + // easy case :D + if(firstSemiColonSemiColon == NULL) + { + free(line); + return FALSE; + } + + // if there are no comments + if(firstComment == NULL) + { + // if there are no quotations used + if(firstQuote == NULL) + { + BOOL r = (firstSemiColonSemiColon != NULL); + free(line); + return r; + } else { + // we need to first check if the ;; is before the \", since the \" + // won't matter if its before the semicolonsemicolon + if(firstQuote < firstSemiColonSemiColon) + { + // the quote is before the ;;, we need to make sure its terminated + // also we have to check for escaped quotes, le sigh! + char *c = firstQuote+1; + BOOL in_quote = TRUE; + + // in-quote determiner loop + while(c[0] != '\0') + { + // are we a backslash? + if(c[0] == '\\') + { + // ignore the next character + c++; + } + else + { + // are we a quote? + if(c[0] == '"') + { + in_quote = !in_quote; + } + } + + c++; + } + + free(line); + return !in_quote; + } else { + BOOL r = (firstSemiColonSemiColon != NULL); + free(line); + return r; + } + } + } else { + // we have to search through finding all comments + + // a neat little trick we can do is compare the point at which + // the ;; is and where the first (* can be found, if the ;; is + // before the (* ocaml.exe ignores the comment + if((unsigned int)firstSemiColonSemiColon < (unsigned int)firstComment) + { + free(line); + return TRUE; + } else { + // time to search and find if the endline is inside a comment or not + // start at the first comment, and move forward keeping track of the + // nesting level, if the nest level is 0, i.e. outside a comment + // and we find the ;; return TRUE immediately, otherwise keep searching + // if we end with a nest level >0 return FALSE + + char *c = firstComment+2; // firstComment[0] is the '(', firstComment[1] is the '*' + int nestLevel = 1; // we have a (* + + // in-comment determiner loop + while(c[0] != '\0') + { + // are we an endline + if((c[0] == ';') && (c[1] == ';')) + { + // if we are NOT in a comment, its a full line + if(nestLevel <= 0) + { + free(line); + return TRUE; + } + } + + // are we in a comment? + if((c[0] == '(') && (c[1] == '*')) + { + nestLevel++; + + // watch out we may go past the end + if(c[2] == '\0') + { + free(line); + return FALSE; + } + + // c needs to advance past the *, cause (*) is NOT the start/finish of a comment + c++; + } + + // adjust the nesting down a level + if((c[0] == '*') && (c[1] == ')')) + nestLevel--; + + // next char + c++; + } + + // not a full line + free(line); + return FALSE; + } + } + + // weird case ;) + free(line); + return FALSE; +} + +/*------------------------------------------------------------------------ +Procedure: AppendToEditBuffer ID:1 +Author: Chris Watford watford@uiuc.edu +Purpose: Add a line to the edit buffer +Input: Handle of the edit control +Output: +Errors: +------------------------------------------------------------------------*/ +void AppendToEditBuffer(HWND hEdit) +{ + char *p = NULL, linebuffer[2048]; + int n = 0; + int curline = GetCurLineIndex(hEdit); + int linescount = GetNumberOfLines(hEdit); + + // they are passing the size of the buffer as + // the first 'short' in the array... + *(unsigned short *)linebuffer = sizeof(linebuffer)-1; + + if (curline > (linescount-1)) + { + n = SendMessage(hEdit, EM_GETLINE, curline, (LPARAM)linebuffer); + } else { + n = SendMessage(hEdit, EM_GETLINE, --curline, (LPARAM)linebuffer); + } + + // correct for the prompt line + if (n >= 2 && linebuffer[0] == '#' && linebuffer[1] == ' ') + { + n -= 2; + memmove(linebuffer, linebuffer+2, n); + } + + linebuffer[n] = '\0'; + + // linebuffer now has the line to add to our edit buffer + editbuffer_updateoraddline(CurrentEditBuffer, (curline - LastPromptPosition.line), linebuffer); +} + +/*------------------------------------------------------------------------ +Procedure: SetLastPrompt ID:1 +Purpose: Record the position of the last prompt ("# ") sent by +the interpreter. This isn't really used yet. +Input: +Output: +Errors: +------------------------------------------------------------------------*/ +void SetLastPrompt(HWND hEdit) +{ + DWORD startpos,endpos; + SendMessage(hEdit,EM_GETSEL,(WPARAM)&startpos,(LPARAM)&endpos); + LastPromptPosition.line = SendMessage(hEdit,EM_LINEFROMCHAR,(WPARAM)-1,0); + LastPromptPosition.col = startpos; +} + +/*------------------------------------------------------------------------ +Procedure: MdiChildWndProc ID:1 +Purpose: The edit control is enclosed in a normal MDI window. +This is the window procedure for that window. When it +receives the WM_CREATE message, it will create the +edit control. +Input: +Output: +Errors: +-------------------------------------------------------------------------- +Edit History: + 14 Sept 2003 - Chris Watford watford@uiuc.edu + - Added edit buffer and statement buffer support to the WM_NEWLINE + message. + 15 Sept 2003 - Chris Watford watford@uiuc.edu + - Got it adding to the edit buffer + 16 Sept 2003 - Chris Watford watford@uiuc.edu + - Proper handling of newline message finished + 21 Sept 2003 - Chris Watford watford@uiuc.edu + - Added error detection on return from ocaml interp + 23 Sept 2003 - Chris Watford watford@uiuc.edu + - Fixed prompt detection error as pointed out by Patrick Meredith +------------------------------------------------------------------------*/ +static LRESULT CALLBACK MdiChildWndProc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam) +{ + HWND hwndChild; + RECT rc; + HDC hDC; + + switch(msg) { + case WM_CREATE: + GetClientRect(hwnd,&rc); + hwndChild= CreateWindow("EDIT", + NULL, + WS_CHILD | WS_VISIBLE | + ES_MULTILINE | + WS_VSCROLL | WS_HSCROLL | + ES_AUTOHSCROLL | ES_AUTOVSCROLL, + 0, + 0, + (rc.right-rc.left), + (rc.bottom-rc.top), + hwnd, + (HMENU) EditControls++, + hInst, + NULL); + SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) hwndChild); + SendMessage(hwndChild, WM_SETFONT, (WPARAM) ProgramParams.hFont, 0L); + SendMessage(hwndChild,EM_LIMITTEXT,0xffffffff,0); + SubClassEditField(hwndChild); + break; + // Resize the edit control + case WM_SIZE: + hwndChild = (HWND) GetWindowLongPtr(hwnd, DWLP_USER); + MoveWindow(hwndChild, 0, 0, LOWORD(lparam), HIWORD(lparam), TRUE); + break; + // Always set the focus to the edit control. + case WM_SETFOCUS: + hwndChild = (HWND) GetWindowLongPtr(hwnd, DWLP_USER); + SetFocus(hwndChild); + break; + // Repainting of the edit control about to happen. + // Set the text color and the background color + case WM_CTLCOLOREDIT: + hDC = (HDC)wparam; + SetTextColor(hDC,ProgramParams.TextColor); + SetBkColor(hDC,BackColor); + return (LRESULT)BackgroundBrush; + // Take care of erasing the background color to avoid flicker + case WM_ERASEBKGND: + GetWindowRect(hwnd,&rc); + hDC = (HDC)wparam; + FillRect(hDC,&rc,BackgroundBrush); + return 1; + // A carriage return has been pressed. Send the data to the interpreted. + // This message is posted by the subclassed edit field. + case WM_COMMAND: + if (LOWORD(wparam) >= IDEDITCONTROL && LOWORD(wparam) < IDEDITCONTROL+5) { + switch (HIWORD(wparam)) { + case EN_ERRSPACE: + case EN_MAXTEXT: + ResetText(); + break; + } + } + break; + case WM_NEWLINE: + if (busy) + break; + + hwndChild = (HWND) GetWindowLongPtr(hwnd, DWLP_USER); + + // add what they wrote to the edit buffer + AppendToEditBuffer(hwndChild); + + /** Modified by Chris Watford 14 Sept 2003, 15 Sept 2003, 16 Sept 2003 **/ + // test if this line has an end or if it needs to be in the Edit Buffer + if(SendingFullCommand()) + { + // send the edit buffer to the interpreter + //SendLastLine(hwndChild); + SendLastEditBuffer(hwndChild); + historyEntry = NULL; + } else { + AddStringToControl(" "); + } + /** End Modifications **/ + + break; + // The timer will call us 4 times a second. Look if the interpreter + // has written something in its end of the pipe. + case WM_TIMERTICK: + /** Modified by Chris Watford 21 Sept 2003 **/ + hwndChild = (HWND) GetWindowLongPtr(hwnd, DWLP_USER); + + if (ReadToLineBuffer()) + { + int errMsg = 0; + char *p, *l = lineBuffer; + + // Ok we read something. Display the trimmed version + while(((*l) == ' ') || ((*l) == '\t') || ((*l) == '\n') || ((*l) == '\r') || ((*l) == '*')) + l++; + + SendMessage(hwndChild,EM_REPLACESEL,0,(LPARAM)l); + + // fix bug where it won't find prompt + p = strrchr(l, '\r'); + if((l[0] == '#') || (p != NULL)) + { + if(p != NULL) + { + if(!strcmp(p, "\r\n# ")) + { + SetLastPrompt(hwndChild); + } + // solve the bug Patrick found + } else if((l[0] == '#') && (l[1] == ' ')) { + SetLastPrompt(hwndChild); + } + } + + // detect syntax errors + if(strstr(lineBuffer, "Syntax error")) + { + errMsg = WM_SYNTAXERROR; + } else if(strstr(lineBuffer, "Illegal character")) { + errMsg = WM_ILLEGALCHAR; + } else if(strstr(lineBuffer, "Unbound value")) { + errMsg = WM_UNBOUNDVAL; + } + + // error! error! alert alert! + if(errMsg > 0) + { + int len = strlen(lineBuffer); + char* err = (char*)SafeMalloc(len+1); + char *m = err, *n1 = NULL, *n2 = NULL, *nt = NULL; + + // make a copy of the message + strncpy(err, lineBuffer, len); + err[len] = '\0'; + + // find it + m = strstr(err, "Characters "); + if(m == NULL) + break; + + // got the start char + n1 = m + strlen("Characters "); + + // start looking for the end char + nt = strstr(n1, "-"); + if(nt == NULL) + break; + + // makes n1 a valid string + nt[0] = '\0'; + + // end char is right after this + n2 = nt + 1; + + // find the end of n2 + nt = strstr(n2, ":"); + if(nt == NULL) + break; + + // makes n2 a valid string + nt[0] = '\0'; + + SendMessage(hwndChild, errMsg, (WPARAM)atoi(n1), (LPARAM)atoi(n2)); + } + } + /** End Modifications **/ + + break; + + } + return DefMDIChildProc(hwnd, msg, wparam, lparam); +} + + +/*------------------------------------------------------------------------ +Procedure: MainWndProc ID:1 +Purpose: Window procedure for the frame window, that contains +the menu. The messages handled are: +WM_CREATE: Creates the mdi child window +WM_SIZE: resizes the status bar and the mdi child +window +WM_COMMAND: Sends the command to the dispatcher +WM_CLOSE: If the user confirms, it exists the program +WM_QUITOCAML: Stops the program unconditionally. +Input: Standard windows callback +Output: +Errors: +------------------------------------------------------------------------*/ +static LRESULT CALLBACK MainWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) +{ + switch (msg) { + // Create the MDI client invisible window + case WM_CREATE: + hwndMDIClient = CreateMdiClient(hwnd); + TimerId = SetTimer((HWND) 0, 0, 100, (TIMERPROC) TimerProc); + break; + // Move the child windows + case WM_SIZE: + SendMessage(hWndStatusbar,msg,wParam,lParam); + InitializeStatusBar(hWndStatusbar,1); + // Position the MDI client window between the tool and status bars + if (wParam != SIZE_MINIMIZED) { + RECT rc, rcClient; + + GetClientRect(hwnd, &rcClient); + GetWindowRect(hWndStatusbar, &rc); + ScreenToClient(hwnd, (LPPOINT)&rc.left); + rcClient.bottom = rc.top; + MoveWindow(hwndMDIClient,rcClient.left,rcClient.top,rcClient.right-rcClient.left, rcClient.bottom-rcClient.top, TRUE); + } + + return 0; + // Dispatch the menu commands + case WM_COMMAND: + HandleCommand(hwnd, wParam,lParam); + return 0; + // If user confirms close + case WM_CLOSE: + if (!AskYesOrNo("Quit OCamlWinPlus?")) + return 0; + break; + // End application + case WM_DESTROY: + PostQuitMessage(0); + break; + // The interpreter has exited. Force close of the application + case WM_QUITOCAML: + DestroyWindow(hwnd); + return 0; + case WM_USER+1000: + // TestGraphics(); + break; + default: + return DefFrameProc(hwnd,hwndMDIClient,msg,wParam,lParam); + } + return DefFrameProc(hwnd,hwndMDIClient,msg,wParam,lParam); +} + +/*------------------------------------------------------------------------ +Procedure: CreationCourier ID:1 +Purpose: Creates the courier font +Input: +Output: +Errors: +------------------------------------------------------------------------*/ +static HFONT CreationCourier(int flag) +{ + LOGFONT CurrentFont; + memset(&CurrentFont, 0, sizeof(LOGFONT)); + CurrentFont.lfCharSet = ANSI_CHARSET; + CurrentFont.lfWeight = FW_NORMAL; + if (flag) + CurrentFont.lfHeight = 18; + else + CurrentFont.lfHeight = 15; + CurrentFont.lfPitchAndFamily = (BYTE) (FIXED_PITCH | FF_MODERN); + strcpy(CurrentFont.lfFaceName, "Courier"); /* Courier */ + return (CreateFontIndirect(&CurrentFont)); +} + +/*------------------------------------------------------------------------ +Procedure: ReadToLineBuffer ID:1 +Purpose: Reads into the line buffer the characters written by +the interpreter +Input: None +Output: The number of characters read +Errors: None +------------------------------------------------------------------------*/ +int ReadToLineBuffer(void) +{ + memset(lineBuffer,0,sizeof(lineBuffer)); + return ReadFromPipe(lineBuffer,sizeof(lineBuffer)); +} + +/*------------------------------------------------------------------------ +Procedure: AddLineBuffer ID:1 +Purpose: Sends the contents of the line buffer to the edit +control +Input: None +Output: +Errors: +------------------------------------------------------------------------*/ +int AddLineBuffer(void) +{ + HWND hEditCtrl; + + hEditCtrl = (HWND)GetWindowLongPtr(hwndSession,DWLP_USER); + return SendMessage(hEditCtrl,EM_REPLACESEL,0,(LPARAM)lineBuffer); + +} + +/*------------------------------------------------------------------------ +Procedure: Setup ID:1 +Purpose: Handles GUI initialization (Fonts, brushes, colors, +etc) +Input: +Output: +Errors: +------------------------------------------------------------------------*/ +static int Setup(HANDLE *phAccelTable) +{ + if (!InitApplication()) + return 0; + ProgramParams.hFont = CreationCourier(1); + ProgramParams.TextColor = RGB(0,0,0); + GetObject(ProgramParams.hFont,sizeof(LOGFONT),&CurrentFont); + BackgroundBrush = CreateSolidBrush(BackColor); + *phAccelTable = LoadAccelerators(hInst,MAKEINTRESOURCE(IDACCEL)); + return 1; +} + + +/*------------------------------------------------------------------------ +Procedure: WinMain ID:1 +Purpose: Entry point for windows programs. +Input: +Output: +Errors: +------------------------------------------------------------------------*/ +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nCmdShow) +{ + MSG msg; + HANDLE hAccelTable; + char consoleTitle[512]; + HWND hwndConsole; + + CurrentEditBuffer = (EditBuffer*)SafeMalloc(sizeof(EditBuffer)); + CurrentEditBuffer->LineCount = 0; + CurrentEditBuffer->Lines = NULL; + + //setup the history index pointer + historyEntry = NULL; + + // Setup the hInst global + hInst = hInstance; + // Do the setup + if (!Setup(&hAccelTable)) + return 0; + // Need to set up a console so that we can send ctrl-break signal + // to inferior Caml + AllocConsole(); + GetConsoleTitle(consoleTitle,sizeof(consoleTitle)); + hwndConsole = FindWindow(NULL,consoleTitle); + ShowWindow(hwndConsole,SW_HIDE); + // Create main window and exit if this fails + if ((hwndMain = CreateinriaWndClassWnd()) == (HWND)0) + return 0; + // Create the status bar + CreateSBar(hwndMain,"Ready",2); + // Show the window + ShowWindow(hwndMain,SW_SHOW); + // Create the session window + hwndSession = MDICmdFileNew("Session transcript",0); + // Get the path to ocaml.exe + GetOcamlPath(); + // Start the interpreter + StartOcaml(); + // Show the session window + ShowWindow(hwndSession, SW_SHOW); + // Maximize it + SendMessage(hwndMDIClient, WM_MDIMAXIMIZE, (WPARAM) hwndSession, 0); + + PostMessage(hwndMain,WM_USER+1000,0,0); + while (GetMessage(&msg,NULL,0,0)) { + if (!TranslateMDISysAccel(hwndMDIClient, &msg)) + if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { + TranslateMessage(&msg); // Translates virtual key codes + DispatchMessage(&msg); // Dispatches message to window + } + } + WriteToPipe("#quit;;\r\n\032"); + KillTimer((HWND) 0, TimerId); + return msg.wParam; +} diff --git a/ocaml-binary-annot/win32caml/ocaml.ico b/ocaml-binary-annot/win32caml/ocaml.ico Binary files differnew file mode 100644 index 0000000000..13560db450 --- /dev/null +++ b/ocaml-binary-annot/win32caml/ocaml.ico diff --git a/ocaml-binary-annot/win32caml/ocaml.rc b/ocaml-binary-annot/win32caml/ocaml.rc new file mode 100644 index 0000000000..52ae949742 --- /dev/null +++ b/ocaml-binary-annot/win32caml/ocaml.rc @@ -0,0 +1,255 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#define APSTUDIO_HIDDEN_SYMBOLS +#include "windows.h" +#undef APSTUDIO_HIDDEN_SYMBOLS +#include "inriares.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +1000 ICON "ocaml.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDMAINMENU MENU +BEGIN + POPUP "&File" + BEGIN + MENUITEM "&Open...", IDM_OPEN + MENUITEM "&Save ML...", IDM_SAVE + MENUITEM "Save &Transcript...", IDM_SAVEAS + MENUITEM SEPARATOR + MENUITEM "&Print", IDM_PRINT, GRAYED + MENUITEM "P&rint Setup...", IDM_PRINTSU, GRAYED + MENUITEM SEPARATOR + MENUITEM "E&xit", IDM_EXIT + END + POPUP "&Edit" + BEGIN + MENUITEM "&Undo\tAlt+BkSp", IDM_EDITUNDO + MENUITEM SEPARATOR + MENUITEM "Cu&t\t Shift+Del", IDM_EDITCUT + MENUITEM "&Copy\tCtrl+Ins", IDM_EDITCOPY + MENUITEM "&Paste\tShift+Ins", IDM_EDITPASTE + END + POPUP "Workspace" + BEGIN + MENUITEM "&Font...", IDM_FONT + MENUITEM "Text &Color...", IDM_COLORTEXT + MENUITEM "&Background Color...", IDM_BACKCOLOR + MENUITEM SEPARATOR + MENUITEM "&History...", IDM_HISTORY + MENUITEM "&Garbage Collect", IDM_GC + MENUITEM "&Interrupt", IDCTRLC + END + POPUP "&Window", GRAYED + BEGIN + MENUITEM "&Tile", IDM_WINDOWTILE, INACTIVE + MENUITEM "&Cascade", IDM_WINDOWCASCADE, INACTIVE + MENUITEM "Arrange &Icons", IDM_WINDOWICONS, INACTIVE + MENUITEM "Close &All", IDM_WINDOWCLOSEALL, INACTIVE + END + POPUP "&Help" + BEGIN + MENUITEM "&About...", IDM_ABOUT + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Accelerator +// + +BARMDI ACCELERATORS +BEGIN + "Q", IDM_EXIT, VIRTKEY, CONTROL +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUT DIALOGEX 7, 29, 236, 81 +STYLE DS_SETFONT | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | + WS_SYSMENU +EXSTYLE WS_EX_TOOLWINDOW | WS_EX_CLIENTEDGE +CAPTION "About OCamlWinPlus" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + LTEXT "Objective Caml for Windows",101,75,7,90,12 + LTEXT "New Windows Interface 1.9RC4",102,68,15,104,12 + CTEXT "Copyright 1996-2001\nUpdated 2003",103,88,25,66,23 + CTEXT "Institut National de Recherche en Informatique et Automatique", + 104,16,46,211,10 + CTEXT "Réalisé par Jacob Navia 2001. Updated by Chris Watford 2003.\nwatford@uiuc.edu", + 105,18,54,207,19 +END + +IDD_HISTORY DIALOGEX 6, 18, 261, 184 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | + WS_SYSMENU | WS_THICKFRAME +EXSTYLE WS_EX_TOOLWINDOW +CAPTION "Session History" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + LISTBOX IDLIST,7,7,247,173,LBS_USETABSTOPS | WS_VSCROLL | + WS_HSCROLL | WS_TABSTOP +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""windows.h""\r\n" + "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""inriares.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + 3010 "Switches to " +END + +STRINGTABLE +BEGIN + 2000 "Create, open, save, or print documents" + 2010 "Get help" +END + +STRINGTABLE +BEGIN + 500 "Displays information about this application" +END + +STRINGTABLE +BEGIN + 440 "Closes all open windows" +END + +STRINGTABLE +BEGIN + 420 "Arranges windows as overlapping tiles" + 430 "Arranges minimized window icons" +END + +STRINGTABLE +BEGIN + 410 "Arranges windows as non-overlapping tiles" +END + +STRINGTABLE +BEGIN + 340 "Inserts the clipboard contents at the insertion point" + 350 "Removes the selection without putting it on the clipboard" +END + +STRINGTABLE +BEGIN + 320 "Cuts the selection and puts it on the clipboard" + 330 "Copies the selection and puts it on the clipboard" +END + +STRINGTABLE +BEGIN + 310 "Reverses the last action" +END + +STRINGTABLE +BEGIN + 260 "Changes the printer selection or configuration" + 270 "Quits this application" +END + +STRINGTABLE +BEGIN + 240 "Closes the active document" + 250 "Prints the active document" +END + +STRINGTABLE +BEGIN + 230 "Saves the active document under a different name" +END + +STRINGTABLE +BEGIN + 210 "Opens an existing document" + 220 "Saves the active document" +END + +STRINGTABLE +BEGIN + 200 "Creates a new session" +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/ocaml-binary-annot/win32caml/resource.h b/ocaml-binary-annot/win32caml/resource.h new file mode 100644 index 0000000000..67625979c8 --- /dev/null +++ b/ocaml-binary-annot/win32caml/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by ocaml.rc +// + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NO_MFC 1 +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/ocaml-binary-annot/win32caml/startocaml.c b/ocaml-binary-annot/win32caml/startocaml.c new file mode 100644 index 0000000000..f1a3562d9c --- /dev/null +++ b/ocaml-binary-annot/win32caml/startocaml.c @@ -0,0 +1,362 @@ +/***********************************************************************/ +/* */ +/* Objective Caml */ +/* */ +/* Developed by Jacob Navia. */ +/* Copyright 2001 Institut National de Recherche en Informatique et */ +/* en Automatique. All rights reserved. This file is distributed */ +/* under the terms of the GNU Library General Public License, with */ +/* the special exception on linking described in file ../LICENSE. */ +/* */ +/***********************************************************************/ + +/***********************************************************************/ +/* Changes made by Chris Watford to enhance the source editor */ +/* Began 14 Sept 2003 - watford@uiuc.edu */ +/***********************************************************************/ + +/* $Id$ */ + +#include <windows.h> +#include <stdio.h> +#include <io.h> +#include <direct.h> +#include "inria.h" + +PROCESS_INFORMATION pi; +#define BUFSIZE 4096 +STARTUPINFO startInfo; + +/*------------------------------------------------------------------------ +Procedure: ShowDbgMsg ID:1 +Purpose: Puts up a dialog box with a message, forcing it to +the foreground. +Input: +Output: +Errors: +------------------------------------------------------------------------*/ +void ShowDbgMsg(char *str) +{ + HWND hWnd; + char p[20], message[255]; + hWnd = hwndMain; + if (IsIconic(hWnd)){ + ShowWindow(hWnd,SW_RESTORE); + } + strncpy(message, str, 254); + message[254] = 0; + strcpy(p, "Error"); + MessageBox(hWnd, message, p, MB_OK | MB_ICONHAND|MB_TASKMODAL|MB_SETFOREGROUND); +} + +int AskYesOrNo(char *msg) +{ + HWND hwnd; + int r; + + hwnd = hwndMain; + r = MessageBox(hwnd, msg, "Ocaml", MB_YESNO | MB_SETFOREGROUND); + if (r == IDYES) + return (TRUE); + return (FALSE); +} + + +static DWORD OcamlStatus; + +static int RegistryError(void) +{ + char buf[512]; + + wsprintf(buf,"Error %d writing to the registry",GetLastError()); + ShowDbgMsg(buf); + return 0; +} + +static int ReadRegistry(HKEY hroot, + char * p1, char * p2, char * p3, + char dest[1024]) +{ + HKEY h1, h2; + DWORD dwType; + unsigned long size; + LONG ret; + + if (RegOpenKeyExA(hroot, p1, 0, KEY_QUERY_VALUE, &h1) != ERROR_SUCCESS) + return 0; + if (RegOpenKeyExA(h1, p2, 0, KEY_QUERY_VALUE, &h2) != ERROR_SUCCESS) { + RegCloseKey(h1); + return 0; + } + dwType = REG_SZ; + size = 1024; + ret = RegQueryValueExA(h2, p3, 0, &dwType, dest, &size); + RegCloseKey(h2); + RegCloseKey(h1); + return ret == ERROR_SUCCESS; +} + +static int WriteRegistry(HKEY hroot, + char * p1, char * p2, char * p3, + char data[1024]) +{ + HKEY h1, h2; + DWORD disp; + LONG ret; + + if (RegOpenKeyExA(hroot, p1, 0, KEY_QUERY_VALUE, &h1) != ERROR_SUCCESS) + return 0; + if (RegCreateKeyExA(h1, p2, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &h2, &disp) + != ERROR_SUCCESS) { + RegCloseKey(h1); + return 0; + } + ret = RegSetValueEx(h2, p3, 0, REG_SZ, data, strlen(data) + 1); + RegCloseKey(h2); + RegCloseKey(h1); + return ret == ERROR_SUCCESS; +} + +/*------------------------------------------------------------------------ +Procedure: GetOcamlPath ID:1 +Purpose: Read the registry key +HKEY_LOCAL_MACHINE\Software\Objective Caml +or +HKEY_CURRENT_USER\Software\Objective Caml, +and creates it if it doesn't exists. +If any error occurs, i.e. the +given path doesn't exist, or the key didn't exist, it +will put up a browse dialog box to allow the user to +enter the path. The path will be verified that it +points to a file that exists. If that file is in a +directory called 'bin', it will look for another +directory in the same level called lib' and set the +Lib path to that. +Input: None explicit +Output: 1 means sucess, zero failure +Errors: Almost all system calls will be verified +------------------------------------------------------------------------*/ +int GetOcamlPath(void) +{ + char path[1024], *p; + + while (( !ReadRegistry(HKEY_CURRENT_USER, + "Software", "Objective Caml", + "InterpreterPath", path) + && + !ReadRegistry(HKEY_LOCAL_MACHINE, + "Software", "Objective Caml", + "InterpreterPath", path)) + || _access(path, 0) != 0) { + /* Registry key doesn't exist or contains invalid path */ + /* Ask user */ + if (!BrowseForFile("Ocaml interpreter|ocaml.exe", path)) { + ShowDbgMsg("Impossible to find ocaml.exe. I quit"); + exit(0); + } + WriteRegistry(HKEY_CURRENT_USER, + "Software", "Objective Caml", + "InterpreterPath", path); + /* Iterate to validate again */ + } + strcpy(OcamlPath, path); + p = strrchr(OcamlPath,'\\'); + if (p) { + *p = 0; + strcpy(LibDir,OcamlPath); + *p = '\\'; + p = strrchr(LibDir,'\\'); + if (p && !stricmp(p,"\\bin")) { + *p = 0; + strcat(LibDir,"\\lib"); + } + } + return 1; +} + +static HANDLE hChildStdinRd, hChildStdinWr,hChildStdoutRd, hChildStdoutWr; +/*------------------------------------------------------------------------ +Procedure: IsWindowsNT ID:1 +Purpose: Returns 1 if we are running under windows NT, zero +otherwise. +Input: None +Output: 1 or zero +Errors: +------------------------------------------------------------------------*/ +int IsWindowsNT(void) +{ + OSVERSIONINFO osv; + + osv.dwOSVersionInfoSize = sizeof(osv); + GetVersionEx(&osv); + return(osv.dwPlatformId == VER_PLATFORM_WIN32_NT); +} + +/*------------------------------------------------------------------------ +Procedure: DoStartOcaml ID:1 +Purpose: Starts the ocaml interpreter ocaml.exe. The standard +input of the interpreter will be connected to a pipe, +and the standard output and standard error to another +pipe. The interpreter starts as a hidden process, +showing only in the task list. Since this is in an +own thread, its workings are independent of the rest +of the program. After starting the interpreter, the +thread waits in case the interpreter exits, for +instance if the user or some program types #quit;;. +In this case, the waiting thread awakens and exits +the user interface. +Input: Not used. It uses the OcamlPath global variable, that +is supposed to be correct, no test for its validity +are done here. +Output: None visible +Errors: If any system call for whatever reason fails, the +thread will exit. No error message is shown. +------------------------------------------------------------------------*/ +DWORD WINAPI DoStartOcaml(LPVOID param) +{ + HWND hwndParent = (HWND) param; + char *cmdline; + int processStarted; + LPSECURITY_ATTRIBUTES lpsa=NULL; + SECURITY_ATTRIBUTES sa; + SECURITY_DESCRIPTOR sd; + + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + // Under windows NT/2000/Whistler we have to initialize the security descriptors + // This is not necessary under windows 98/95. + if (IsWindowsNT()) { + InitializeSecurityDescriptor(&sd,SECURITY_DESCRIPTOR_REVISION); + SetSecurityDescriptorDacl(&sd,TRUE,NULL,FALSE); + sa.bInheritHandle = TRUE; + sa.lpSecurityDescriptor = &sd; + lpsa = &sa; + } + memset(&startInfo,0,sizeof(STARTUPINFO)); + startInfo.cb = sizeof(STARTUPINFO); + // Create a pipe for the child process's STDOUT. + if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &sa, 0)) + return 0; + // Create a pipe for the child process's STDIN. + if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &sa, 0)) + return 0; + // Setup the start info structure + startInfo.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW; + startInfo.wShowWindow = SW_HIDE; + startInfo.hStdOutput = hChildStdoutWr; + startInfo.hStdError = hChildStdoutWr; + startInfo.hStdInput = hChildStdinRd; + cmdline = OcamlPath; + // Set the OCAMLLIB environment variable + SetEnvironmentVariable("OCAMLLIB", LibDir); + // Let's go: start the ocaml interpreter + processStarted = CreateProcess(NULL,cmdline,lpsa,lpsa,1, + CREATE_NEW_PROCESS_GROUP|NORMAL_PRIORITY_CLASS, + NULL,ProgramParams.CurrentWorkingDir,&startInfo,&pi); + if (processStarted) { + WaitForSingleObject(pi.hProcess,INFINITE); + GetExitCodeProcess(pi.hProcess,(unsigned long *)&OcamlStatus); + CloseHandle(pi.hProcess); + PostMessage(hwndMain,WM_QUITOCAML,0,0); + } + else { + char *msg = malloc(1024); + wsprintf(msg,"Impossible to start ocaml.exe in:\n%s",cmdline); + ShowDbgMsg(msg); + free(msg); + } + return 0; +} + +/*------------------------------------------------------------------------ +Procedure: WriteToPipe ID:1 +Purpose: Writes the given character string to the standard +input of the interpreter +Input: The character string (zero terminated) to be written +Output: The number of characters written or zero if an error +occurs +Errors: None +------------------------------------------------------------------------*/ +int WriteToPipe(char *data) +{ + DWORD dwWritten; + + if (! WriteFile(hChildStdinWr, data, strlen(data), &dwWritten, NULL)) + return 0; + + return dwWritten; + +} + +/*------------------------------------------------------------------------ +Procedure: ReadFromPipe ID:1 +Purpose: Reads from the standard output of the interpreter and +stores the data in the given buffer up to the given +length. This is done in a non-blocking manner, i.e. +it is safe to call this even if there is no data +available. +Input: The buffer to be used and its length. +Output: Returns the number of characters read from the pipe. +Errors: None explicit +------------------------------------------------------------------------*/ +int ReadFromPipe(char *data,int len) +{ + DWORD dwRead; + + PeekNamedPipe(hChildStdoutRd,data,len,NULL,&dwRead,NULL); + if (dwRead == 0) + return 0; + + // Read output from the child process, and write to parent's STDOUT. + if( !ReadFile( hChildStdoutRd, data, len, &dwRead, NULL) || dwRead == 0) + return 0; + + return dwRead; +} + +static DWORD tid; +/*------------------------------------------------------------------------ +Procedure: StartOcaml ID:1 +Purpose: Starts the thread that will call the ocaml.exe +program. +Input: +Output: +Errors: +------------------------------------------------------------------------*/ +int StartOcaml(void) +{ + getcwd(ProgramParams.CurrentWorkingDir,sizeof(ProgramParams.CurrentWorkingDir)); + CreateThread(NULL,0,DoStartOcaml,hwndMain,0,&tid); + return 1; +} + + +void *SafeMalloc(int size) +{ + void *result; + + if (size < 0) { + char message[1024]; + +error: + sprintf(message,"Can't allocate %d bytes",size); + MessageBox(NULL, message, "Ocaml", MB_OK); + exit(-1); + } + result = malloc(size); + + if (result == NULL) + goto error; + + return result; +} + + +void InterruptOcaml(void) +{ + if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, pi.dwProcessId)) { + char message[1024]; + sprintf(message, "GenerateConsole failed: %lu\n", GetLastError()); + MessageBox(NULL, message, "Ocaml", MB_OK); + } + WriteToPipe(" "); +} |
