Hi folks,
I tried to compile the following program with both ghc-3.02 and ghc-4.02

(pathlevel 1), using the linux glibc binary releases. The 3.02 one works

fine but the code produced by 4.02 segmentation faults when I try to run

it.

It uses a c program, which links to code in tcl-tk v8.0. I've included
the tclhaskell.c and tclhaskell.h files at the end of this mail.

I compiled with
gcc -c -I/usr/local/opt/include  -I/usr/local/opt/include
-I/usr/X11/include  tclhaskell.c
ghc-4.02 -O -fvia-C -fglasgow-exts -c '-#include "tclhaskell.h"' Main.hs

ghc-4.02 -O -fvia-C -fglasgow-exts -ltk8.0 -ltcl8.0 -lX11 -lm -lc -ldl
-L/usr/local/opt/lib  -L/usr/local/opt/lib  -L/usr/X11/lib  -L/usr/lib
-L/lib -o main Main.o tclhaskell.o
and similarly for ghc-3.02

Thanks
  Meurig

--- Main.hs
-----------------------------------------------------------------
module Main where

main :: IO ()
main = do
 primInitTcl
 primExecuteTcl_ "button .b -text ben"
 primExecuteTcl_ "pack .b"
 loop
  where
   loop = do
    still <- primRunTcl
    if still then loop
     else return ()

primInitTcl :: IO Bool
primInitTcl = map' int2bool $ _ccall_ primInitTcl

primExecuteTcl_ :: String -> IO ()
primExecuteTcl_ s = _ccall_ primExecuteTcl_ s

primRunTcl :: IO Bool
primRunTcl = map' int2bool (_ccall_ primRunTcl)

map' :: (a -> b) -> IO a -> IO b
map' f io = do
  x <- io
  return $ f x

int2bool :: Int -> Bool
int2bool 0 = False
int2bool n = True


-- tclhaskell.h
--------------------------------------------------------------
void primPutEnv (char *str);
void primTclDebug(int flg);
int  primInitTcl(void);
int  primRunTcl(void);
char *primExecuteTcl(char *cmd);
void primExecuteTcl_ (char *cmd);
char *primGetEvent(void);
void primSetVar(char * varname,char * inp);

-- tclhaskell.c -----------------------------------------------
/* ------------------------------------------------------------
 * tclhaskell.c --
 *
 *      Based on tkgofer.c from the TkGofer distribution.
 *      Changes by Chris Dornan ([EMAIL PROTECTED]).
 *
 * This file contains the interface for the "haskell-tcl" link.
 * It is based on tkMain.c - the main program of wish.
 *
 * It supports a new tcl-command
 * - haskell_event n    : to write the string n into the event buffer
 *
 * The provided gofer primitives are
 * - primInitTcl       : to initialze tcl/tk, returns 1 if successful
 * - primRunTcl      : to start the eventloop of tcl/tk
 *      - primExecuteTcl     : to evaluate an event by the tcl
interpreter
 * - primGetEvent       : to read the event buffer
 *                             buffer contains event identification
 *                             plus bind arguments
 *      - primSetVar         : write user output into tcl variables
 *
------------------------------------------------------------ */

#include <stdio.h>
#include <stdlib.h>

#include <tcl.h>
#include <tk.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#include "tclhaskell.h"


void  primPutEnv(char *str)
{
  char *cpy = malloc(strlen(str)+1);

  if (str!=NULL) {
    strcpy(cpy,str);
    putenv(cpy);
  }
}



/* ------------------------------------------------------------
* Declaration for debug information
------------------------------------------------------------ */

Bool tcl_debug=0;   /* TRUE  => show debug information */


/* ------------------------------------------------------------
 * Declaration for window and interpreter variables
------------------------------------------------------------ */

static Tcl_Interp *interp;         /* Interpreter for this application.
*/

#define BUFFER_SIZE 2000           /* Buffers for communication
        Contains identifier and
        bind arguments
             */

#define QUEUE_SLOTS 20                  /* The number of slots in the
buffer */

int queue_head, queue_tail, queue_full; /* The head, tail and full flag
of
        the event queue, organised as a
        cyclic buffer
             */

static char event_buffer[BUFFER_SIZE];   /* the event buffer */


/* ------------------------------------------------------------
 * Reporting Errors
------------------------------------------------------------ */

tkh_error(char *message)
{
  fprintf(stderr, "TclHaskell: %s\n", message);
}

tkh_abort(char *message)
{
  tkh_error(message);
  abort();
}


/* ------------------------------------------------------------
 * Buffer manipulation functions
------------------------------------------------------------ */

static int slot_size(void)
{
  return (BUFFER_SIZE/QUEUE_SLOTS);
}

static int slot_base(int i)
{
  return (i*slot_size());
}

static void inc_index(int *i)
{
  *i= (*i+1) % QUEUE_SLOTS;
}

static int init_queue(void)
{
  queue_head= queue_tail= queue_full= 0;
}

static int queue_empty(void)
{
  return (!queue_full && queue_head==queue_tail);
}

static void enqueue(char *str)
{
  if (str[0]==0) {
    tkh_error("empty event string");
    return;
  }
  if (strlen(str)+1>slot_size()) {
    tkh_error("event string too large");
    return;
  }
  if (queue_full) {
    tkh_error("event buffer overrun");
    return;
  }
  strcpy(event_buffer+slot_base(queue_tail), str);
  inc_index(&queue_tail);
  if (queue_head==queue_tail)
    queue_full= 1;
}

static char *dequeue(void)
{
  char *item = event_buffer+slot_base(queue_head);

  if (queue_empty())
    tkh_abort("empty queue");

  inc_index(&queue_head);
  queue_full= 0;
  return item;
}


/* ------------------------------------------------------------
 *  haskellEventCmd:
 *    (Registered as a new Tcl command: see initTcl, below.)
 *
 *    This is used as part of the callback mechanism: it inserts
 *    argument string into the TclHaskell event queue, triggering
 *    primRunTcl to break its loop so that TclHaskell can retrieve
 *    the event descriptor woth primGetEvent.
------------------------------------------------------------ */

static int haskellEventCmd(dummy, interp, argc, argv)
    ClientData dummy;                   /* Not used. */
    Tcl_Interp *interp;                 /* Current interpreter. */
    int argc;                           /* Number of arguments. */
    char **argv;                        /* Argument strings. */
{

    if (tcl_debug) {
        fprintf(stderr, "[Queueing Event: %s]\n", argv[1]);
    }

    /* ignore surplus arguments as passed to scale commands, for example
*/

    if (argc<2){
        Tcl_AppendResult(interp,
    "haskellEvent: should have at least 1 argument",
    (char *) NULL);
        return TCL_ERROR;
    }
    enqueue(argv[1]);

    return TCL_OK;
}


/* ------------------------------------------------------------
 *  Implementation of Haskell Primitives
------------------------------------------------------------ */



/* ------------------------------------------------------------
 *  primTclDebug:
 *    sets the debug flag
------------------------------------------------------------ */

void primTclDebug (int flg)
{
  tcl_debug = flg;
}


/* ------------------------------------------------------------
 *  primInitTcl:
 *    initializes Tcl/Tk,
 *    and the new new command `haskellEvent',
 *    return 1 if successful, 0 otherwise.
------------------------------------------------------------ */

int primInitTcl (void) {


    if (tcl_debug) {
        fprintf(stderr, "[Initialize Tcl]\n");
    }

    init_queue();          /* Reset commuication buffers */

    interp = Tcl_CreateInterp();

    Tcl_SetVar(interp, "tcl_interactive", "0", TCL_GLOBAL_ONLY);

    if (Tcl_Init(interp) == TCL_ERROR) {
 fprintf(stderr, "%s\n", interp->result);
 return(0);
    }

    if (Tk_Init(interp) == TCL_ERROR) {
 fprintf(stderr, "%s\n", interp->result);
 return(0);
    }


    /* Extensions for tcl: */

    Tcl_CreateCommand(interp, "haskellEvent", haskellEventCmd,
        (ClientData) NULL, (void (*)()) NULL);

    return(1);
}



/* ------------------------------------------------------------
 *  primRunTcl:
 *    runs Tcl's event loop until one or more events
 *    are queued for Haskell processing, returning 1
 *    if `.' has been destroyed, 0 otherwise.
------------------------------------------------------------ */

int primRunTcl (void) {

    if (tcl_debug) {
    fprintf(stderr, "[TclHaskell is waiting for an event...]\n");
    }

    while ((Tk_GetNumMainWindows() > 0) && (queue_empty())) {
      Tk_DoOneEvent(0);
    }
    return (Tk_GetNumMainWindows() > 0);
}



/* ------------------------------------------------------------
 *  primExecuteTcl:
 *    perform Tcl command and return result to TclHaskell
------------------------------------------------------------ */

static char *executeTcl (char *cmd);

char *primExecuteTcl (char *cmd)
{
  char *result;

  result= executeTcl(cmd);
  if (tcl_debug) fprintf(stderr, "  %s <- %s\n", result, cmd);
  return result;
}

void primExecuteTcl_ (char *cmd)
{
  (void) executeTcl(cmd);
  if (tcl_debug) fprintf(stderr, "  %s\n", cmd);
}

static char *executeTcl (char *cmd)
{
   if (Tcl_Eval(interp,cmd) != TCL_OK) {
       fprintf(stderr, "Tk/Tcl: %s\n", interp->result);
       return ("");
   }
   return (interp -> result);
}



/* ------------------------------------------------------------
 *  primGetEvent:
 *    return the event buffer to gofer
------------------------------------------------------------ */

char *primGetEvent(void) {

  if (queue_empty())
    return ("");
  else {
    char *item = dequeue();

    if (tcl_debug) {
      fprintf (stderr, "[Processing event %s]\n", item);
    }
    return(item);
  }
}



/* ------------------------------------------------------------
 *  primSetVar:
 *    write user output in tcl variable
 *    in this way, special tcl characters
 *    like [, $, } etc. are irrelevant for tcl.
------------------------------------------------------------ */

void primSetVar(char *varname, char *inp)
{
    if (tcl_debug) {
       fprintf(stderr, "set %s %s\n", varname, inp);
    }
    Tcl_SetVar(interp, varname, inp, TCL_GLOBAL_ONLY);
}

--
Meurig Sage
Dept of Computing Science
University of Glasgow
http://www.dcs.gla.ac.uk/~meurig
mailto:[EMAIL PROTECTED]


Reply via email to