Redirecting output of an external application started with glib - glib

I'm trying to use vala to start an external application using GLib with spawn_command_line_sync().
According to the documentation (http://valadoc.org/#!api=glib-2.0/GLib.Process.spawn_sync) you can pass a string to store the output of the external application.
While this works fine when starting a script which prints a couple of lines, I need to call a program which will print the content of a binary file.
(for example "cat /usr/bin/apt-get")
Is there any way how I can receive the output of the external program not in a string, but in a DataStream or something like that ?
I'm planning to write the ouput of the external program to a file, so just calling "cat /usr/bin/apt-get > outputfile" would be an alternative (not as nice), but it doesn't seem to work.
Anyway I would prefer it to get some kind of Output Stream.
I would appreciate any help.
Code im using:
using GLib;
static void main(string[] args) {
string execute = "cat /usr/bin/apt-get";
string output = "out";
try {
GLib.Process.spawn_command_line_sync(execute, out output);
} catch (SpawnError e) {
stderr.printf("spawn error!");
stderr.printf(e.message);
}
stdout.printf("Output: %s\n", output);
}

GLib.Process.spawn_async_with_pipes will let you do just that. It spawns the processes and returns a file descriptor for each of stdout, stderr, and stdin. There's a sample of code in the ValaDoc on how to set up IOChannels to monitor the output.

Thanks for that, I must have overread spawn_async_with_pipes() returning ints and not strings.
Is there anything wrong with doing it this way ?
(besides the buffer size of 1)
using GLib;
static void main(string[] args) {
string[] argv = {"cat", "/usr/bin/apt-get"};
string[] envv = Environ.get();
int child_pid;
int child_stdin_fd;
int child_stdout_fd;
int child_stderr_fd;
try {
Process.spawn_async_with_pipes(
".",
argv,
envv,
SpawnFlags.SEARCH_PATH,
null,
out child_pid,
out child_stdin_fd,
out child_stdout_fd,
out child_stderr_fd);
} catch (SpawnError e) {
stderr.printf("spawn error!");
stderr.printf(e.message);
return;
}
FileStream filestream1 = FileStream.fdopen(child_stdout_fd, "r");
FileStream filestream2 = FileStream.open("./stdout", "w");
uint8 buf[1];
size_t t;
while ((t = filestream1.read(buf, 1)) != 0) {
filestream2.write(buf, 1);
}
}

Related

GLib parsing integer from string

I'm trying to parse value from string in C for GLib application.
The result is well-compiled freezing app with no error/warning.
I post the function used to be launched for specific thread. The function is a stub only.
int i;
gchar *buffer="";
void *mainthreadfunc(){
buffer = g_strdup ("25");
i = atoi((char *)buffer);
for(;i<10;i++){
g_print("The i is: %d\n", i);
g_usleep (1000000);
}
}

Interfacing readline into Rust

I try to do this tutorial in rust, so far I have a lot of problems interfacing the C library into Rust.
C equivalent code:
#include <stdio.h>
#include <stdlib.h>
#include <editline/readline.h>
#include <editline/history.h>
int main(int argc, char** argv) {
/* Print Version and Exit Information */
puts("Lispy Version 0.0.0.0.1");
puts("Press Ctrl+c to Exit\n");
/* In a never ending loop */
while (1) {
/* Output our prompt and get input */
char* input = readline("lispy> ");
/* Add input to history */
add_history(input);
/* Echo input back to user */
printf("No you're a %s\n", input);
/* Free retrived input */
free(input);
}
return 0;
}
So far i got this:
extern crate libc;
use std::c_str;
#[link(name = "readline")]
extern {
fn readline (p: *const libc::c_char) -> *const libc::c_char;
}
fn rust_readline (prompt: &str) -> Option<Box<str>> {
let cprmt = prompt.to_c_str();
cprmt.with_ref(|c_buf| {
unsafe {
let ret = c_str::CString::new (readline (c_buf), true);
ret.as_str().map(|ret| ret.to_owned())
}
})
}
fn main() {
println!("Lispy Version 0.0.1");
println!("Press Ctrl+c to Exit.\n");
// I want to have "history" in Linux of this:
//
// loop {
// print!("lispy> ");
// let input = io::stdin().read_line().unwrap();
// print!("No you're a {}", input);
// }
loop {
let val = rust_readline ("lispy> ");
match val {
None => { break }
_ => {
let input = val.unwrap();
println!("No you're a {}", input);
}
}
}
}
Especifically, I'm having issues with rust_readline function, i don't understand very well what's doing inside.
Edit Cargo.toml, put this:
[dependencies.readline]
git = "https://github.com/shaleh/rust-readline"
Code corrected:
extern crate readline;
fn main() {
println!("Lispy Version 0.0.1");
println!("Press Ctrl+c to Exit.\n");
loop {
let input = readline::readline("lispy> ").unwrap();
readline::add_history(input.as_str());
println!("No you're a {}", input);
}
}
Happy Lisping :-) .
Funny thing is, that I found this question reading the very same book, but not including any book specific information in my search query.
There is now a crate for this. Facon's solution worked for me, but the prompt string always printed as garbage using that library, so I looked for another crate and found one working nicely. Here is an updated example:
cargo.toml:
[dependencies]
# https://crates.io/crates/rustyline
rustyline = "3.0.0"
main.rs:
extern crate rustyline;
use rustyline::error::ReadlineError;
use rustyline::Editor;
const HISTORY_FILENAME: &str = "history.txt";
fn main() {
println!("Lispy Version 0.0.1");
println!("Press Ctrl+c to Exit.\n");
// We create an editor for the readline history.
let mut readline_editor = Editor::<()>::new();
// And then load the history, if it exists.
if readline_editor.load_history(HISTORY_FILENAME).is_err() {
println!("No previous history.");
}
loop {
// We read some input from CLI.
let readline = readline_editor.readline("LISPY>> ");
// The reading of the input could fail, if a user uses special
// key combinations. So we match against the readline Result
// type. Result can either be some `Ok` or an some `Err`.
match readline {
Ok(line) => {
readline_editor.add_history_entry(line.as_ref());
println!("No, you are {}", line);
},
Err(ReadlineError::Interrupted) => {
println!("CTRL-C");
break
},
Err(ReadlineError::Eof) => {
println!("CTRL-D");
break
},
Err(err) => {
println!("Error: {:?}", err);
break
}
}
readline_editor.save_history(HISTORY_FILENAME).expect("Could not save to readline history.");
}
}

Lua 'require' but files are only in memory

Setting: I'm using Lua from a C/C++ environment.
I have several lua files on disk. Those are read into memory and some more memory-only lua files become available during runtime. Think e.g. of an editor, with additional unsaved lua files.
So, I have a list<identifier, lua_file_content> in memory. Some of these files have require statements in them. When I try to load all these files to a lua instance (currently via lua_dostring) I get attempt to call global require (a nil value).
Is there a possibility to provide a require function, which replaces the old one and just uses the provided in memory files (those files are on the C side)?
Is there another way of allowing require in these files without having the required files on disk?
An example would be to load the lua stdlib from memory only without altering it. (This is actually my test case.)
Instead of replacing require, why not add a function to package.loaders? The code is nearly the same.
int my_loader(lua_State* state) {
// get the module name
const char* name = lua_tostring(state);
// find if you have such module loaded
if (mymodules.find(name) != mymodules.end())
{
luaL_loadbuffer(state, buffer, size, name);
// the chunk is now at the top of the stack
return 1;
}
// didn't find anything
return 0;
}
// When you load the lua state, insert this into package.loaders
http://www.lua.org/manual/5.1/manual.html#pdf-package.loaders
A pretty straightforward C++ function that would mimic require could be: (pseudocode)
int my_require(lua_State* state) {
// get the module name
const char* name = lua_tostring(state);
// find if you have such module loaded
if (mymodules.find(name) != mymodules.end())
luaL_loadbuffer(state, buffer, size, name);
// the chunk is now at the top of the stack
lua_call(state)
return 1;
}
Expose this function to Lua as require and you're good to go.
I'd also like to add that to completely mimic require's behaviour, you'd probably need to take care of package.loaded, to avoid the code to be loaded twice.
There is no package.loaders in lua 5.2
It called package.searchers now.
#include <stdio.h>
#include <string>
#include <lua.hpp>
std::string module_script;
int MyLoader(lua_State *L)
{
const char *name = luaL_checkstring(L, 1); // Module name
// std::string result = SearchScript(name); // Search your database.
std::string result = module_script; // Just for demo.
if( luaL_loadbuffer(L, result.c_str(), result.size(), name) )
{
printf("%s", lua_tostring(L, -1));
lua_pop(L, 1);
}
return 1;
}
void SetLoader(lua_State* L)
{
lua_register(L, "my_loader", MyLoader);
std::string str;
// str += "table.insert(package.loaders, 2, my_loader) \n"; // Older than lua v5.2
str += "table.insert(package.searchers, 2, my_loader) \n";
luaL_dostring(L, str.c_str());
}
void SetModule()
{
std::string str;
str += "print([[It is add.lua]]) \n";
str += "return { func = function() print([[message from add.lua]]) end } \n";
module_script=str;
}
void LoadMainScript(lua_State* L)
{
std::string str;
str += "dev = require [[add]] \n";
str += "print([[It is main.lua]]) \n";
str += "dev.func() \n";
if ( luaL_loadbuffer(L, str.c_str(), str.size(), "main") )
{
printf("%s", lua_tostring(L, -1));
lua_pop(L, 1);
return;
}
}
int main()
{
lua_State* L = luaL_newstate();
luaL_openlibs(L);
SetModule(L); // Write down module in memory. Lua not load it yet.
SetLoader(L);
LoadMainScript(L);
lua_pcall(L,0,0,0);
lua_close(L);
return 0;
}

Why is that using Boost on iOS crashed in release mode, but not int debug

When I use boost.asio, boost.thread and etc on iOS platform, the app crashed int release mode but works well int debug mode. I fix the release runtime bugs as I descibed at this.
My Question Is:
Why is everything ok in debug-mode? The answer seems to say that the crash is caused by thumb flag. The debug-mode compiler should use "thumb" flag as same as release mode, ant I wonder the app should also crash in debug-mode because of using thumb, which confuses me.
UPDATE:
Here is my code of using asio:
Params are declared as the private member of the CrossPlatformAPI:
boost::recursive_mutex m_mutex;
boost::asio::io_service m_ioService;
boost::scoped_ptr<boost::asio::io_service::work> m_idleWork;
boost::scoped_ptr<boost::thread> m_mainThread;
First, I post two async-tasks by calling CrossPlatformAPI::Init in the main thread:
int CrossPlatformAPI::Init(const P2PInitParam& oInitParam)
{
boost::recursive_mutex::scoped_lock lock(m_mutex);
m_idleWork.reset(new boost::asio::io_service::work(m_ioService));
m_mainThread.reset(new boost::thread(boost::bind( &boost::asio::io_service::run, &m_ioService)));
std::string strLog(oInitParam.szAppDataDir);
m_ioService.post(boost::bind( &CrossPlatformAPI::HandleLog, this, strLog));
m_ioService.post(boost::bind( &CrossPlatformAPI::HandleInit, this, oInitParam));
return 0;
}
Second, CrossPlatformAPI::HandleLog and CrossPlatformAPI::HandleInit handle the async-task:
void CrossPlatformAPI::HandleLog(std::string & log)
{
std::cout << log << std::endl;
}
void CrossPlatformAPI::HandleInit(P2PInitParam& oInitParam)
{
try
{
//Init
//...
}
catch (std::exception&)
{
}
return;
}
I have tried using boost:ref to wrap the binding param instead of binding directly, then the app doesn't crash. Why not? And what also confuses me is that if the bind param type is std::string, the param that the handle function received is incorrect when wrapped by std::ref. It seems that std::string without using std::ref works well: didn't crash and the value recived is correct, but not the sruct-type param, like P2PInitParam.
UPDATE2:
int CrossPlatformAPI::Init(const P2PInitParam& oInitParam)
{
boost::recursive_mutex::scoped_lock lock(m_mutex);
m_idleWork.reset(new boost::asio::io_service::work(m_ioService));
m_mainThread.reset(new boost::thread(boost::bind( &boost::asio::io_service::run, &m_ioService)));
std::string strLog(oInitParam.szAppDataDir);
m_ioService.post(boost::bind( &CrossPlatformAPI::HandleLog, this, boost::cref(strLog))); // OK
m_ioService.post(boost::bind( &CrossPlatformAPI::HandleInit, this, boost::cref(oInitParam))); // Crash
return 0;
}
void CrossPlatformAPI::HandleLog(const std::string& log)
{
std::cout << log << std::endl;
}
void CrossPlatformAPI::HandleInit(const P2PInitParam& oInitParam)
{
try
{
//Init
//...
}
catch (std::exception&)
{
}
return;
}

ObjectiveC Lua: Error in C function call from Lua

I am using two libraries for objectiveC-lua bridge.
One is Lua library (with C API) provided by Lua official web page. Since that library
does not provide API to pass objectiveC object to lua, I opt for another library
for this purpose, and Wax seems to be the only option for now.
This program starts when runLua() is called, where it will invoke test.lua
iOS implementation
-(void) runLua{
[self initLua];
[self invokeLua:#"require test"];
}
-(void)initLua{
// initialize Lua and our load our lua file
L = luaL_newstate(); // create a new state structure for the interpreter
luaL_openlibs(L); // load all the standard libraries into the interpreter
lua_settop(L, 0);
initDone = TRUE;
}
-(void) invokeLua:(NSString*)luaSrcStr{
//NSLog(#"%#",luaSrcStr);
if(!initDone){
NSLog(#"inside invokeLua: not yet init");
[self initLua];
}
lua_settop(L, 0);
int ok = luaL_loadstring(L, [luaSrcStr UTF8String]);
if(ok == 0){
lua_getglobal(L,"debug");
lua_getfield(L,-1, "traceback");
lua_remove(L,-2);
lua_insert(L,-2);
ok = lua_pcall(L, 0, 0, -2);
if (ok != 0){
luaL_error(L, "cannot run lua file: %s",
lua_tostring(L, -1));
return;
}
}
test.lua
local testObject = myLib.newiOSObjWithName("TestObject")
testObject:setObjectLength(3.6)
myLib.passTestObjectToC(testObject)
There is no problem in executing 1st and 2nd line, only 3rd line, error occurs.
Error
PANIC: unprotected error in call to Lua API (cannot run lua file: attempt to index a nil
value stack traceback:
[C]: in function 'passTestObjectToC'
...-451C-9F1D-9CE481B4F9A0/test.app/test.lua:6: in main chunk
[C]: in function 'require'
[string "..."]:3: in main chunk)
The error seems to indicate that the function passTestObjectToC is not found in lua, which in this case is not true as the function is registered to lua when luaL_openlibs(L) is called.
My guess, the problem comes where objectiveC object is passed to lua using wax_instance_create(luaState *L, ...). After passing the object, Wax probably has changed the luaState *L that it doesnt remember that passTestObjectToC is already registered.
The C implementation as below.
C implementation
static int newiOSObjWithName(lua_State *L){
NSString *className = [NSString stringWithCString:lua_tostring(L, -1)
encoding:NSUTF8StringEncoding];
className = [className stringByReplacingCharactersInRange:NSMakeRange(0,1) withString:
[[className substringToIndex:1] uppercaseString]];
id classId = [[NSClassFromString(className) alloc] init];
luaopen_wax_instance(L);
wax_instance_create(L, classId, YES);
return 1;
}
static int passTestObjectToC(lua_State *L){
// something to be done here
return 0;
}
static const struct luaL_Reg myLib [] = {
{"newiOSObjWithName", newiOSObjWithName},
{"passTestObjectToC", passTestObjectToC},
{NULL, NULL}
}
int luaopen_mylib (lua_State *L){
luaL_register(L, "myLib", myLib);
return 1;
}
linit.c of Lua Library
static const luaL_Reg lualibs[] = {
{"", luaopen_base},
{LUA_LOADLIBNAME, luaopen_package},
{LUA_TABLIBNAME, luaopen_table},
{LUA_IOLIBNAME, luaopen_io},
{LUA_OSLIBNAME, luaopen_os},
{LUA_STRLIBNAME, luaopen_string},
{LUA_MATHLIBNAME, luaopen_math},
{LUA_DBLIBNAME, luaopen_debug},
{"myLib", luaopen_mylib},
{NULL, NULL}
};
LUALIB_API void luaL_openlibs (lua_State *L) {
const luaL_Reg *lib = lualibs;
for (; lib->func; lib++) {
lua_pushcfunction(L, lib->func);
lua_pushstring(L, lib->name);
lua_call(L, 1, 0);
}
}
Anyone can tell me why there is an error for passTestObjectToC call? What is the reason?
There is no example of Wax implementation for passing iOSObject available. I hv not found it.
So I am not sure if this is the right way to do it. Most examples use Wax to implement iOS classes/functions directly in Lua script instead.
My mistake, there is no problem in the codes above. Function passTestObjectToC is successfully called, the error occurred because of the implementation inside passTestObjectToC and not during the calling of passTestObjectToC.
iOS object is successfully passed from iOS to Lua using Wax as above.

Resources