emscripten - string/char* parameter reference weirdness - javascript

So I'm playing around with emscripten and making linked lists. I started with the following code in C -
struct Node {
struct Node *next;
char *value;
};
extern struct Node *ll_new_node(char *value) {
struct Node *node;
node = malloc(sizeof(struct Node));
node->value = value;
return node;
}
extern struct Node *ll_add(struct Node *root, char *value) {
struct Node *node = ll_new_node(value);
if (root == NULL) {
root = node;
} else {
tail(root)->next = node;
}
return root;
}
//....
In the page I'm calling the code this way -
var new_node = Module.cwrap('ll_new_node', 'object', ['string'])
var add = Module.cwrap('ll_add', 'object', ['object', 'string']);
var list = 0;
Zepto(function($){
var printList = function() {
var node = list;
var s = "head -> ";
while (node != null && node != 0) {
s = s + value(node) + " -> ";
node = next(node);
}
s = s + "NULL";
$('#display').text(s);
};
printList();
$('#addBtn').on('click', function() {
var add_value = $('#itemField').val();
if (add_value && add_value.length > 0) {
list = add(list, add_value);
printList();
}
});
//...
});
What was happening was if I put "A" in the text box and added it to the list, "head -> A -> NULL" would print. Then if I but "B" in the text box and added it to the list, "head -> B -> B -> NULL" would print. The same pattern continued as more nodes were added. It was adding the new node, but it seems all node->value fields pointed to a shared string reference.
I made some test code in C to build and print a list, and it worked as expected with no changes. I ended up fixing it via emscripten by using strcpy on the string passed into ll_new_node and assigning the copy to node->value.
Is this "expected behavior" or a bug? Is the "copied reference" to the string due to some problem with how I'm using it on the JavaScript side? Is there some way to tell Emscripten not to do this?

Related

I need help converting a traversal tree from Java to JS (answer is in the description, dont downvote this post or else it will go private.)

This is the code I need help converting from Java to JavaScript. The code here is a Traversal Binary Tree written in Java, all I need is help from converting it from Java to JavaScript.
Java program for different tree traversals
/* Class containing left and right child of current
node and key value*/
class Node {
int key;
Node left, right;
public Node(int item)
{
key = item;
left = right = null;
}
}
class BinaryTree {
// Root of Binary Tree
Node root;
BinaryTree() { root = null; }
/* Given a binary tree, print its nodes according to the
"bottom-up" postorder traversal. */
void printPostorder(Node node)
{
if (node == null)
return;
// first recur on left subtree
printPostorder(node.left);
// then recur on right subtree
printPostorder(node.right);
// now deal with the node
System.out.print(node.key + " ");
}
/* Given a binary tree, print its nodes in inorder*/
void printInorder(Node node)
{
if (node == null)
return;
/* first recur on left child */
printInorder(node.left);
/* then print the data of node */
System.out.print(node.key + " ");
/* now recur on right child */
printInorder(node.right);
}
/* Given a binary tree, print its nodes in preorder*/
void printPreorder(Node node)
{
if (node == null)
return;
/* first print data of node */
System.out.print(node.key + " ");
/* then recur on left sutree */
printPreorder(node.left);
/* now recur on right subtree */
printPreorder(node.right);
}
// Wrappers over above recursive functions
void printPostorder() { printPostorder(root); }
void printInorder() { printInorder(root); }
void printPreorder() { printPreorder(root); }
// Driver method
public static void main(String[] args)
{
BinaryTree tree = new BinaryTree();
tree.root = new Node(1);
tree.root.left = new Node(2);
tree.root.right = new Node(3);
tree.root.left.left = new Node(4);
tree.root.left.right = new Node(5);
System.out.println(
"Preorder traversal of binary tree is ");
tree.printPreorder();
System.out.println(
"\nInorder traversal of binary tree is ");
tree.printInorder();
System.out.println(
"\nPostorder traversal of binary tree is ");
tree.printPostorder();
}
}
Disclamer: I have reaserched how to convert code but none of them show how to do it. So please help.
The answer to this code is here, so if any of you have the same problem then come here and copy this code! I didn't write this code it was actually someone named #wrangler. Thank you wrangler for sharing your code with me!
var displayTree = tree => console.log(JSON.stringify(tree, null, 2));
function Node(value) {
this.value = value;
this.left = null;
this.right = null;
}
function BinarySearchTree() {
this.root = null;
// Only change code below this line
this.inor=[];
this.inorder = function(node=this.root){
if(!this.root) return null;
if(node==this.root) this.inor=[];
if(!node) return this.inor;
this.inorder(node.left);
this.inor.push(node.value);
this.inorder(node.right);
return this.inor;
}
this.preor=[];
this.preorder = function(node=this.root){
if(!this.root) return null;
if(node==this.root) this.preor=[];
if(!node) return this.preor;
this.preor.push(node.value);
this.preorder(node.left);
this.preorder(node.right);
return this.preor;
}
this.postor=[];
this.postorder = function(node=this.root){
if(!this.root) return null;
if(node==this.root) this.postor=[];
if(!node) return this.postor;
this.postorder(node.left);
this.postorder(node.right);
this.postor.push(node.value);
return this.postor;
}
// Only change code above this line
}

Reference/set nested XML object property using path in a string - JavaScript

This is not for web development. I am using ES3.
How do I get the information from the xml element proof using javascript in this scenario?
My way of looking for the proof element with xml[xmlVariable] doesn't work - it returns nothing. But when you enter xml.ait.pages.proof in the console (while the program is held by breakpoint at the return expression) it returns the "desired info" from the proof element correctly.
I've read up on dot/bracket notation thinking that would be the solution but nope.
What's the correct syntax here?
<root>
<ait>
<pages>
<proof>desired info</proof>
</pages>
</ait>
</root>
var xmlFile = "C:\Users\user\Desktop\info.xml"
var xmlElementPath = "ait.pages.proof"
var info = readXMLVar(xmlElementPath, xmlFile)
function readXMLVar(xmlVariable, xmlFilePath) {
var file = new File(xmlFilePath)
file.open("r")
var content = file.read()
file.close()
var xml = new XML(content)
return xml[xmlVariable]
}
For XML I would probably query using XPath. The code you're using, however, seems to create an object structure from the parsed XML, and you then want to ask for a part of that structure using a path to it, as it were.
You can use square bracket notation as you tried, but you have to do it one property/node-level at a time. JS doesn't parse the dot separated path you provided to walk into the nested structure.
As such, you need something that can break apart the path you want, and recursively walk down the structure node by node.
Here is a basic function that can walk an object structure:
var getNodeFromPath = function (data, path, separator) {
var node_name,
node,
ret;
if (!Array.isArray(path)) {
path = path.split(separator || '.');
}
node_name = path.shift();
node = data[node_name];
if (node === undefined) {
ret = null;
} else {
if (path.length) {
ret = getNodeFromPath(node, path);
} else {
ret = node;
}
}
return ret;
};
You could call it like so:
var proof_element = getNodeFromPath(yourParsedXmlData, 'ait.pages.proof');
Note that the function I gave you has minimal control in it. You'll probably want to add some checking to make it more resistant to arbitrary input data/path problems.
Applied fixes to JAAulde's answer and some slight modifications to fit into my function. Here is my code to get and set XML variables.
!(Object.prototype.toString.call(path) === '[object Array]') is used in place of !Array.isArray(path) because I'm forced to use ES3.
function readXMLFile(xmlFilePath) {
var file = new File(xmlFilePath)
file.open("r")
var content = file.read()
file.close()
return [file, new XML(content)]
}
function getXMLVar(xmlFilePath, nodePath, separator) {
var xml = readXMLFile(xmlFilePath)[1]
// navigate xml to return target node info
var getNodeFromPath = function(data, path, separator) {
var node_name,
node,
ret
if(!(Object.prototype.toString.call(path) === '[object Array]')) {
path = path.split(separator || '.')
}
node_name = path.shift()
node = data[node_name]
if(node === undefined) {
ret = null
} else {
if(path.length) {
ret = getNodeFromPath(node, path, separator)
} else {
ret = node
}
}
return ret
}
return getNodeFromPath(xml, nodePath, separator)
}
function setXMLVar(xmlFilePath, nodePath, separator, value) {
var read = readXMLFile(xmlFilePath)
var file = read[0]
var xml = read[1]
setNodeFromPath = function(data, path, separator, value) {
var node_name,
node
if(!(Object.prototype.toString.call(path) === '[object Array]')) {
path = path.split(separator || '.')
}
node_name = path.shift()
node = data[node_name]
if(path.length > 1) {
setNodeFromPath(node, path, separator, value)
} else {
node[path[0]] = value
}
}
setNodeFromPath(xml, nodePath, separator, value)
file.open("w")
file.write(xml)
file.close()
}

Read a text file into an array with OS X Javascript

I'm really struggling to find documentation on how to read a text file into an array using OS X Automation with Javascript.
Here's what I have so far:
var app = Application.currentApplication();
app.includeStandardAdditions = true;
var myFile = "/Users/Me/Dropbox/textfile.txt";
var openedFile = app.openForAccess(myfile, { writePermission: true });
var myText = openedFile.??
app.closeAccess(URLFile);
I copied most of this from the official Apple documentation. I'm finding it really difficult to find documentation anywhere online. For example, what are the arguments for openForAccess? There doesn't seem to be anything in any dictionary to describe that method.
Am I wasting my time with JXA?
Apple has an entire page devoted to reading and writing files in their Mac Automation Scripting Guide. This includes a function that performs exactly the action you are looking for. I've re-written your example below using the readAndSplitFile function from Apple's guide:
var app = Application.currentApplication()
app.includeStandardAdditions = true
function readAndSplitFile(file, delimiter) {
// Convert the file to a string
var fileString = file.toString()
// Read the file using a specific delimiter and return the results
return app.read(Path(fileString), { usingDelimiter: delimiter })
}
var fileContentsArray = readAndSplitFile('/Users/Me/Dropbox/textfile.txt', '\n')
After running the above code, fileContentsArray will hold an array of strings, with each string containg a single line of the file. (You could also use \t as a delimiter to break at every tab, or any other character of your choosing.)
Some generic functions and an illustrative test:
(function () {
'use strict';
// GENERIC FUNCTIONS ------------------------------------------------------
// doesFileExist :: String -> Bool
function doesFileExist(strPath) {
var error = $();
return $.NSFileManager.defaultManager
.attributesOfItemAtPathError($(strPath)
.stringByStandardizingPath, error), error.code === undefined;
};
// lines :: String -> [String]
function lines(s) {
return s.split(/[\r\n]/);
};
// readFile :: FilePath -> maybe String
function readFile(strPath) {
var error = $(),
str = ObjC.unwrap(
$.NSString.stringWithContentsOfFileEncodingError($(strPath)
.stringByStandardizingPath, $.NSUTF8StringEncoding, error)
),
blnValid = typeof error.code !== 'string';
return {
nothing: !blnValid,
just: blnValid ? str : undefined,
error: blnValid ? '' : error.code
};
};
// show :: a -> String
function show(x) {
return JSON.stringify(x, null, 2);
};
// TEST -------------------------------------------------------------------
var strPath = '~/DeskTop/tree.txt';
return doesFileExist(strPath) ? function () {
var dctMaybe = readFile(strPath);
return dctMaybe.nothing ? dctMaybe.error : show(lines(dctMaybe.just));
}() : 'File not found:\n\t' + strPath;
})();

Providing stdin to an emscripten HTML program?

I have a C program that takes one argument (a char array / string) via command line and also reads from stdin. I've compiled it to JavaScript using emscripten. This was successful and I can run it just like the normal C program using node.js:
emcc -O2 translate.c
node translate.js "foo" < bar.txt
As you can see, I'm providing the string "foo" as an argument and the contents of bar.txt as stdin. Now I want this to be a self-contained HTML file.
By changing the output to HTML:
emcc -O2 translate.c -o trans.html
I provide the argument by adding arguments: ['foo'], to the definitions in var Module. This works as expected, the program receives the argument correctly.
Now, how do I provide the stdin input to this program? I don't need to do this dynamically. It would be fine to just declare a string somewhere in the HTML with the required stdin content.
A way would be to use the Emscripten Filesystem API, for example by calling FS.init in the Module preRun function, passing custom functions to be used for standard input, output and error.
var Module = {
preRun: function() {
function stdin() {
// Return ASCII code of character, or null if no input
}
function stdout(asciiCode) {
// Do something with the asciiCode
}
function stderr(asciiCode) {
// Do something with the asciiCode
}
FS.init(stdin, stdout, stderr);
}
};
The functions are quite low-level: they each deal with one character at a time as an ASCII code. If you have strings you want to pass in, you would have to iterate over the characters of the string yourself. I suspect charCodeAt would be helpful. To output strings from stdout or stderr, then I suspect fromCharCode would be helpful.
Example (not very well tested!) implementations using each are below.
var input = "This is from the standard input\n";
var i = 0;
var Module = {
preRun: function() {
function stdin() {
if (i < res.length) {
var code = input.charCodeAt(i);
++i;
return code;
} else {
return null;
}
}
var stdoutBuffer = "";
function stdout(code) {
if (code === "\n".charCodeAt(0) && stdoutBuffer !== "") {
console.log(stdoutBuffer);
stdoutBuffer = "";
} else {
stdoutBuffer += String.fromCharCode(code);
}
}
var stderrBuffer = "";
function stderr(code) {
if (code === "\n".charCodeAt(0) && stderrBuffer !== "") {
console.log(stderrBuffer);
stderrBuffer = "";
} else {
stderrBuffer += String.fromCharCode(code);
}
}
FS.init(stdin, stdout, stderr);
}
};
Rather than editing the output of Emscripten, you could monkey patch the Window object
window.prompt = function() {
return 'This will appear to come from standard input';
};
Not wonderful, but I would deem this less of a hack than editing the Emscripten-generated Javascript.
According the question "Edit" , I made my function , thx a lot.
Just hope the code below can help someone else.
comment run(); in the end of emscript
// in my emscript
// shouldRunNow refers to calling main(), not run().
var shouldRunNow = true;
if (Module['noInitialRun']) {
shouldRunNow = false;
}
//run(); // << here
// {{POST_RUN_ADDITIONS}}
result = areaInput(); // As the question mentioned
add the code below in your html file to activate run() in emscript
<script>
var message;
var point = -1;
function getArea(){
message = document.getElementById('input').value.split('\n');
}
function areaInput(){
if(point >= message.length - 1){
return null;
}
point += 1;
return message[point];
}
function execEmscript(){
window.console = {
log: function(str){
document.getElementById("output").value += "\n" + str;
}
}
getArea();
run();
}
</script>
remember io textareas in your html
<textarea id="input" cols="80" rows="30"></textarea>
<textarea id="output" cols="80" rows="30"></textarea>
and a button
<button onclick="execEmscript();">run</button>

Windows Scripting to call other commands?

I was trying my hand at Windows shell scripting using cscript and Javascript. The idea was to take a really long Python command that I was tired of typing into the command line over and over. What I wanted to do was write a script that is much shorter to write the whole Python command into a Windows script and just call the Windows script, which would be a lot less to type. I just don't know how I would go about calling a "command within a command" if that makes sense.
This is probably an easy thing, but I'm an newbie at this so please bear with me!
The idea:
Example original command: python do <something really complicated with a long filepath>
Windows Script: cscript easycommand
<package id = "easycommand">
<job id = "main" >
<script type="text/javascript">
// WHAT GOES HERE TO CALL python do <something really complicated>
WScript.Echo("Success!");
</script>
</job>
</package>
Thanks for all your help!
Here's what I use
function logMessage(msg) {
if (typeof wantLogging != "undefined" && wantLogging) {
WScript.Echo(msg);
}
}
// http://msdn.microsoft.com/en-us/library/d5fk67ky(VS.85).aspx
var windowStyle = {
hidden : 0,
minimized : 1,
maximized : 2
};
// http://msdn.microsoft.com/en-us/library/a72y2t1c(v=VS.85).aspx
var specialFolders = {
windowsFolder : 0,
systemFolder : 1,
temporaryFolder : 2
};
function runShellCmd(command, deleteOutput) {
deleteOutput = deleteOutput || false;
logMessage("RunAppCmd("+command+") ENTER");
var shell = new ActiveXObject("WScript.Shell"),
fso = new ActiveXObject("Scripting.FileSystemObject"),
tmpdir = fso.GetSpecialFolder(specialFolders.temporaryFolder),
tmpFileName = fso.BuildPath(tmpdir, fso.GetTempName()),
rc;
logMessage("shell.Run("+command+")");
// use cmd.exe to redirect the output
rc = shell.Run("%comspec% /c " + command + "> " + tmpFileName,
windowStyle.Hidden, true);
logMessage("shell.Run rc = " + rc);
if (deleteOutput) {
fso.DeleteFile(tmpFileName);
}
return {
rc : rc,
outputfile : (deleteOutput) ? null : tmpFileName
};
}
Here's an example of how to use the above to list the Sites defined in IIS with Appcmd.exe:
var
fso = new ActiveXObject("Scripting.FileSystemObject"),
windir = fso.GetSpecialFolder(specialFolders.WindowsFolder),
r = runShellCmd("%windir%\\system32\\inetsrv\\appcmd.exe list sites");
if (r.rc !== 0) {
// 0x80004005 == E_FAIL
throw {error: "ApplicationException",
message: "shell.run returned nonzero rc ("+r.rc+")",
code: 0x80004005};
}
// results are in r.outputfile
var
textStream = fso.OpenTextFile(r.outputfile, OpenMode.ForReading),
sites = [], item,
re = new RegExp('^SITE "([^"]+)" \\((.+)\\) *$'),
parseOneLine = function(oneLine) {
// each line is like this: APP "kjsksj" (dkjsdkjd)
var tokens = re.exec(oneLine), parts;
if (tokens === null) {
return null;
}
// return the object describing the website
return {
name : tokens[1]
};
};
// Read from the file and parse the results.
while (!textStream.AtEndOfStream) {
item = parseOneLine(textStream.ReadLine()); // you create this...
logMessage(" site: " + item.name);
sites.push(item);
}
textStream.Close();
fso.DeleteFile(r.outputfile);
Well, basically:
Obtain a handle to the shell so you can execute your script
Create the command you want to execute (parameters and all) as a string
Call the Run method on the shell handle, and figure out which window mode you want and also whether you want to wait until the spawned process finishes (probably) or not.
Error handling because Run throws exceptions
At this point it's worth writing a lot of utility functions if ever you need to do it more than once:
// run a command, call: run('C:\Python27\python.exe', 'path/to/script.py', 'arg1', 'arg2') etc.
function run() {
try {
var cmd = "\"" + arguments[0] + "\"";
var arg;
for(var i=1; i< arguments.length; ++i) {
arg = "" + arguments[i];
if(arg.length > 0) {
cmd += arg.charAt(0) == "/" ? (" " + arg) : (" \"" + arg + "\"");
}
}
return getShell().Run(cmd, 1, true); // show window, wait until done
}
catch(oops) {
WScript.Echo("Error: unable to execute shell command:\n"+cmd+
"\nInside directory:\n" + pwd()+
"\nReason:\n"+err_message(oops)+
"\nThis script will exit.");
exit(121);
}
}
// utility which makes an attempt at retrieving error messages from JScript exceptions
function err_message(err_object) {
if(typeof(err_object.message) != 'undefined') {
return err_object.message;
}
if(typeof(err_object.description) != 'undefined') {
return err_object.description;
}
return err_object.name;
}
// don't create new Shell objects each time you call run()
function getShell() {
var sh = WScript.CreateObject("WScript.Shell");
getShell = function() {
return sh;
};
return getShell();
}
For your use case this may be sufficient, but you might want to extend this with routines to change working directory and so on.

Categories

Resources