Tcl Source Code

Check-in [21b74633e5]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:First example of a non-trivial event-driven Tcl program interacting with JS. Features after, [bgerror] and a primitive [domset].
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | ferrieux-nacl
Files: files | file ages | folders
SHA1: 21b74633e5401b388308e948136da8bca4c32d99
User & Date: ferrieux 2011-04-08 22:47:23
Context
2011-04-10
11:25
Cleanup of init, wrappers now compiled in. Coro-based [source $url]. Detailed description in README. check-in: 4d49dfa58c user: ferrieux tags: ferrieux-nacl
2011-04-08
22:47
First example of a non-trivial event-driven Tcl program interacting with JS. Features after, [bger... check-in: 21b74633e5 user: ferrieux tags: ferrieux-nacl
2011-04-06
21:44
Let nacl/tclUnixPort.h be a generated file rather than a source. check-in: bf7fead8fd user: ferrieux tags: ferrieux-nacl
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Added nacl/balls.html.



















































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
<!DOCTYPE html>
<html>
  <!--
  Copyright (c) 2010 The Native Client Authors. All rights reserved.
  Use of this source code is governed by a BSD-style license that can be
  found in the LICENSE file.
  -->
<head>
  <title>Tcl in Nacl</title>

  <script type="text/javascript">
     
     tclModule = null;  // Global application object.
xhr = null;
tclReportError = "";
statusText = 'NO-STATUS';

function tclDo(s) {
    console.log("do:"+s);
    try {
	t = tclModule.eval("naclwrap {"+s+"}");
	console.log("ret:"+t);
	eval(t);
    } catch(err) {
	console.log("err:"+err);
	tclReportError="bgerror {"+err+" -- while doing: "+t+"}";
	setTimeout('tclDo(tclReportError)',0);
    }
}

    function moduleDidLoad() {
      tclModule = document.getElementById('tcl');
      tclModule.eval('proc bgerror s {printf "### BGERROR: $s";regsub -all {[\'\'\\\\]} $s {\\\\&} s;regsub -all \\n $s \t s;return "alert(\'### BGERROR: $s\');";}');
      tclModule.eval('proc naclwrap s {set ::JS "";if {[catch {uplevel 1 $s} err]} {set ::JS [bgerror $err]};return $::JS} ');
      updateStatus('NaTcl Loaded ; fetching script...');
      xhr = new XMLHttpRequest();
      xhr.open("GET","balls.natcl",true);
      xhr.send(null);
      xhr.onreadystatechange = function() {
	  if (xhr.readyState==4)
	      {
		  if (xhr.status==200) {
		      updateStatus("Running");
		      tclDo(xhr.responseText);
		  } else {
		      updateStatus("Cannot load script: "+xhr.status+" "+xhr.statusText);
		  }
	      }
      };
    }

     var statusField = null;
    // If the page loads before the Native Client module loads, then set the
    // status message indicating that the module is still loading.  Otherwise,
    // do not change the status message.
    function pageDidLoad() {
      statusField = document.getElementById('status');
      if (tclModule == null) {
        updateStatus('Loading Nacl...');
      } else {
        // It's possible that the Native Client module onload event fired
        // before the page's onload event.  In this case, the status message
        // will reflect 'SUCCESS', but won't be displayed.  This call will
        // display the current message.
        updateStatus();
      }
    }

    function doeval() {
      try {
        alert(tclModule.eval(this.the_form.input_id.value));
      } catch(e) {
        alert(e.message);
      }
    }

    // Set the global status message.  If the element with id 'status'
    // exists, then set its HTML to the status message as well.
    // opt_message The message test.  If this is null or undefined, then
    //     attempt to set the element with id 'status' to the value of
    //     |statusText|.
    function updateStatus(opt_message) {
      if (opt_message)
        statusText = opt_message;
      if (statusField) {
        statusField.innerHTML = statusText;
      }
    }
  </script>
</head>
<body onload="pageDidLoad()">

<h1>Native Client Tcl Module</h1>
<p>
  <form name="the_form" action="" method="get">
  <input type="text" id="input_id" name="inputbox" value="list a b c"><p>
  <input type="button" value="Call eval()" onclick="doeval()">
  </form>
  <!-- Load the published .nexe.  This includes the 'nacl' attribute which
  shows how to load multi-architecture modules.  Each entry in the "nexes"
  object in the  .nmf manifest file is a key-value pair: the key is the runtime
  ('x86-32', 'x86-64', etc.); the value is a URL for the desired NaCl module.
  To load the debug versions of your .nexes, set the 'nacl' attribute to the
  _dbg.nmf version of the manifest file.
  -->
  <embed name="nacl_module"
         id="tcl"
         width=0 height=0
         nacl="tcl.nmf"
         type="application/x-nacl"
         onload="moduleDidLoad();" />
</p>

<p>If the module is working correctly, a click on the "Call eval()" button
  should open a popup dialog containing the Tcl result as its value.</p>

<h2>Status</h2>
<div id="status">NO-STATUS</div>
<hr>
</body>
</html>

Added nacl/balls.natcl.

























































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
#------ Std preamble
proc after {ms script} {
    regsub -all {[""''\\]} $script {\\&} script
    append ::JS "setTimeout(\"tclDo('$script')\",$ms);\n"
}
proc domset {element inner} {
    regsub -all {[''\\]} $inner {\\&} inner
    regsub -all \n $inner \t inner
    append ::JS "$element.innerHTML='$inner';\n"
}

#------ App callbacks

set cnt 0

proc daemon {} {
    after 1000 daemon
    printf DAEMON:$::cnt
    domset statusField "<h1 align='center'>DAEMON:$::cnt</h1>"
    incr ::cnt
    if {$::cnt>10} {
       error "Oh, I barfed !"
    }
}

#------ Runtime
printf Salut!!!
daemon

Changes to nacl/index.html.

19
20
21
22
23
24
25

26
27
28
29
30
31
32

    // If the page loads before the Native Client module loads, then set the
    // status message indicating that the module is still loading.  Otherwise,
    // do not change the status message.
    function pageDidLoad() {
      if (tclModule == null) {
        updateStatus('LOADING...');

      } else {
        // It's possible that the Native Client module onload event fired
        // before the page's onload event.  In this case, the status message
        // will reflect 'SUCCESS', but won't be displayed.  This call will
        // display the current message.
        updateStatus();
      }







>







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

    // If the page loads before the Native Client module loads, then set the
    // status message indicating that the module is still loading.  Otherwise,
    // do not change the status message.
    function pageDidLoad() {
      if (tclModule == null) {
        updateStatus('LOADING...');
    alert(' FOO \'  BAR \\ BAZ');
      } else {
        // It's possible that the Native Client module onload event fired
        // before the page's onload event.  In this case, the status message
        // will reflect 'SUCCESS', but won't be displayed.  This call will
        // display the current message.
        updateStatus();
      }

Changes to nacl/naclMain.c.

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


#include <errno.h>
#include "tcl.h"
#include "tclInt.h"

static Tcl_Interp *interp = NULL;


const char *init_tcl_contents =
"set ::tcl_library {/}\n"
# include "init.tcl.c"
  ;
















static Tcl_Interp *NewTcl(void)
{
  Tcl_Interp *ii;

  printf("DBUG:TclInitSubsystems\n");
  TclInitSubsystems();
  printf("DBUG:TclpSetInitialEncodings\n");
  TclpSetInitialEncodings();

  printf("DBUG:Busyloop-check\n");
  {
    volatile int x;

    x=0;
    if (x) printf("BUSYLOOP : break out by resetting the var (set $eax=0)\n");
    else printf("NO-BUSYLOOP\n");
    while(x) {}
  }
  printf("DBUG:CreateInterp\n");
  ii=Tcl_CreateInterp();
  if (!ii) {
    printf("Tcl CreateInterp Failed !!!\n");
    return NULL;
  }
  printf("DBUG:Tcl_Init2\n");
  if (Tcl_Eval(ii,init_tcl_contents)!=TCL_OK) {
    printf("Tcl Init Failed: %s !!!\n",Tcl_GetStringResult(ii));
    return NULL;
  }

  return ii;
}
static const char *EvalTcl(char *s)
{
  if (!interp) return "No Tcl Interp!!!";
  Tcl_Eval(interp,s);
  return Tcl_GetStringResult(interp);







>





>
>
>
>
>
>
>
>
>
>
>
>
>
>
>





|

|


<




|
<


|


|


|

|


>







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


#include <errno.h>
#include "tcl.h"
#include "tclInt.h"

static Tcl_Interp *interp = NULL;
static int pid = 0;

const char *init_tcl_contents =
"set ::tcl_library {/}\n"
# include "init.tcl.c"
  ;

static int PrintfObjCmd(
			ClientData clientData,
			Tcl_Interp *interp,
			int objc,
			Tcl_Obj *const objv[])
{
    if (objc != 2) {
	Tcl_WrongNumArgs(interp, 1, objv, "string");
	return TCL_ERROR;
    }
    printf("NaTcl(%d): %s\n", pid, Tcl_GetString(objv[1]));
    return TCL_OK;
}


static Tcl_Interp *NewTcl(void)
{
  Tcl_Interp *ii;

  //printf("DBUG:TclInitSubsystems\n");
  TclInitSubsystems();
  //printf("DBUG:TclpSetInitialEncodings\n");
  TclpSetInitialEncodings();


  {
    volatile int x;

    x=0;
    if (x) printf("NaTcl(%d): BUSYLOOP : break out by resetting the var (set $eax=0)\n",pid);

    while(x) {}
  }
  //  printf("DBUG:CreateInterp\n");
  ii=Tcl_CreateInterp();
  if (!ii) {
    printf("NaTcl(%d): Tcl CreateInterp Failed !!!\n",pid);
    return NULL;
  }
  //printf("DBUG:Tcl_Init2\n");
  if (Tcl_Eval(ii,init_tcl_contents)!=TCL_OK) {
    printf("NaTcl(%d): Tcl Init Failed: %s !!!\n",pid,Tcl_GetStringResult(ii));
    return NULL;
  }
  Tcl_CreateObjCommand(ii,"printf",PrintfObjCmd,NULL,NULL);
  return ii;
}
static const char *EvalTcl(char *s)
{
  if (!interp) return "No Tcl Interp!!!";
  Tcl_Eval(interp,s);
  return Tcl_GetStringResult(interp);
228
229
230
231
232
233
234
235
236

237
238
239
240
241
242
243

/**
 * Create scriptable object for the given instance.
 * @param[in] instance The instance ID.
 * @return A scriptable object.
 */
static struct PP_Var Instance_GetInstanceObject(PP_Instance instance) {
  if (var_interface)
    return var_interface->CreateObject(instance, &ppp_class, NULL);

  return PP_MakeUndefined();
}

/**
 * Check existence of the function associated with @a name.
 * @param[in] object unused
 * @param[in] name method name







|

>







243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259

/**
 * Create scriptable object for the given instance.
 * @param[in] instance The instance ID.
 * @return A scriptable object.
 */
static struct PP_Var Instance_GetInstanceObject(PP_Instance instance) {
  if (var_interface) {
    return var_interface->CreateObject(instance, &ppp_class, NULL);
  }
  return PP_MakeUndefined();
}

/**
 * Check existence of the function associated with @a name.
 * @param[in] object unused
 * @param[in] name method name
298
299
300
301
302
303
304

305
306
307
308
309
310
311
312
313
314
315
316
 * Initialize instance interface and scriptable object class.
 * @param[in] a_module_id module ID
 * @param[in] get_browser pointer to PPB_GetInterface
 * @return PP_OK on success, any other value on failure.
 */
PP_EXPORT int32_t PPP_InitializeModule(PP_Module a_module_id,
                                       PPB_GetInterface get_browser) {

  module_id = a_module_id;
  var_interface =
      (struct PPB_Var_Deprecated*)(get_browser(PPB_VAR_DEPRECATED_INTERFACE));

  printf("DBUG:begin\n");
  interp = NewTcl();
  if (!interp) return PP_ERROR_FAILED;

  memset(&ppp_class, 0, sizeof(ppp_class));
  ppp_class.Call = Tcl_Call;
  ppp_class.HasMethod = Tcl_HasMethod;
  return PP_OK;







>




|







314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
 * Initialize instance interface and scriptable object class.
 * @param[in] a_module_id module ID
 * @param[in] get_browser pointer to PPB_GetInterface
 * @return PP_OK on success, any other value on failure.
 */
PP_EXPORT int32_t PPP_InitializeModule(PP_Module a_module_id,
                                       PPB_GetInterface get_browser) {
  pid = getpid();
  module_id = a_module_id;
  var_interface =
      (struct PPB_Var_Deprecated*)(get_browser(PPB_VAR_DEPRECATED_INTERFACE));

  printf("NaTcl(%d): DBUG: NaTcl starting\n",pid);
  interp = NewTcl();
  if (!interp) return PP_ERROR_FAILED;

  memset(&ppp_class, 0, sizeof(ppp_class));
  ppp_class.Call = Tcl_Call;
  ppp_class.HasMethod = Tcl_HasMethod;
  return PP_OK;

Changes to nacl/tools/chrd.

1
2

3
#! /bin/sh -x
./chromedebug http://localhost:5103/tcl/



|
>

1
2
3
4
#! /bin/sh -x
./chromedebug http://localhost:5103/tcl/${1:-balls.html}


Changes to nacl/tools/chromedebug.

1
2


3
4
#! /bin/sh -x



NACLVERBOSITY=2 google-chrome --no-sandbox "$@"
#PPAPI_BROWSER_DEBUG=1 NACL_PLUGIN_DEBUG=1 NACL_PPAPI_PROXY_DEBUG=1 NACLVERBOSITY=15 google-chrome --no-sandbox "$@"


>
>
|

1
2
3
4
5
6
#! /bin/sh -x

google-chrome --no-sandbox "$@"

#NACLVERBOSITY=2 google-chrome --no-sandbox "$@"
#PPAPI_BROWSER_DEBUG=1 NACL_PLUGIN_DEBUG=1 NACL_PPAPI_PROXY_DEBUG=1 NACLVERBOSITY=15 google-chrome --no-sandbox "$@"