Last active
September 29, 2022 06:32
-
-
Save Tetralux/c7d1d0562786675e8c73bc7f3bfdff80 to your computer and use it in GitHub Desktop.
Example of how to bind and use popen from libc
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package process | |
import "core:c" | |
import "core:c/libc" | |
import "core:strings" | |
when ODIN_OS == .Windows { | |
foreign import libc_obj "system:libucrt.lib" | |
POPEN_NAME :: "_popen" | |
PCLOSE_NAME :: "_pclose" | |
} else when ODIN_OS == .Darwin { | |
foreign import libc_obj "system:System.framework" | |
POPEN_NAME :: "popen" | |
PCLOSE_NAME :: "pclose" | |
} else { | |
foreign import libc_obj "system:c" | |
POPEN_NAME :: "popen" | |
PCLOSE_NAME :: "pclose" | |
} | |
@(default_calling_convention="c") | |
foreign libc_obj { | |
@(link_name=POPEN_NAME) popen :: proc(command: cstring, typ: cstring) -> ^libc.FILE --- | |
@(link_name=PCLOSE_NAME) pclose :: proc(stream: ^libc.FILE) -> c.int --- | |
} | |
Process :: distinct ^libc.FILE | |
start :: proc(cmd: string) -> (p: Process, ok: bool) { | |
cmd := strings.clone_to_cstring(cmd) | |
defer delete(cmd) | |
fd := popen(cmd, "rw") | |
if fd == nil do return | |
return Process(fd), true | |
} | |
wait :: proc(p: Process) { | |
pclose(cast(^libc.FILE) p) // NOTE: waits for the process to quit, and then frees it | |
} | |
// Write to the process' stdin. | |
write :: proc(p: Process, buf: []byte) -> (wrote: int, ok: bool) { | |
fd := cast(^libc.FILE) p | |
for wrote < len(buf) { | |
n := libc.fwrite(raw_data(buf), 1, c.size_t(len(buf)), fd) | |
if n == 0 { | |
ok = libc.ferror(fd) == 0 | |
if !ok do libc.clearerr(fd) | |
return | |
} | |
wrote += int(n) | |
} | |
libc.fflush(fd) // NOTE: libc buffers the stdin/stdout of the process | |
ok = true | |
return | |
} | |
// Read from the process' stdout. | |
read :: proc(p: Process, dst: []byte) -> (read: int, ok: bool) { | |
fd := cast(^libc.FILE) p | |
n := libc.fread(raw_data(dst), 1, c.size_t(len(dst)), fd) | |
ok = libc.ferror(fd) == 0 | |
if !ok do libc.clearerr(fd) | |
return int(n), ok | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hey, i am the person that asked this question on discord, sadly i dont grasp how i should use this to achieve what i want.
For example reading stdout, i need to pass a process and byte array to the read function, but i dont know which process.
SO when i try to execute libc.system("ls"), that i get feedback of what exactly happend, but passing that wont work since its of type int.
I hope my question is not bothering you, i am just trying to make sense of how to use code that you provided.
Thank you very much.