Coverage Report

Created: 2026-07-16 06:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/moddable/xs/tools/xst.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2016-2026  Moddable Tech, Inc.
3
 *
4
 *   This file is part of the Moddable SDK Tools.
5
 * 
6
 *   The Moddable SDK Tools is free software: you can redistribute it and/or modify
7
 *   it under the terms of the GNU General Public License as published by
8
 *   the Free Software Foundation, either version 3 of the License, or
9
 *   (at your option) any later version.
10
 * 
11
 *   The Moddable SDK Tools is distributed in the hope that it will be useful,
12
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 *   GNU General Public License for more details.
15
 * 
16
 *   You should have received a copy of the GNU General Public License
17
 *   along with the Moddable SDK Tools.  If not, see <http://www.gnu.org/licenses/>.
18
 *
19
 */
20
21
#include "xsAll.h"
22
#include "xsScript.h"
23
#include "xs.h"
24
25
extern int fuzz(int argc, char* argv[]);
26
extern void fx_print(xsMachine* the);
27
extern void fxBuildAgent(xsMachine* the);
28
extern void fxBuildFuzz(xsMachine* the);
29
extern txScript* fxLoadScript(txMachine* the, txString path, txUnsigned flags);
30
extern void fxFulfillModuleFile(txMachine* the);
31
extern void fxRejectModuleFile(txMachine* the);
32
extern void fxRunLoop(txMachine* the);
33
extern void fxRunModuleFile(txMachine* the, txString path);
34
extern void fxRunProgramFile(txMachine* the, txString path, txUnsigned flags);
35
extern int fxBundleIs(const char *buffer, size_t size);
36
extern int fxBundleLoad(txMachine *the, txSlot *module, txID moduleID);
37
extern void fxBundleMapReset(void);
38
extern void fxBundleRun(txMachine *the, char *buffer, size_t size);
39
extern int main262(int argc, char* argv[]);
40
41
struct sxJob {
42
  txMachine* the;
43
  txSlot self;
44
  txSlot function;
45
  txSlot argument;
46
};
47
48
struct sxSharedTimer {
49
  txSharedTimer* next;
50
  txThread thread;
51
  txNumber when;
52
  txNumber interval;
53
  txSharedTimerCallback callback;
54
  txInteger refconSize;
55
  char refcon[1];
56
};
57
58
static void fxPrintUsage();
59
static int fxRunBundle(const char* path);
60
61
static void fx_agent_broadcast(xsMachine* the);
62
static void fx_agent_getReport(xsMachine* the);
63
static void fx_agent_leaving(xsMachine* the);
64
static void fx_agent_monotonicNow(xsMachine* the);
65
static void fx_agent_receiveBroadcast(xsMachine* the);
66
static void fx_agent_report(xsMachine* the);
67
static void fx_agent_sleep(xsMachine* the);
68
static void fx_agent_start(xsMachine* the);
69
#if mxWindows
70
static unsigned int __stdcall fx_agent_start_aux(void* it);
71
#else
72
static void* fx_agent_start_aux(void* it);
73
#endif
74
static void fx_createRealm(xsMachine* the);
75
static void fx_detachArrayBuffer(xsMachine* the);
76
static void fx_evalScript(xsMachine* the);
77
static void fx_gc(xsMachine* the);
78
static void fx_isLockedDown(xsMachine* the);
79
static void fx_metering(xsMachine* the);
80
static void fx_runScript(xsMachine* the);
81
82
extern void fx_clearTimer(txMachine* the);
83
static void fx_destroyTimer(void* data);
84
static void fx_markTimer(txMachine* the, void* it, txMarkRoot markRoot);
85
static void fx_setInterval(txMachine* the);
86
static void fx_setTimeout(txMachine* the);
87
static void fx_setTimer(txMachine* the, txNumber interval, txBoolean repeat);
88
89
txAgentCluster gxAgentCluster;
90
91
#if OSSFUZZ
92
int omain(int argc, char* argv[]) 
93
#else
94
int main(int argc, char* argv[]) 
95
#endif
96
0
{
97
0
  txAgentCluster* agentCluster = &gxAgentCluster;
98
0
  int argi;
99
0
  int option = 0;
100
0
  int profiling = 0;
101
0
  int bundle = 0;
102
0
  char path[C_PATH_MAX];
103
0
  char* dot;
104
#if mxWindows
105
    char* harnessPath = "..\\harness";
106
#else
107
0
    char* harnessPath = "../harness";
108
0
#endif
109
0
  int error = 0;
110
  
111
0
  c_memset(agentCluster, 0, sizeof(txAgentCluster));
112
0
  fxCreateMutex(&(agentCluster->mainMutex));
113
0
  fxCreateCondition(&(agentCluster->countCondition));
114
0
  fxCreateMutex(&(agentCluster->countMutex));
115
0
  fxCreateCondition(&(agentCluster->dataCondition));
116
0
  fxCreateMutex(&(agentCluster->dataMutex));
117
0
  fxCreateMutex(&(agentCluster->reportMutex));
118
119
0
  if (argc == 1) {
120
0
    fxPrintUsage();
121
0
    return 1;
122
0
  }
123
0
  for (argi = 1; argi < argc; argi++) {
124
0
    if (argv[argi][0] != '-')
125
0
      continue;
126
  
127
0
    if (!strcmp(argv[argi], "-c"))
128
0
      option = 4;
129
0
    else if (!strcmp(argv[argi], "-i")) {
130
0
      argi++;
131
0
      option = 4;
132
0
    }
133
0
    else if (!strcmp(argv[argi], "-l"))
134
0
      option = 4;
135
0
    else if (!strcmp(argv[argi], "-lc"))
136
0
      option = 4;
137
0
    else if (!strcmp(argv[argi], "-o")) {
138
0
      argi++;
139
0
      option = 4;
140
0
    }
141
0
    else if (!strcmp(argv[argi], "-t"))
142
0
      option = 4;
143
144
0
    else if (!strcmp(argv[argi], "-h"))
145
0
      fxPrintUsage();
146
0
    else if (!strcmp(argv[argi], "-b"))
147
0
      option = 7;
148
0
    else if (!strcmp(argv[argi], "-e"))
149
0
      option = 1;
150
0
    else if (!strcmp(argv[argi], "-f"))
151
0
      option = 5;
152
0
    else if (!strcmp(argv[argi], "-j"))
153
0
      option = 6;
154
0
    else if (!strcmp(argv[argi], "-m"))
155
0
      option = 2;
156
0
    else if (!strcmp(argv[argi], "-p"))
157
0
      profiling = 1;
158
0
    else if (!strcmp(argv[argi], "-s"))
159
0
      option = 3;
160
0
    else if (!strcmp(argv[argi], "-v"))
161
0
      printf("XS %d.%d.%d, slot %zu bytes, ID %zu bytes\n", XS_MAJOR_VERSION, XS_MINOR_VERSION, XS_PATCH_VERSION, sizeof(txSlot), sizeof(txID));
162
0
    else if (!strcmp(argv[argi], "--bundle"))
163
0
      bundle = 1;
164
0
    else {
165
0
      fxPrintUsage();
166
0
      return 1;
167
0
    }
168
0
  }
169
0
  if (bundle && (option != 5)) {
170
0
    for (argi = 1; argi < argc; argi++) {
171
0
      if (argv[argi][0] == '-') {
172
        // consume flags that take a following value
173
0
        if (!strcmp(argv[argi], "-i") || !strcmp(argv[argi], "-o"))
174
0
          argi++;
175
0
        continue;
176
0
      }
177
0
      int r = fxRunBundle(argv[argi]);
178
0
      if (r) error = r;
179
0
    }
180
0
    return error;
181
0
  }
182
0
  if (option == 0) {
183
0
    if (c_realpath(harnessPath, path))
184
0
      option  = 4;
185
0
  }
186
0
  if (option == 4) {
187
0
    error = main262(argc, argv);
188
0
  }
189
0
  else if (option == 5) {
190
0
    error = fuzz(argc, argv);
191
0
  }
192
0
  else {
193
0
    xsCreation _creation = {
194
0
      16 * 1024 * 1024,   /* initialChunkSize */
195
0
      16 * 1024 * 1024,   /* incrementalChunkSize */
196
0
      1 * 1024 * 1024,  /* initialHeapCount */
197
0
      1 * 1024 * 1024,  /* incrementalHeapCount */
198
0
      256 * 1024,     /* stackCount */
199
0
      1024,         /* initialKeyCount */
200
0
      1024,       /* incrementalKeyCount */
201
0
      1993,         /* nameModulo */
202
0
      127,        /* symbolModulo */
203
0
      64 * 1024,      /* parserBufferSize */
204
0
      1993,       /* parserTableModulo */
205
0
    };
206
0
    xsCreation* creation = &_creation;
207
0
    xsMachine* machine;
208
0
        machine = xsCreateMachine(creation, "xst", NULL);
209
0
    xsBeginMetering(machine, NULL, 0);
210
0
    {
211
0
    if (profiling)
212
0
      fxStartProfiling(machine);
213
214
0
    xsBeginHost(machine);
215
0
    {
216
0
      xsVars(2);
217
0
      xsTry {
218
0
        fxBuildAgent(machine);
219
0
        fxBuildFuzz(machine);
220
221
0
        xsVar(0) = xsUndefined;
222
0
        the->rejection = &xsVar(0);
223
0
        for (argi = 1; argi < argc; argi++) {
224
0
          if (argv[argi][0] == '-')
225
0
            continue;
226
0
          if (option == 1) {
227
0
            xsVar(1) = xsGet(xsGlobal, xsID("$262"));
228
0
            xsResult = xsString(argv[argi]);
229
0
            xsCall1(xsVar(1), xsID("evalScript"), xsResult);
230
0
          }
231
0
          else {
232
0
            if (!c_realpath(argv[argi], path))
233
0
              xsURIError("file not found: %s", argv[argi]);
234
0
            dot = strrchr(path, '.');
235
0
            if ((option == 6) || (option == 7)) {
236
0
              FILE* file = C_NULL;
237
0
              char *buffer = C_NULL;
238
0
              xsTry {
239
0
                file = fopen(path, "r");
240
0
                if (!file)
241
0
                  xsUnknownError("can't open file");
242
0
                fseek(file, 0, SEEK_END);
243
0
                size_t size = ftell(file);
244
0
                fseek(file, 0, SEEK_SET);
245
0
                buffer = c_malloc(size + 1);
246
0
                if (!buffer)
247
0
                  xsUnknownError("not enough memory");
248
0
                if (size != fread(buffer, 1, size, file)) 
249
0
                  xsUnknownError("can't read file");
250
0
                buffer[size] = 0;
251
0
                fclose(file);
252
0
                file = C_NULL;
253
0
                xsResult = xsArrayBuffer(buffer, (txInteger)size);
254
0
                c_free(buffer);
255
0
                buffer = C_NULL;
256
0
                xsVar(1) = xsNew0(xsGlobal, xsID("TextDecoder"));
257
0
                xsResult = xsCall1(xsVar(1), xsID("decode"), xsResult);
258
0
                if (option == 6) {
259
0
                  xsVar(1) = xsGet(xsGlobal, xsID("JSON"));
260
0
                  xsResult = xsCall1(xsVar(1), xsID("parse"), xsResult);
261
0
                }
262
0
                else {
263
0
                  xsResult = xsCall1(xsGlobal, xsID("eval"), xsResult);
264
0
                }
265
0
              }
266
0
              xsCatch {
267
0
                if (buffer)
268
0
                  c_free(buffer);
269
0
                if (file)
270
0
                  fclose(file);
271
0
              }
272
0
            }
273
0
            else
274
0
            if (((option == 0) && dot && !c_strcmp(dot, ".mjs")) || (option == 2))
275
0
              fxRunModuleFile(the, path);
276
0
            else
277
0
              fxRunProgramFile(the, path, mxProgramFlag | mxDebugFlag);
278
0
          }
279
0
        }
280
0
        fxRunLoop(the);
281
0
        if (xsTest(xsVar(0))) 
282
0
          xsThrow(xsVar(0));
283
0
      }
284
0
      xsCatch {
285
0
        fprintf(stderr, "%s\n", xsToString(xsException));
286
0
        error = 1;
287
0
      }
288
0
    }
289
0
    fxCheckUnhandledRejections(machine, 1);
290
0
    xsEndHost(machine);
291
0
    if (profiling)
292
0
      fxStopProfiling(machine, C_NULL);
293
0
    }
294
0
    xsEndMetering(machine);
295
0
    if (machine->exitStatus) {
296
0
      fprintf(stderr, "Error: %s\n", fxAbortString(machine->exitStatus));
297
0
      error = 1;
298
0
    }
299
0
    xsDeleteMachine(machine);
300
0
  }
301
0
  return error;
302
0
}
303
304
int fxRunBundle(const char* path)
305
0
{
306
0
  int error = 0;
307
0
  FILE* file = C_NULL;
308
0
  char* buffer = C_NULL;
309
0
  size_t size = 0;
310
0
  char resolved[C_PATH_MAX];
311
312
0
  if (!c_realpath(path, resolved)) {
313
0
    fprintf(stderr, "file not found: %s\n", path);
314
0
    return 1;
315
0
  }
316
0
  file = fopen(resolved, "r");
317
0
  if (!file) {
318
0
    fprintf(stderr, "can't open file: %s\n", resolved);
319
0
    return 1;
320
0
  }
321
0
  fseek(file, 0, SEEK_END);
322
0
  size = ftell(file);
323
0
  fseek(file, 0, SEEK_SET);
324
0
  buffer = c_malloc(size + 1);
325
0
  if (!buffer) {
326
0
    fclose(file);
327
0
    fprintf(stderr, "not enough memory\n");
328
0
    return 1;
329
0
  }
330
0
  if (size != fread(buffer, 1, size, file)) {
331
0
    fclose(file);
332
0
    c_free(buffer);
333
0
    fprintf(stderr, "can't read file: %s\n", resolved);
334
0
    return 1;
335
0
  }
336
0
  buffer[size] = 0;
337
0
  fclose(file);
338
339
0
  xsCreation _creation = {
340
0
    16 * 1024 * 1024,   /* initialChunkSize */
341
0
    16 * 1024 * 1024,   /* incrementalChunkSize */
342
0
    1 * 1024 * 1024,  /* initialHeapCount */
343
0
    1 * 1024 * 1024,  /* incrementalHeapCount */
344
0
    256 * 1024,     /* stackCount */
345
0
    1024,         /* initialKeyCount */
346
0
    1024,       /* incrementalKeyCount */
347
0
    1993,         /* nameModulo */
348
0
    127,        /* symbolModulo */
349
0
    64 * 1024,      /* parserBufferSize */
350
0
    1993,       /* parserTableModulo */
351
0
  };
352
0
  xsMachine* machine = xsCreateMachine(&_creation, "xst", NULL);
353
0
  xsBeginMetering(machine, NULL, 0);
354
0
  {
355
0
  xsBeginHost(machine);
356
0
  {
357
0
    xsVars(1);
358
0
    xsTry {
359
0
      fxBuildAgent(machine);
360
0
      fxBuildFuzz(machine);
361
0
      xsVar(0) = xsUndefined;
362
0
      the->rejection = &xsVar(0);
363
0
      fxBundleRun(the, buffer, size);
364
0
      fxRunLoop(the);
365
0
      if (xsTest(xsVar(0)))
366
0
        xsThrow(xsVar(0));
367
0
    }
368
0
    xsCatch {
369
0
      fprintf(stderr, "%s\n", xsToString(xsException));
370
0
      error = 1;
371
0
    }
372
0
  }
373
0
  fxCheckUnhandledRejections(machine, 1);
374
0
  xsEndHost(machine);
375
0
  }
376
0
  xsEndMetering(machine);
377
0
  fxBundleMapReset();
378
0
  if (machine->exitStatus) {
379
0
    fprintf(stderr, "Error: %s\n", fxAbortString(machine->exitStatus));
380
0
    error = 1;
381
0
  }
382
0
  xsDeleteMachine(machine);
383
0
  c_free(buffer);
384
0
  return error;
385
0
}
386
387
extern void modInstallTextDecoder(xsMachine *the);
388
extern void modInstallTextEncoder(xsMachine *the);
389
extern void modInstallBase64(xsMachine *the);
390
391
void fxBuildAgent(xsMachine* the) 
392
0
{
393
0
  txSlot* slot;
394
0
  txSlot* agent;
395
0
  txSlot* global;
396
397
0
  slot = fxLastProperty(the, fxNewHostObject(the, NULL));
398
0
  slot = fxNextHostFunctionProperty(the, slot, fx_agent_broadcast, 2, xsID("broadcast"), XS_DONT_ENUM_FLAG); 
399
0
  slot = fxNextHostFunctionProperty(the, slot, fx_agent_getReport, 0, xsID("getReport"), XS_DONT_ENUM_FLAG); 
400
0
  slot = fxNextHostFunctionProperty(the, slot, fx_agent_monotonicNow, 0, xsID("monotonicNow"), XS_DONT_ENUM_FLAG); 
401
0
  slot = fxNextHostFunctionProperty(the, slot, fx_agent_sleep, 1, xsID("sleep"), XS_DONT_ENUM_FLAG); 
402
0
  slot = fxNextHostFunctionProperty(the, slot, fx_agent_start, 1, xsID("start"), XS_DONT_ENUM_FLAG); 
403
0
  agent = the->stack;
404
405
0
  mxPush(mxGlobal);
406
0
  global = the->stack;
407
408
0
  mxPush(mxObjectPrototype);
409
0
  slot = fxLastProperty(the, fxNewObjectInstance(the));
410
0
  slot = fxNextSlotProperty(the, slot, agent, xsID("agent"), XS_GET_ONLY);
411
0
  slot = fxNextHostFunctionProperty(the, slot, fx_createRealm, 0, xsID("createRealm"), XS_DONT_ENUM_FLAG); 
412
0
  slot = fxNextHostFunctionProperty(the, slot, fx_detachArrayBuffer, 1, xsID("detachArrayBuffer"), XS_DONT_ENUM_FLAG); 
413
0
  slot = fxNextHostFunctionProperty(the, slot, fx_gc, 1, xsID("gc"), XS_DONT_ENUM_FLAG); 
414
0
  slot = fxNextHostFunctionProperty(the, slot, fx_evalScript, 1, xsID("evalScript"), XS_DONT_ENUM_FLAG); 
415
0
  slot = fxNextHostFunctionProperty(the, slot, fx_isLockedDown, 1, xsID("isLockedDown"), XS_DONT_ENUM_FLAG); 
416
0
  slot = fxNextHostFunctionProperty(the, slot, fx_metering, 1, xsID("metering"), XS_DONT_ENUM_FLAG); 
417
0
  slot = fxNextSlotProperty(the, slot, global, xsID("global"), XS_GET_ONLY);
418
419
0
  slot = fxLastProperty(the, fxToInstance(the, global));
420
0
  slot = fxNextSlotProperty(the, slot, the->stack, xsID("$262"), XS_DONT_ENUM_FLAG);
421
0
  slot = fxNextHostFunctionProperty(the, slot, fx_print, 1, xsID("print"), XS_DONT_ENUM_FLAG);
422
0
  slot = fxNextHostFunctionProperty(the, slot, fx_runScript, 1, xsID("runScript"), XS_DONT_ENUM_FLAG);
423
0
  slot = fxNextHostFunctionProperty(the, slot, fx_clearTimer, 1, xsID("clearInterval"), XS_DONT_ENUM_FLAG);
424
0
  slot = fxNextHostFunctionProperty(the, slot, fx_clearTimer, 1, xsID("clearTimeout"), XS_DONT_ENUM_FLAG);
425
0
  slot = fxNextHostFunctionProperty(the, slot, fx_setInterval, 1, xsID("setInterval"), XS_DONT_ENUM_FLAG);
426
0
  slot = fxNextHostFunctionProperty(the, slot, fx_setTimeout, 1, xsID("setTimeout"), XS_DONT_ENUM_FLAG);
427
  
428
0
  slot = fxNextHostFunctionProperty(the, slot, fx_harden, 1, xsID("harden"), XS_DONT_ENUM_FLAG);
429
0
  slot = fxNextHostFunctionProperty(the, slot, fx_lockdown, 0, xsID("lockdown"), XS_DONT_ENUM_FLAG);
430
  
431
0
  slot = fxNextHostFunctionProperty(the, slot, fx_unicodeCompare, 2, xsID("unicodeCompare"), XS_DONT_ENUM_FLAG);
432
433
0
  mxPop();
434
0
  mxPop();
435
  
436
0
  modInstallTextDecoder(the);
437
0
  modInstallTextEncoder(the);
438
0
  modInstallBase64(the);
439
0
}
440
441
void fxPrintUsage()
442
0
{
443
0
  printf("xst [-h] [-e] [-f] [-j] [-m] [-p] [-s] [-t] [-v] strings...\n");
444
0
  printf("\t-b: strings are paths to script buffers\n");
445
0
  printf("\t-e: eval strings\n");
446
0
  printf("\t-f: fuzz with REPRL harness\n");
447
0
  printf("\t-h: print this help message\n");
448
0
  printf("\t-j: strings are paths to JSON buffers\n");
449
0
  printf("\t-m: strings are paths to modules\n");
450
0
  printf("\t-p: profile\n");
451
0
  printf("\t-s: strings are paths to scripts\n");
452
0
  printf("\t-t: strings are paths to test262 cases or directories\n");
453
0
  printf("\t-v: print XS version\n");
454
0
  printf("without -b, -e, -f, -j, -m, -s, or -t:\n");
455
0
  printf("\tif ../harness exists, strings are paths to test262 cases or directories\n");
456
0
  printf("\telse if the extension is .mjs, strings are paths to modules\n");
457
0
  printf("\telse strings are paths to scripts\n");
458
0
}
459
460
void fx_evalScript(xsMachine* the)
461
0
{
462
0
  txSlot* realm;
463
0
  txSlot* module = mxFunctionInstanceHome(mxFunction->value.reference)->value.home.module;
464
0
  if (!module) module = mxProgram.value.reference;
465
0
  realm = mxModuleInstanceInternal(module)->value.module.realm;
466
0
  txStringStream aStream;
467
0
  aStream.slot = mxArgv(0);
468
0
  aStream.offset = 0;
469
0
  aStream.size = mxStringLength(fxToString(the, mxArgv(0)));
470
0
  fxRunScript(the, fxParseScript(the, &aStream, fxStringGetter, mxProgramFlag | mxDebugFlag), mxRealmGlobal(realm), C_NULL, mxRealmClosures(realm)->value.reference, C_NULL, module);
471
0
  mxPullSlot(mxResult);
472
0
}
473
474
void fx_gc(xsMachine* the)
475
0
{
476
0
  xsCollectGarbage();
477
0
}
478
479
void fx_isLockedDown(xsMachine* the)
480
0
{
481
0
  xsResult = (mxProgram.value.reference->flag & XS_DONT_MARSHALL_FLAG) ? xsTrue : xsFalse;
482
0
}
483
484
void fx_metering(xsMachine* the)
485
0
{
486
0
#ifdef mxMetering
487
0
  xsResult = xsNumber(the->meterIndex);
488
0
#endif  
489
0
}
490
491
void fx_print(xsMachine* the)
492
0
{
493
0
  xsIntegerValue c = xsToInteger(xsArgc), i;
494
0
  xsStringValue string, p, q;
495
0
  xsVars(1);
496
0
  xsVar(0) = xsGet(xsGlobal, xsID("String"));
497
0
  for (i = 0; i < c; i++) {
498
0
    if (i)
499
0
      fprintf(stdout, " ");
500
0
    xsArg(i) = xsCallFunction1(xsVar(0), xsUndefined, xsArg(i));
501
0
    p = string = xsToString(xsArg(i));
502
0
  #if mxCESU8
503
0
    for (;;) {
504
0
      xsIntegerValue character;
505
0
      q = fxUTF8Decode(p, &character);
506
0
    again:
507
0
      if (character == C_EOF)
508
0
        break;
509
0
      if (character == 0) {
510
0
        if (p > string) {
511
0
          char c = *p;
512
0
          *p = 0;
513
0
          fprintf(stdout, "%s", string);
514
0
          *p = c;
515
0
        }
516
0
        string = q;
517
0
      }
518
0
      else if ((0x0000D800 <= character) && (character <= 0x0000DBFF)) {
519
0
        xsStringValue r = q;
520
0
        xsIntegerValue surrogate;
521
0
        q = fxUTF8Decode(r, &surrogate);
522
0
        if ((0x0000DC00 <= surrogate) && (surrogate <= 0x0000DFFF)) {
523
0
          char buffer[5];
524
0
          character = (txInteger)(0x00010000 + ((character & 0x03FF) << 10) + (surrogate & 0x03FF));
525
0
          if (p > string) {
526
0
            char c = *p;
527
0
            *p = 0;
528
0
            fprintf(stdout, "%s", string);
529
0
            *p = c;
530
0
          }
531
0
          p = fxUTF8Encode(buffer, character);
532
0
          *p = 0;
533
0
          fprintf(stdout, "%s", buffer);
534
0
          string = q;
535
0
        }
536
0
        else {
537
0
          p = r;
538
0
          character = surrogate;
539
0
          goto again;
540
0
        }
541
0
      }
542
0
      p = q;
543
0
    }
544
0
  #endif  
545
0
    fprintf(stdout, "%s", string);
546
0
  }
547
0
  fprintf(stdout, "\n");
548
0
}
549
550
void fx_runScript(xsMachine* the)
551
0
{
552
0
  txSlot* realm = mxProgram.value.reference->next->value.module.realm;
553
0
  char path[C_PATH_MAX];
554
0
  txUnsigned flags = mxProgramFlag | mxDebugFlag;
555
0
  if (!c_realpath(fxToString(the, mxArgv(0)), path))
556
0
    xsURIError("file not found");
557
0
  txScript* script = fxLoadScript(the, path, flags);
558
0
  mxModuleInstanceInternal(mxProgram.value.reference)->value.module.id = fxID(the, path);
559
0
  fxRunScript(the, script, mxRealmGlobal(realm), C_NULL, mxRealmClosures(realm)->value.reference, C_NULL, mxProgram.value.reference);
560
0
  mxPullSlot(mxResult);
561
0
}
562
563
/* $262 */
564
565
void fx_agent_broadcast(xsMachine* the)
566
0
{
567
0
  txAgentCluster* agentCluster = &gxAgentCluster;
568
0
  if (xsIsInstanceOf(xsArg(0), xsTypedArrayPrototype)) {
569
0
    xsArg(0) = xsGet(xsArg(0), xsID("buffer"));
570
0
  }
571
0
    fxLockMutex(&(agentCluster->dataMutex));
572
0
  agentCluster->dataBuffer = xsMarshallAlien(xsArg(0));
573
0
  if (mxArgc > 1)
574
0
    agentCluster->dataValue = xsToInteger(xsArg(1));
575
0
  fxWakeAllCondition(&(agentCluster->dataCondition));
576
0
    fxUnlockMutex(&(agentCluster->dataMutex));
577
    
578
0
    fxLockMutex(&(agentCluster->countMutex));
579
0
    while (agentCluster->count > 0)
580
0
    fxSleepCondition(&(agentCluster->countCondition), &(agentCluster->countMutex));
581
0
    fxUnlockMutex(&(agentCluster->countMutex));
582
0
}
583
584
void fx_agent_getReport(xsMachine* the)
585
0
{
586
0
  txAgentCluster* agentCluster = &gxAgentCluster;
587
0
  txAgentReport* report = C_NULL;
588
0
    fxLockMutex(&(agentCluster->reportMutex));
589
0
  report = agentCluster->firstReport;
590
0
  if (report)
591
0
    agentCluster->firstReport = report->next;
592
0
    fxUnlockMutex(&(agentCluster->reportMutex));
593
0
    if (report) {
594
0
      xsResult = xsString(report->message);
595
0
      c_free(report);
596
0
    }
597
0
    else
598
0
      xsResult = xsNull;
599
0
}
600
601
void fx_agent_leaving(xsMachine* the)
602
0
{
603
0
}
604
605
void fx_agent_monotonicNow(xsMachine* the)
606
0
{
607
0
  xsResult = xsNumber(mxMonotonicNow());
608
0
}
609
610
void fx_agent_receiveBroadcast(xsMachine* the)
611
0
{
612
0
  txAgentCluster* agentCluster = &gxAgentCluster;
613
0
   fxLockMutex(&(agentCluster->dataMutex));
614
0
  while (agentCluster->dataBuffer == NULL)
615
0
    fxSleepCondition(&(agentCluster->dataCondition), &(agentCluster->dataMutex));
616
0
  xsResult = xsDemarshallAlien(agentCluster->dataBuffer);
617
0
    fxUnlockMutex(&(agentCluster->dataMutex));
618
  
619
0
    fxLockMutex(&(agentCluster->countMutex));
620
0
    agentCluster->count--;
621
0
    fxWakeCondition(&(agentCluster->countCondition));
622
0
    fxUnlockMutex(&(agentCluster->countMutex));
623
    
624
0
  xsCallFunction2(xsArg(0), xsGlobal, xsResult, xsInteger(agentCluster->dataValue));
625
0
}
626
627
void fx_agent_report(xsMachine* the)
628
0
{
629
0
  txAgentCluster* agentCluster = &gxAgentCluster;
630
0
  xsStringValue message = xsToString(xsArg(0));
631
0
  xsIntegerValue messageLength = mxStringLength(message);
632
0
  txAgentReport* report = c_malloc(sizeof(txAgentReport) + messageLength);
633
0
  if (!report) xsUnknownError("not enough memory");
634
0
    report->next = C_NULL;
635
0
  c_memcpy(&(report->message[0]), message, messageLength + 1);
636
0
    fxLockMutex(&(agentCluster->reportMutex));
637
0
    if (agentCluster->firstReport)
638
0
    agentCluster->lastReport->next = report;
639
0
    else
640
0
    agentCluster->firstReport = report;
641
0
  agentCluster->lastReport = report;
642
0
    fxUnlockMutex(&(agentCluster->reportMutex));
643
0
}
644
645
void fx_agent_sleep(xsMachine* the)
646
0
{
647
0
  xsIntegerValue delay = xsToInteger(xsArg(0));
648
#if mxWindows
649
  Sleep(delay);
650
#else 
651
0
  usleep(delay * 1000);
652
0
#endif
653
0
}
654
655
void fx_agent_start(xsMachine* the)
656
0
{
657
0
  xsStringValue script = xsToString(xsArg(0));
658
0
  xsIntegerValue scriptLength = mxStringLength(script);
659
0
  txAgentCluster* agentCluster = &gxAgentCluster;
660
0
  txAgent* agent = c_malloc(sizeof(txAgent) + scriptLength);
661
0
  if (!agent) xsUnknownError("not enough memory");
662
0
  c_memset(agent, 0, sizeof(txAgent));
663
0
  if (agentCluster->firstAgent)
664
0
    agentCluster->lastAgent->next = agent;
665
0
  else
666
0
    agentCluster->firstAgent = agent;
667
0
  agentCluster->lastAgent = agent;
668
0
  agentCluster->count++;
669
0
  agent->scriptLength = scriptLength;
670
0
  c_memcpy(&(agent->script[0]), script, scriptLength + 1);
671
#if mxWindows
672
  agent->thread = (HANDLE)_beginthreadex(NULL, 0, fx_agent_start_aux, agent, 0, NULL);
673
#elif mxMacOSX
674
  pthread_attr_t attr; 
675
  pthread_t self = pthread_self();
676
  size_t size = pthread_get_stacksize_np(self);
677
  pthread_attr_init(&attr);
678
  pthread_attr_setstacksize(&attr, size);
679
    pthread_create(&(agent->thread), &attr, &fx_agent_start_aux, agent);
680
#else 
681
0
    pthread_create(&(agent->thread), NULL, &fx_agent_start_aux, agent);
682
0
#endif
683
0
}
684
685
#if mxWindows
686
unsigned int __stdcall fx_agent_start_aux(void* it)
687
#else
688
void* fx_agent_start_aux(void* it)
689
#endif
690
0
{
691
0
  xsCreation creation = {
692
0
    16 * 1024 * 1024,   /* initialChunkSize */
693
0
    16 * 1024 * 1024,   /* incrementalChunkSize */
694
0
    1 * 1024 * 1024,  /* initialHeapCount */
695
0
    1 * 1024 * 1024,  /* incrementalHeapCount */
696
0
    4096,         /* stackCount */
697
0
    1024,         /* initialKeyCount */
698
0
    1024,       /* incrementalKeyCount */
699
0
    1993,         /* nameModulo */
700
0
    127,        /* symbolModulo */
701
0
    64 * 1024,      /* parserBufferSize */
702
0
    1993,       /* parserTableModulo */
703
0
  };
704
0
  txAgent* agent = it;
705
0
  xsMachine* machine = xsCreateMachine(&creation, "xst-agent", NULL);
706
0
  xsBeginHost(machine);
707
0
  {
708
0
    xsTry {
709
0
      txSlot* slot;
710
0
      txSlot* global;
711
0
      txStringCStream stream;
712
      
713
0
      mxPush(mxGlobal);
714
0
      global = the->stack;
715
      
716
0
      slot = fxLastProperty(the, fxNewHostObject(the, NULL));
717
0
      slot = fxNextHostFunctionProperty(the, slot, fx_agent_leaving, 0, xsID("leaving"), XS_DONT_ENUM_FLAG); 
718
0
      slot = fxNextHostFunctionProperty(the, slot, fx_agent_monotonicNow, 0, xsID("monotonicNow"), XS_DONT_ENUM_FLAG); 
719
0
      slot = fxNextHostFunctionProperty(the, slot, fx_agent_receiveBroadcast, 1, xsID("receiveBroadcast"), XS_DONT_ENUM_FLAG); 
720
0
      slot = fxNextHostFunctionProperty(the, slot, fx_agent_report, 1, xsID("report"), XS_DONT_ENUM_FLAG); 
721
0
      slot = fxNextHostFunctionProperty(the, slot, fx_agent_sleep, 1, xsID("sleep"), XS_DONT_ENUM_FLAG); 
722
0
      fxSetHostData(the, the->stack, agent);
723
      
724
0
      mxPush(mxObjectPrototype);
725
0
      slot = fxLastProperty(the, fxNewObjectInstance(the));
726
0
      slot = fxNextSlotProperty(the, slot, the->stack + 1, xsID("agent"), XS_GET_ONLY);
727
      
728
0
      slot = fxLastProperty(the, fxToInstance(the, global));
729
0
      slot = fxNextSlotProperty(the, slot, the->stack, xsID("$262"), XS_GET_ONLY);
730
      
731
0
      mxPop();
732
0
      mxPop();
733
0
      mxPop();
734
      
735
0
      stream.buffer = agent->script;
736
0
      stream.offset = 0;
737
0
      stream.size = agent->scriptLength;
738
0
      fxRunScript(the, fxParseScript(the, &stream, fxStringCGetter, mxProgramFlag), mxThis, C_NULL, C_NULL, C_NULL, mxProgram.value.reference);
739
0
      fxRunLoop(the);
740
0
    }
741
0
    xsCatch {
742
0
    }
743
0
  }
744
0
  xsEndHost(the);
745
0
  xsDeleteMachine(machine);
746
#if mxWindows
747
  return 0;
748
#else
749
0
  return NULL;
750
0
#endif
751
0
}
752
753
void fx_createRealm(xsMachine* the)
754
0
{
755
0
  xsResult = xsThis;
756
0
}
757
758
void fx_detachArrayBuffer(xsMachine* the)
759
0
{
760
0
  txSlot* slot = mxArgv(0);
761
0
  if (slot->kind == XS_REFERENCE_KIND) {
762
0
    txSlot* instance = slot->value.reference;
763
0
    if (((slot = instance->next)) && (slot->flag & XS_INTERNAL_FLAG) && (slot->kind == XS_ARRAY_BUFFER_KIND) && (instance != mxArrayBufferPrototype.value.reference)) {
764
0
      slot->value.arrayBuffer.address = C_NULL;
765
0
      slot->next->value.bufferInfo.length = 0;
766
0
      return;
767
0
    }
768
0
  }
769
0
  mxTypeError("this is no ArrayBuffer instance");
770
0
}
771
772
/* TIMER */
773
774
static txHostHooks gxTimerHooks = {
775
  fx_destroyTimer,
776
  fx_markTimer
777
};
778
779
void fx_callbackTimer(txSharedTimer* timer, void* refcon, txInteger refconSize)
780
0
{
781
0
  txJob* job = (txJob*)refcon;
782
0
  txMachine* the = job->the;
783
0
  if (the) {
784
0
    fxBeginHost(the);
785
0
    mxTry(the) {
786
0
      mxPushUndefined();
787
0
      mxPush(job->function);
788
0
      mxCall();
789
0
      mxPush(job->argument);
790
0
      mxRunCount(1);
791
0
      mxPop();
792
0
    }
793
0
    mxCatch(the) {
794
0
      *((txSlot*)the->rejection) = mxException;
795
0
      timer->interval = 0;
796
0
    }
797
0
    if (job->the) {
798
0
      if (timer->interval == 0) {
799
0
        fxAccess(the, &job->self);
800
0
        *mxResult = the->scratch;
801
0
        fxForget(the, &job->self);
802
0
        fxSetHostData(the, mxResult, NULL);
803
0
        job->the = NULL;
804
0
      }
805
0
    }
806
0
    else
807
0
      timer->interval = 0;
808
0
    fxEndHost(the);
809
0
  }
810
0
  else
811
0
    timer->interval = 0;
812
0
}
813
814
void fx_clearTimer(txMachine* the)
815
0
{
816
0
  if ((0 == mxArgc) || (XS_REFERENCE_KIND != mxArgv(0)->kind) || (C_NULL == fxGetHostDataIf(the, mxArgv(0))))
817
0
    return;
818
0
  txHostHooks* hooks = fxGetHostHooks(the, mxArgv(0));
819
0
  if (hooks == &gxTimerHooks) {
820
0
    txJob* job = fxGetHostData(the, mxArgv(0));
821
0
    if (job) {
822
0
      fxForget(the, &job->self);
823
0
      fxSetHostData(the, mxArgv(0), NULL);
824
0
      job->the = NULL;
825
0
      txSharedTimer* timer = (txSharedTimer*)(((txByte*)job) - offsetof(txSharedTimer, refcon));
826
0
      fxRescheduleSharedTimer(timer, 0, 0);
827
0
    }
828
0
  }
829
0
}
830
831
void fx_destroyTimer(void* data)
832
0
{
833
0
}
834
835
void fx_markTimer(txMachine* the, void* it, txMarkRoot markRoot)
836
0
{
837
0
  txJob* job = it;
838
0
  if (job) {
839
0
    (*markRoot)(the, &job->function);
840
0
    (*markRoot)(the, &job->argument);
841
0
  }
842
0
}
843
844
void fx_setInterval(txMachine* the)
845
0
{
846
0
  fx_setTimer(the, fxToNumber(the, mxArgv(1)), 1);
847
0
}
848
849
void fx_setTimeout(txMachine* the)
850
0
{
851
0
  fx_setTimer(the, fxToNumber(the, mxArgv(1)), 0);
852
0
}
853
854
void fx_setTimer(txMachine* the, txNumber interval, txBoolean repeat)
855
0
{
856
0
  txJob _job;
857
0
  txJob* job;
858
0
  txSharedTimer* timer;
859
0
  if (c_isnan(interval) || (interval < 0))
860
0
    interval = 0;
861
0
  c_memset(&_job, 0, sizeof(txJob));
862
0
  timer = fxScheduleSharedTimer(interval, (repeat) ? interval : 0, fx_callbackTimer, &_job, sizeof(txJob));  
863
0
  if (!timer)
864
0
    fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT);
865
0
  job = (txJob*)&(timer->refcon[0]);
866
0
  job->the = the;
867
0
  fxNewHostObject(the, NULL);
868
0
    mxPull(job->self);
869
0
  job->function = *mxArgv(0);
870
0
  if (mxArgc > 2)
871
0
    job->argument = *mxArgv(2);
872
0
  else
873
0
    job->argument = mxUndefined;
874
0
  fxSetHostData(the, &job->self, job);
875
0
  fxSetHostHooks(the, &job->self, &gxTimerHooks);
876
0
  fxRemember(the, &job->self);
877
0
  fxAccess(the, &job->self);
878
0
  *mxResult = the->scratch;
879
0
}
880
881
/* PLATFORM */
882
883
void fxCreateMachinePlatform(txMachine* the)
884
6.37k
{
885
6.37k
#ifdef mxDebug
886
6.37k
  the->connection = mxNoSocket;
887
6.37k
#endif
888
6.37k
}
889
890
void fxDeleteMachinePlatform(txMachine* the)
891
6.37k
{
892
6.37k
}
893
894
void fxQueuePromiseJobs(txMachine* the)
895
0
{
896
0
  the->promiseJobs = 1;
897
0
}
898
899
/* SHARED TIMERS */
900
901
typedef struct sxSharedTimers txSharedTimers;
902
struct sxSharedTimers {
903
  txSharedTimer* first;
904
  txMutex mutex;
905
};
906
static txSharedTimers gxSharedTimers;
907
908
void fxInitializeSharedTimers()
909
6.37k
{
910
6.37k
  c_memset(&gxSharedTimers, 0, sizeof(txSharedTimers));
911
6.37k
  fxCreateMutex(&(gxSharedTimers.mutex));
912
6.37k
}
913
914
void fxTerminateSharedTimers()
915
6.37k
{
916
6.37k
  fxDeleteMutex(&(gxSharedTimers.mutex));
917
6.37k
  if (gxSharedTimers.first != C_NULL) {
918
0
    fprintf(stderr, "# shared timers mismatch!\n");
919
0
    exit(1);
920
0
  }
921
6.37k
}
922
923
void fxRescheduleSharedTimer(txSharedTimer* timer, txNumber timeout, txNumber interval)
924
0
{
925
0
    fxLockMutex(&(gxSharedTimers.mutex));
926
0
  timer->when = mxMonotonicNow() + timeout;
927
0
  timer->interval = interval;
928
0
    fxUnlockMutex(&(gxSharedTimers.mutex));
929
0
}
930
931
void* fxScheduleSharedTimer(txNumber timeout, txNumber interval, txSharedTimerCallback callback, void* refcon, txInteger refconSize)
932
0
{
933
0
  txSharedTimer* timer;
934
0
  txSharedTimer** address;
935
0
  txSharedTimer* link;
936
0
  timer = c_calloc(1, sizeof(txSharedTimer) + refconSize - 1);
937
0
  if (timer) {
938
0
    timer->thread = mxCurrentThread();
939
0
    timer->when = mxMonotonicNow() + timeout;
940
0
    timer->interval = interval;
941
0
    timer->callback = callback;
942
0
    timer->refconSize = refconSize;
943
0
    c_memcpy(timer->refcon, refcon, refconSize);
944
    
945
0
    fxLockMutex(&(gxSharedTimers.mutex));
946
0
    address = (txSharedTimer**)&(gxSharedTimers.first);
947
0
    while ((link = *address))
948
0
      address = &(link->next);
949
0
    *address = timer;
950
0
    fxUnlockMutex(&(gxSharedTimers.mutex));
951
0
    }
952
0
    return timer;
953
0
}
954
955
void fxUnscheduleSharedTimer(txSharedTimer* timer)
956
0
{
957
0
  txSharedTimer** address;
958
0
  txSharedTimer* link;
959
0
    fxLockMutex(&(gxSharedTimers.mutex));
960
0
    address = (txSharedTimer**)&(gxSharedTimers.first);
961
0
  while ((link = *address)) {
962
0
    if (link == timer) {
963
0
      *address = link->next;
964
0
      c_free(timer);
965
0
      break;
966
0
    }
967
0
    address = &(link->next);
968
0
  }
969
0
    fxUnlockMutex(&(gxSharedTimers.mutex));
970
0
}
971
972
void fxRunLoop(txMachine* the)
973
0
{
974
0
  txThread thread = mxCurrentThread();
975
0
  txNumber when;
976
0
  txInteger count;
977
0
  txSharedTimer* timer;
978
  
979
0
  for (;;) {
980
0
    fxEndJob(the);
981
0
    while (the->promiseJobs) {
982
0
      while (the->promiseJobs) {
983
0
        the->promiseJobs = 0;
984
0
        fxRunPromiseJobs(the);
985
0
      }
986
0
      fxEndJob(the);
987
0
    }
988
0
    when = mxMonotonicNow();
989
0
    fxLockMutex(&(gxSharedTimers.mutex));
990
0
    count = 0;
991
0
    timer = gxSharedTimers.first;
992
0
    while (timer) {
993
0
      if (timer->thread == thread) {
994
0
        count++;
995
0
        if (timer->when <= when)
996
0
          break; // one timer at time to run promise jobs queued by the timer in the same "tick"
997
0
      }
998
0
      timer = timer->next;
999
0
    }
1000
0
    fxUnlockMutex(&(gxSharedTimers.mutex));
1001
0
    if (timer) {
1002
0
      (timer->callback)(timer, timer->refcon, timer->refconSize);
1003
0
      if (timer->interval == 0)
1004
0
        fxUnscheduleSharedTimer(timer);
1005
0
      else
1006
0
        timer->when += timer->interval;
1007
0
      continue;
1008
0
    }
1009
0
    if (count == 0)
1010
0
      break;
1011
0
  }
1012
0
}
1013
1014
void fxFulfillModuleFile(txMachine* the)
1015
0
{
1016
0
}
1017
1018
void fxRejectModuleFile(txMachine* the)
1019
0
{
1020
0
  *((txSlot*)the->rejection) = xsArg(0);
1021
0
}
1022
1023
void fxRunModuleFile(txMachine* the, txString path)
1024
0
{
1025
0
  txSlot* realm = mxProgram.value.reference->next->value.module.realm;
1026
0
  mxPushStringC(path);
1027
0
  mxPushUndefined();
1028
0
  fxRunImport(the, realm, C_NULL);
1029
0
  mxDub();
1030
0
  fxGetID(the, mxID(_then));
1031
0
  mxCall();
1032
0
  fxNewHostFunction(the, fxFulfillModuleFile, 1, XS_NO_ID, XS_NO_ID);
1033
0
  fxNewHostFunction(the, fxRejectModuleFile, 1, XS_NO_ID, XS_NO_ID);
1034
0
  mxRunCount(2);
1035
0
  mxPop();
1036
0
}
1037
1038
void fxRunProgramFile(txMachine* the, txString path, txUnsigned flags)
1039
0
{
1040
0
  txSlot* realm = mxProgram.value.reference->next->value.module.realm;
1041
0
  txScript* script = fxLoadScript(the, path, flags);
1042
0
  mxModuleInstanceInternal(mxProgram.value.reference)->value.module.id = fxID(the, path);
1043
0
  fxRunScript(the, script, mxRealmGlobal(realm), C_NULL, mxRealmClosures(realm)->value.reference, C_NULL, mxProgram.value.reference);
1044
0
  mxPullSlot(mxResult);
1045
0
}
1046
1047
void fxAbort(txMachine* the, int status)
1048
0
{
1049
0
  if (XS_DEBUGGER_EXIT == status)
1050
0
    c_exit(1);
1051
0
  if (the->exitStatus) // xsEndHost calls fxAbort!
1052
0
    return;
1053
0
  the->exitStatus = status;
1054
0
  fxExitToHost(the);
1055
0
}
1056
1057
txID fxFindModule(txMachine* the, txSlot* realm, txID moduleID, txSlot* slot)
1058
0
{
1059
0
  char name[C_PATH_MAX];
1060
0
  char path[C_PATH_MAX];
1061
0
  txInteger dot = 0;
1062
0
  txString slash;
1063
0
  fxToStringBuffer(the, slot, name, sizeof(name));
1064
0
  if (name[0] == '.') {
1065
0
    if (name[1] == '/') {
1066
0
      dot = 1;
1067
0
    }
1068
0
    else if ((name[1] == '.') && (name[2] == '/')) {
1069
0
      dot = 2;
1070
0
    }
1071
0
  }
1072
0
  if (dot) {
1073
0
    if (moduleID == XS_NO_ID)
1074
0
      return XS_NO_ID;
1075
0
    c_strncpy(path, fxGetKeyName(the, moduleID), C_PATH_MAX - 1);
1076
0
    path[C_PATH_MAX - 1] = 0;
1077
0
    slash = c_strrchr(path, mxSeparator);
1078
0
    if (!slash)
1079
0
      return XS_NO_ID;
1080
0
    if (dot == 2) {
1081
0
      *slash = 0;
1082
0
      slash = c_strrchr(path, mxSeparator);
1083
0
      if (!slash)
1084
0
        return XS_NO_ID;
1085
0
    }
1086
#if mxWindows
1087
    {
1088
      char c;
1089
      char* s = name;
1090
      while ((c = *s)) {
1091
        if (c == '/')
1092
          *s = '\\';
1093
        s++;
1094
      }
1095
    }
1096
#endif
1097
0
  }
1098
0
  else
1099
0
    slash = path;
1100
0
  *slash = 0;
1101
0
  if ((c_strlen(path) + c_strlen(name + dot)) >= sizeof(path))
1102
0
    xsRangeError("path too long");
1103
0
  c_strcat(path, name + dot);
1104
0
  return fxNewNameC(the, path);
1105
0
}
1106
1107
void fxLoadModule(txMachine* the, txSlot* module, txID moduleID)
1108
0
{
1109
0
  char path[C_PATH_MAX];
1110
0
  char real[C_PATH_MAX];
1111
0
  txString dot;
1112
0
  txScript* script;
1113
0
#ifdef mxDebug
1114
0
  txUnsigned flags = mxDebugFlag;
1115
#else
1116
  txUnsigned flags = 0;
1117
#endif
1118
0
  if (fxBundleLoad(the, module, moduleID))
1119
0
    return;
1120
0
  c_strncpy(path, fxGetKeyName(the, moduleID), C_PATH_MAX - 1);
1121
0
  path[C_PATH_MAX - 1] = 0;
1122
0
  if (c_realpath(path, real)) {
1123
#if mxWindows
1124
    DWORD attributes;
1125
    attributes = GetFileAttributes(path);
1126
    if (attributes != 0xFFFFFFFF) {
1127
      if (attributes & FILE_ATTRIBUTE_DIRECTORY)
1128
        return;
1129
    }
1130
#else
1131
0
    struct stat a_stat;
1132
0
    if (stat(path, &a_stat) == 0) {
1133
0
      if (S_ISDIR(a_stat.st_mode)) 
1134
0
        return;
1135
0
    }
1136
0
#endif  
1137
0
    dot = c_strrchr(real, '.');
1138
0
    if (dot && !c_strcmp(dot, ".json"))
1139
0
      flags |= mxJSONModuleFlag;
1140
0
    script = fxLoadScript(the, real, flags);
1141
0
    if (script)
1142
0
      fxResolveModule(the, module, moduleID, script, C_NULL, C_NULL);
1143
0
  }
1144
0
}
1145
1146
txScript* fxLoadScript(txMachine* the, txString path, txUnsigned flags)
1147
0
{
1148
0
  txParser _parser;
1149
0
  txParser* parser = &_parser;
1150
0
  txParserJump jump;
1151
0
  FILE* file = NULL;
1152
0
  txString name = NULL;
1153
0
  char map[C_PATH_MAX];
1154
0
  txScript* script = NULL;
1155
0
  fxInitializeParser(parser, the, the->parserBufferSize, the->parserTableModulo);
1156
0
  parser->firstJump = &jump;
1157
0
  file = fopen(path, "r");
1158
0
  if (c_setjmp(jump.jmp_buf) == 0) {
1159
0
    mxParserThrowElse(file);
1160
0
    parser->path = fxNewParserSymbol(parser, path);
1161
0
    fxParserTree(parser, file, (txGetter)fgetc, flags, &name);
1162
0
    fclose(file);
1163
0
    file = NULL;
1164
0
    if (name) {
1165
0
      mxParserThrowElse(c_realpath(fxCombinePath(parser, path, name), map));
1166
0
      parser->path = fxNewParserSymbol(parser, map);
1167
0
      file = fopen(map, "r");
1168
0
      mxParserThrowElse(file);
1169
0
      fxParserSourceMap(parser, file, (txGetter)fgetc, flags, &name);
1170
0
      fclose(file);
1171
0
      file = NULL;
1172
0
      if ((parser->errorCount == 0) && name) {
1173
0
        mxParserThrowElse(c_realpath(fxCombinePath(parser, map, name), map));
1174
0
        parser->path = fxNewParserSymbol(parser, map);
1175
0
      }
1176
0
    }
1177
0
    fxParserHoist(parser);
1178
0
    fxParserBind(parser);
1179
0
    script = fxParserCode(parser);
1180
0
  }
1181
0
  if (file)
1182
0
    fclose(file);
1183
#ifdef mxInstrument
1184
  if (the->peakParserSize < parser->total)
1185
    the->peakParserSize = parser->total;
1186
#endif
1187
0
  fxTerminateParser(parser);
1188
0
  return script;
1189
0
}
1190
1191
/* DEBUG */
1192
1193
#ifdef mxDebug
1194
1195
void fxConnect(txMachine* the)
1196
6.37k
{
1197
6.37k
  if (!c_strcmp(the->name, "xst_fuzz"))
1198
0
    return;
1199
6.37k
  if (!c_strcmp(the->name, "xst_fuzz_oss"))
1200
6.37k
    return;
1201
#ifdef mxMultipleThreads
1202
  if (!c_strcmp(the->name, "xst262"))
1203
    return;
1204
  if (!c_strcmp(the->name, "xst-agent"))
1205
    return;
1206
#endif    
1207
0
  char name[256];
1208
0
  char* colon;
1209
0
  int port;
1210
#if mxWindows
1211
  if (GetEnvironmentVariable("XSBUG_HOST", name, sizeof(name))) {
1212
#else
1213
0
  colon = getenv("XSBUG_HOST");
1214
0
  if ((colon) && (c_strlen(colon) + 1 < sizeof(name))) {
1215
0
    c_strcpy(name, colon);
1216
0
#endif    
1217
0
    colon = strchr(name, ':');
1218
0
    if (colon == NULL)
1219
0
      port = 5002;
1220
0
    else {
1221
0
      *colon = 0;
1222
0
      colon++;
1223
0
      port = strtol(colon, NULL, 10);
1224
0
    }
1225
0
  }
1226
0
  else {
1227
0
    strcpy(name, "localhost");
1228
0
    port = 5002;
1229
0
  }
1230
#if mxWindows
1231
{   
1232
  WSADATA wsaData;
1233
  struct hostent *host;
1234
  struct sockaddr_in address;
1235
  unsigned long flag;
1236
  if (WSAStartup(0x202, &wsaData) == SOCKET_ERROR)
1237
    return;
1238
  host = gethostbyname(name);
1239
  if (!host)
1240
    goto bail;
1241
  memset(&address, 0, sizeof(address));
1242
  address.sin_family = AF_INET;
1243
  memcpy(&(address.sin_addr), host->h_addr, host->h_length);
1244
    address.sin_port = htons(port);
1245
  the->connection = socket(AF_INET, SOCK_STREAM, 0);
1246
  if (the->connection == INVALID_SOCKET)
1247
    return;
1248
    flag = 1;
1249
    ioctlsocket(the->connection, FIONBIO, &flag);
1250
  if (connect(the->connection, (struct sockaddr*)&address, sizeof(address)) == SOCKET_ERROR) {
1251
    if (WSAEWOULDBLOCK == WSAGetLastError()) {
1252
      fd_set fds;
1253
      struct timeval timeout = { 2, 0 }; // 2 seconds, 0 micro-seconds
1254
      FD_ZERO(&fds);
1255
      FD_SET(the->connection, &fds);
1256
      if (select(0, NULL, &fds, NULL, &timeout) == 0)
1257
        goto bail;
1258
      if (!FD_ISSET(the->connection, &fds))
1259
        goto bail;
1260
    }
1261
    else
1262
      goto bail;
1263
  }
1264
  flag = 0;
1265
  ioctlsocket(the->connection, FIONBIO, &flag);
1266
}
1267
#else
1268
0
{   
1269
0
  struct sockaddr_in address;
1270
0
  int flag;
1271
0
  memset(&address, 0, sizeof(address));
1272
0
    address.sin_family = AF_INET;
1273
0
  address.sin_addr.s_addr = inet_addr(name);
1274
0
  if (address.sin_addr.s_addr == INADDR_NONE) {
1275
0
    struct hostent *host = gethostbyname(name);
1276
0
    if (!host)
1277
0
      return;
1278
0
    memcpy(&(address.sin_addr), host->h_addr, host->h_length);
1279
0
  }
1280
0
    address.sin_port = htons(port);
1281
0
  the->connection = socket(AF_INET, SOCK_STREAM, 0);
1282
0
  if (the->connection <= 0)
1283
0
    goto bail;
1284
0
  c_signal(SIGPIPE, SIG_IGN);
1285
#if mxMacOSX
1286
  {
1287
    int set = 1;
1288
    setsockopt(the->connection, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int));
1289
  }
1290
#endif
1291
0
  flag = fcntl(the->connection, F_GETFL, 0);
1292
0
  fcntl(the->connection, F_SETFL, flag | O_NONBLOCK);
1293
0
  if (connect(the->connection, (struct sockaddr*)&address, sizeof(address)) < 0) {
1294
0
       if (errno == EINPROGRESS) { 
1295
0
      fd_set fds;
1296
0
      struct timeval timeout = { 2, 0 }; // 2 seconds, 0 micro-seconds
1297
0
      int error = 0;
1298
0
      unsigned int length = sizeof(error);
1299
0
      FD_ZERO(&fds);
1300
0
      FD_SET(the->connection, &fds);
1301
0
      if (select(the->connection + 1, NULL, &fds, NULL, &timeout) == 0)
1302
0
        goto bail;
1303
0
      if (!FD_ISSET(the->connection, &fds))
1304
0
        goto bail;
1305
0
      if (getsockopt(the->connection, SOL_SOCKET, SO_ERROR, &error, &length) < 0)
1306
0
        goto bail;
1307
0
      if (error)
1308
0
        goto bail;
1309
0
    }
1310
0
    else
1311
0
      goto bail;
1312
0
  }
1313
0
  fcntl(the->connection, F_SETFL, flag);
1314
0
  c_signal(SIGPIPE, SIG_DFL);
1315
0
}
1316
0
#endif
1317
0
  return;
1318
0
bail:
1319
0
  fxDisconnect(the);
1320
0
}
1321
1322
void fxDisconnect(txMachine* the)
1323
0
{
1324
#if mxWindows
1325
  if (the->connection != INVALID_SOCKET) {
1326
    closesocket(the->connection);
1327
    the->connection = INVALID_SOCKET;
1328
  }
1329
  WSACleanup();
1330
#else
1331
0
  if (the->connection >= 0) {
1332
0
    close(the->connection);
1333
0
    the->connection = -1;
1334
0
  }
1335
0
#endif
1336
0
}
1337
1338
txBoolean fxIsConnected(txMachine* the)
1339
28.6k
{
1340
28.6k
  return (the->connection != mxNoSocket) ? 1 : 0;
1341
28.6k
}
1342
1343
txBoolean fxIsReadable(txMachine* the)
1344
0
{
1345
0
  return 0;
1346
0
}
1347
1348
void fxReceive(txMachine* the)
1349
0
{
1350
0
  int count;
1351
0
  if (the->connection != mxNoSocket) {
1352
#if mxWindows
1353
    count = recv(the->connection, the->debugBuffer, sizeof(the->debugBuffer) - 1, 0);
1354
    if (count < 0)
1355
      fxDisconnect(the);
1356
    else
1357
      the->debugOffset = count;
1358
#else
1359
0
  again:
1360
0
    count = read(the->connection, the->debugBuffer, sizeof(the->debugBuffer) - 1);
1361
0
    if (count < 0) {
1362
0
      if (errno == EINTR)
1363
0
        goto again;
1364
0
      else
1365
0
        fxDisconnect(the);
1366
0
    }
1367
0
    else
1368
0
      the->debugOffset = count;
1369
0
#endif
1370
0
  }
1371
0
  the->debugBuffer[the->debugOffset] = 0;
1372
0
}
1373
1374
void fxSend(txMachine* the, txBoolean more)
1375
0
{
1376
0
  if (the->connection != mxNoSocket) {
1377
#if mxWindows
1378
    if (send(the->connection, the->echoBuffer, the->echoOffset, 0) <= 0)
1379
      fxDisconnect(the);
1380
#else
1381
0
  again:
1382
0
    if (write(the->connection, the->echoBuffer, the->echoOffset) <= 0) {
1383
0
      if (errno == EINTR)
1384
0
        goto again;
1385
0
      else
1386
0
        fxDisconnect(the);
1387
0
    }
1388
0
#endif
1389
0
  }
1390
0
}
1391
1392
#endif /* mxDebug */
1393
1394
1395
1396
1397