I am using libxml in my iOS Swift project. To debug, I need to call the following C function from Swift:
void xmlDebugDumpString (FILE * output, const xmlChar * r)
However, I don't know how to create the FILE * output pointer in Swift.
I tried the following code:
let debugDoc: UnsafeMutablePointer<FILE>
debugDoc = fopen(debugDocURL.absoluteString, "w")
xmlDebugDumpNode(debugDoc, str)
The code compiled fine but gives the following runtime error
Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
The problem is the wrong usage of absoluteString, so that fopen()
fails and returns nil. The correct way to create a C string from an URL is withUnsafeFileSystemRepresentation:
guard let debugFile = debugDocURL.withUnsafeFileSystemRepresentation( { fopen($0, "w") }) else {
// Could not open file ...
}
Now you can write to the file
xmlDebugDumpNode(debugFile, ...)
and eventually close it:
fclose(debugFile)
An alternative option is to dump the debug output to the (predefined)
“standard error” file:
xmlDebugDumpNode(stderr, ...)
Related
I have an issue with trying to check if a file exists and reading it if it exists.
My code:
use std::{env, fs};
use std::fs::{File, read};
use std::path::Path;
use std::process::exit;
let arg = env::args().next().expect("Please open a file via the command line!");
let path = Path::new(
&arg
);
if !path.exists() {
error!("The specified path does not exist!");
exit(101);
}
let file = read(path).expect("Could not read file!");
let content = String::from_utf8(file).expect("The file does not contain valid characters!");
Run the program like this ./program.exe a_vali_file_path.txt
Expectation:
If you run the program with a valid file path as the first argument, the program will check if it exists. If it does, the program reads the file content and just returns.
What actually happened:
The program doesn't even really check for the file (it does not panic, even if the path is not valid) and if it tries to read it prints a bunch of bytes into the console followed by the error
error: Utf8Error { valid_up_to: 2, error_len: Some(1) } }.
This behavior occurs if the file exists or not.
env::args.next() references the executable, which doesn't contain UTF-8 bytes. If you want to point to the next argument you must use another .next() call, or better yet use a Vector to store your args.
Example of a vector being used to store args ->
fn main() {
let args: Vec<String> = env::args().collect()
...
}
To solve it your way:
fn main() {
let args = env::args()
args.next() //Points to executable (argv[0])
args.next() //Points to file (argv[1])
}
As you can see the second solution is not very elegant, but hey, to each their own.
I am using (Unicode) Inno Setup 6.0.5 on Windows 10 64-bit.
The exported symbol, I want to use has the signature:
typedef int(__stdcall *GetDirVST2x86) (LPWSTR lpString1);
The Inno Setup [Code] section has its declaration as:
function GetDirVST2x86(var lpString1: String): Integer;
external 'GetDirVST2x86#files:R2RINNO.DLL stdcall setuponly';
where, lpString1 will contain a pointer to the wide-string after the function returns and R2RINNO.DLL is a 32-bit DLL.
Now my problem is, if I compile and run this setup, a read access violation occurs right when I try to retrieve the value. I get the correct result when I execute this same function from a C program. Removing the var from the prototype declaration in Inno script fetches an empty (or possibly) empty or blank string, so that doesn't help either.
I don't have the source for the DLL I wish to use, and I figured out the signature from IDA. The scripting engine Inno Setup seems hopelessly inadequate as it doesn't support pointers at all.
One interesting thing I observed was if I changed the type of lpString1 to Cardinal or Integer and used IntToStr to fetch the string I got the value of the directory in which the setup was getting created.
Here's a working C code:
#include <windows.h>
#include <stdio.h>
#define _UNICODE
#define UNICODE
typedef int(WINAPI *GetDirVST2x86) (LPWSTR );
int main() {
HMODULE hModule = LoadLibrary("R2RINNO.DLL");
if (NULL != hModule) {
GetDirVST2x86 pGetDirVST2x86 = (GetDirVST2x86) GetProcAddress (hModule, "GetDirVST2x86");
if (NULL != pGetDirVST2x86) {
LPWSTR lpszVST2x86;
pGetDirVST2x86(lpszVST2x86);
wprintf(lpszVST2x86);
}
FreeLibrary(hModule);
}
}
Here's the output:
C:\Program Files (x86)\Steinberg\VstPlugins
Here's the IDA screenshot of the function I want to use:
Pascal Script equivalent of the C declaration should be:
function GetDirVST2x86(lpString1: string): Integer;
external 'GetDirVST2x86#files:R2RINNO.DLL stdcall setuponly';
(i.e. no var, as it is an input character pointer argument).
Assuming the function contract is that you (as a caller) allocate a buffer and provide it to the function to be filled in, you should call the function like this:
var
Buf: string;
begin
{ Allocate buffer for the result large enough according to the API specification }
SetLength(Buf, 1000);
GetDirVST2x86(Buf);
SetLength(Result, Pos(#0, Result) - 1);
end;
See also How to return a string from a DLL to Inno Setup?
If I have created a file in my main() function:
output, err := os.Create("D:\\output.txt")
And I want everything that another function in the program prints, to be put in that file using:
output.WriteString(str)
How could I pass a pointer to that file so that function could write to it?
Also, is there any other way I should use to write a string to a file, or WriteString is succicient?
Have your function take a pointer as a parameter using the * type modifier, and just pass your file object as-is since os.Create already returns a pointer:
func WriteStringToFile(f *os.File) {
n, err := f.WriteString("foobar")
}
// ..
output, err := os.Create("D:\\output.txt")
WriteStringToFile(output)
Also, please note that it is good practice not to ignore errors.
To write strings into a file can be done in a few different ways, especially if you want to avoid using the os.File object directly, and only use the io.Writer interface. For example:
fmt.Fprint(output, "foo bar")
Using an interface such as io.Writer is the way to go. Many types in Go fulfill the io.Writer just by having a Write method. os.File is one of those types.
Simply define a function that can take *File pointer as argument:
func Write(output *os.File) {
(...)
}
Write(&output) //call function.
}
Also you may want to ensure that file is closed in the end using:
defer output.Close()
I am trying to convert some of the ruby interpreter code called in C to mruby format. I am stuck and would appreciate help here.
My testruby.rb file content:
#require 'MyMod'
def helloworld(var1)
puts "You said #{var1}"
return MyMod.Issue1(var1).to_s
end
Below is the snippet of my C++ file:
Issue 1:
static mrb_value Issue1(mrb_state *mrb, mrb_value mrb_self)
{
mrb_??? val1; // What should be the type for string and where to find all the types?
mrb_get_args(mrb, "s", ?);
// How to manipulate val1? Say I want to concatenate few more data.
return mrb_????(val1); // How do I return this value?
}
The above method, I am sending as a module to the mruby interpreter so that .rb file can call this.
Please let me know if below format is the correct one:
struct RClass *mod = mrb_define_module(mrb, "MyMod");
mrb_define_module_function(mrb, mod, "SumI", Issue1, MRB_ARGS_REQ(1));
Issue2:
How do I convert the below ruby interpreter code to mruby?
rb_require("./testruby"); // where testruby is my testruby.rb file
Now I want to call the helloworld method from testruby.rb file. How do I call the equivalent method for mruby (for rb_funcall)?
How do I read the return value from the helloworld method in my c++ code?
Regards,
Re val1: mrb_value is the type that can hold any mruby object
Manipulating val1 could be done using mrb_funcall. That function returns a mrb_value:
mrb_value my_str = mrb_funcall(mrb_context, your_object, "your_method", 0);
printf("my_str = %s\n", RSTRING_PTR(my_str));
Re issue 2: There's no require in mruby: mrbgems are compiled and linked statically with the target binary (they are listed in the top-level build_config.rb file).
(A gem called mruby-require exists to mimic CRuby's require, but I've never used it)
I am facing an issue with calling of mruby VM in C. I could invoke the mruby vm and execute the ruby code from C. I could also trigger the methods defined in the ruby code as well. But I am facing issue while trying to read the return value of the ruby method. I have provided my example scenario below.
CODE:
#include <stdlib.h>
#include <stdio.h>
#include <mruby.h>
#include <mruby/compile.h>
int main(void)
{
mrb_state *mrb = mrb_open();
char code[] = "def helloworld() return'OK' end";
printf("Executing Ruby code from C!\n");
mrb_load_string(mrb, code);
mrb_load_string(mrb, "helloworld()");
// How to read the return value?
return 0;
}
I am not sure if this is the right way of calling the ruby methods? I couldnt find any documentation or examples on the web. Anyone who tried calling ruby code via c (using mruby) can you please help me?
Regards,
The return value of mrb_load_string() is the value of the last evaluated expression. But it's also mrb_undef_value() on failure that happened during parsing or code generation like a syntax error. In general the exc member of mrb_state is non-null if there was an uncaught exception:
mrb_value rv = mrb_load_string(mrb, "helloworld()");
if (mrb->exc) { // if uncaught exception …
if (!mrb_undef_p(rv)) { // … during execution/run-time
mrb_print_error(mrb); // write backtrace and other details to stderr
}
}
else {
mrb_p(mrb, rv); // similar to Kernel#p
}
If you only want to call a method, the mrb_funcall() family of functions can be used:
mrb_value rv = mrb_funcall(mrb, mrb_top_self(mrb), "helloworld", 0);
Or:
mrb_value rv = mrb_funcall_argv(mrb, mrb_top_self(mrb), mrb_intern_cstr(mrb, "helloworld"), 0, NULL);
Then the parser and code generator won't be used, thus it'll be faster and unless they're used elsewhere, the executable or (shared) library will be much smaller too. Plus mrb_undef_value() isn't a possible return value, otherwise checking for an uncaught exception and retrieving the return value can be done in the same way.