summaryrefslogtreecommitdiff
path: root/otherlibs/labltk/support/cltkDMain.c
blob: 06449faf795bf09d49dead5770668e6c25ea142f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
#include <unistd.h>
#include <fcntl.h>  
#include <tcl.h>
#include <tk.h>
#include "gc.h"
#include "exec.h"
#include "sys.h"
#include "fail.h"
#include "io.h"
#include "mlvalues.h"
#include "memory.h"
#include "camltk.h"

#ifndef O_BINARY
#define O_BINARY 0
#endif


/* 
 * Dealing with signals: when a signal handler is defined in Caml,
 * the actual execution of the signal handler upon reception of the
 * signal is delayed until we are sure we are out of the GC.
 * If a signal occurs during the MainLoop, we would have to wait
 *  the next event for the handler to be invoked.
 * The following function will invoke a pending signal handler if any,
 * and we put in on a regular timer.
 */

#define SIGNAL_INTERVAL 300

int signal_events = 0; /* do we have a pending timer */

void invoke_pending_caml_signals (clientdata) 
     ClientData clientdata;
{
  signal_events = 0;
  enter_blocking_section(); /* triggers signal handling */
  /* Rearm timer */
  Tk_CreateTimerHandler(SIGNAL_INTERVAL, invoke_pending_caml_signals, NULL);
  signal_events = 1;
  leave_blocking_section();
}
/* The following is taken from byterun/startup.c */
header_t atom_table[256];
code_t start_code;
asize_t code_size;

static void init_atoms()
{
  int i;
  for(i = 0; i < 256; i++) atom_table[i] = Make_header(0, i, White);
}

static unsigned long read_size(p)
     unsigned char * p;
{
  return ((unsigned long) p[0] << 24) + ((unsigned long) p[1] << 16) +
         ((unsigned long) p[2] << 8) + p[3];
}

#define FILE_NOT_FOUND (-1)
#define TRUNCATED_FILE (-2)
#define BAD_MAGIC_NUM (-3)

static int read_trailer(fd, trail)
     int fd;
     struct exec_trailer * trail;
{
  char buffer[TRAILER_SIZE];

  lseek(fd, (long) -TRAILER_SIZE, 2);
  if (read(fd, buffer, TRAILER_SIZE) < TRAILER_SIZE) return TRUNCATED_FILE;
  trail->code_size = read_size(buffer);
  trail->data_size = read_size(buffer+4);
  trail->symbol_size = read_size(buffer+8);
  trail->debug_size = read_size(buffer+12);
  if (strncmp(buffer + 16, EXEC_MAGIC, 12) == 0)
    return 0;
  else
    return BAD_MAGIC_NUM;
}

int attempt_open(name, trail, do_open_script)
     char ** name;
     struct exec_trailer * trail;
     int do_open_script;
{
  char * truename;
  int fd;
  int err;
  char buf [2];

  truename = searchpath(*name);
  if (truename == 0) truename = *name; else *name = truename;
  fd = open(truename, O_RDONLY | O_BINARY);
  if (fd == -1) return FILE_NOT_FOUND;
  if (!do_open_script){
    err = read (fd, buf, 2);
    if (err < 2) { close(fd); return TRUNCATED_FILE; }
    if (buf [0] == '#' && buf [1] == '!') { close(fd); return BAD_MAGIC_NUM; }
  }
  err = read_trailer(fd, trail);
  if (err != 0) { close(fd); return err; }
  return fd;
}


/* Command for loading the bytecode file */
int CamlRunCmd(dummy, interp, argc, argv)
    ClientData dummy;                   /* Not used. */
    Tcl_Interp *interp;                 /* Current interpreter. */
    int argc;                           /* Number of arguments. */
    char **argv;                        /* Argument strings. */
{
  int fd;
  struct exec_trailer trail;
  struct longjmp_buffer raise_buf;
  struct channel * chan;

  if (argc < 2) {
        Tcl_AppendResult(interp, "wrong # args: should be \"",
                argv[0], " foo.cmo args\"", (char *) NULL);
        return TCL_ERROR;
  }
  fd = attempt_open(&argv[1], &trail, 1);

  switch(fd) {
  case FILE_NOT_FOUND:
    fatal_error_arg("Fatal error: cannot find file %s\n", argv[1]);
    break;
  case TRUNCATED_FILE:
  case BAD_MAGIC_NUM:
    fatal_error_arg(
		    "Fatal error: the file %s is not a bytecode executable file\n",
		    argv[1]);
    break;
  }

  if (sigsetjmp(raise_buf.buf, 1) == 0) {

    external_raise = &raise_buf;

    lseek(fd, - (long) (TRAILER_SIZE + trail.code_size + trail.data_size
                        + trail.symbol_size + trail.debug_size), 2);

    code_size = trail.code_size;
    start_code = (code_t) stat_alloc(code_size);
    if (read(fd, (char *) start_code, code_size) != code_size)
      fatal_error("Fatal error: truncated bytecode file.\n");

#ifdef ARCH_BIG_ENDIAN
    fixup_endianness(start_code, code_size);
#endif

    chan = open_descr(fd);
    global_data = input_value(chan);
    close_channel(chan);
    /* Ensure that the globals are in the major heap. */
    oldify(global_data, &global_data);

    sys_init(argv + 1);
    interprete(start_code, code_size);
    return TCL_OK;
  } else {
    Tcl_AppendResult(interp, "Caml program", argv[1], " raised exception \"",
		     String_val(Field(Field(exn_bucket, 0), 0)));
    return TCL_ERROR;
  }
}

int CamlInvokeCmd(dummy



/* Now the real Tk stuff */
static Tk_Window mainWindow;

#define RCNAME ".camltkrc"
#define CAMLCB "camlcb"

/* Initialisation of the dynamically loaded module */
int Caml_Init(interp)
     Tcl_Interp *interp;
{
  cltclinterp = interp;
  /* Create the camlcallback command */
  Tcl_CreateCommand(cltclinterp,
		    CAMLCB, CamlCBCmd, 
		    (ClientData)NULL,(Tcl_CmdDeleteProc *)NULL);

  /* This is required by "unknown" and thus autoload */
  Tcl_SetVar(cltclinterp, "tcl_interactive", "0", TCL_GLOBAL_ONLY);
  /* Our hack for implementing break in callbacks */
  Tcl_SetVar(cltclinterp, "BreakBindingsSequence", "0", TCL_GLOBAL_ONLY);

  /* Load the traditional rc file */
  {
    char *home = getenv("HOME");
    if (home != NULL) {
      char *f = stat_alloc(strlen(home)+strlen(RCNAME)+2);
      f[0]='\0';
      strcat(f, home);
      strcat(f, "/");
      strcat(f, RCNAME);
      if (0 == access(f,R_OK)) 
	if (TCL_OK != Tcl_EvalFile(cltclinterp,f)) {
	  stat_free(f);
	  tk_error(cltclinterp->result);
	};
      stat_free(f);
    }
  }
  
  /* Initialisations from caml_main */
  {
    int verbose_init = 0,
        percent_free_init = Percent_free_def;
    long minor_heap_init = Minor_heap_def,
         heap_chunk_init = Heap_chunk_def;

    /* Machine-dependent initialization of the floating-point hardware
       so that it behaves as much as possible as specified in IEEE */
    init_ieee_floats();
    init_gc (minor_heap_init, heap_chunk_init, percent_free_init,
	     verbose_init);
    init_stack();
    init_atoms();
  }
}