Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[10_1] migrate basic windows files from mogan #54

Merged
merged 4 commits into from
Aug 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 134 additions & 0 deletions Plugins/Windows/mingw_sys_utils.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@

/******************************************************************************
* MODULE : mingw_sys_utils.cpp
* DESCRIPTION: external command handling
* COPYRIGHT : (C) 2015 Gregoire LECERF, Denis RAUX
*******************************************************************************
* This software falls under the GNU general public license version 3 or later.
* It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
* in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
******************************************************************************/

#include "mingw_sys_utils.hpp"
#include "analyze.hpp"
#include "spawn.hpp"
#include "tm_timer.hpp"
#include "win-utf8-compat.hpp"

static void
_unix_system_warn (pid_t pid, ::string which, ::string msg) {}

int
mingw_system (array< ::string> arg, array<int> fd_in, array< ::string> str_in,
array<int> fd_out, array< ::string*> str_out) {
// Run command arg[0] with arguments arg[i], i >= 1.
// str_in[i] is sent to the file descriptor fd_in[i].
// str_out[i] is filled from the file descriptor fd_out[i].
// If str_in[i] is -1 then $$i automatically replaced by a valid
// file descriptor in arg.
if (N (arg) == 0) return 0;
::string which= recompose (arg, " ");
int n_in= N (fd_in), n_out= N (fd_out);
ASSERT (N (str_in) == n_in, "size mismatch");
ASSERT (N (str_out) == n_out, "size mismatch");
array<Channel> ch (n_in + n_out);

for (int i= 0; i < n_in; i++) {
int fd= fd_in[i];
if (fd >= 0) ch[i].Init (fd, Channel::CHIN);
else ch[i].Init (Channel::CHIN);
}
for (int i= 0; i < n_out; i++) {
int fd= fd_out[i];
if (fd >= 0) ch[i + n_in].Init (fd, Channel::CHOUT);
else ch[i + n_in].Init (Channel::CHOUT);
}

array< ::string> arg_= arg;
for (int j= 0; j < N (arg); j++)
for (int i= 0; i < n_in; i++)
if (fd_in[i] < 0) {
arg_[j]= replace (arg_[j], "$%" * as_string (i),
as_string (_get_osfhandle (ch[i].getPipe ())));
arg_[j]= replace (arg_[j], "$$" * as_string (i),
as_string (ch[i].getPipe ()));
}
array<char*> _arg;
for (int j= 0; j < N (arg_); j++)
_arg << as_charp (arg_[j]);
_arg << (char*) NULL;

spawn_system process (ch, _arg[0], A (_arg));
for (int j= 0; j < N (arg_); j++)
tm_delete_array (_arg[j]);
if (!process.isRunning ()) {
return -1;
}
process.getpid () << LF;

// receive data from spawn process
// class string is not thread safe, use std::string instead
array<std::string> str (n_out);
for (int i= 0; i < n_out; i++)
ch[i + n_in].read (&str[i]);

// send data to spawn process
array<int> pos_in (n_in);
for (int i= 0; i < n_in; i++)
pos_in[i]= 0;
time_t last_wait_time= texmacs_time ();

bool busy;
do {
busy= false;
if (texmacs_time () - last_wait_time > 5000) { // FIXME?
last_wait_time= texmacs_time ();
_unix_system_warn (process.getpid (), which, "waiting spawn process");
}
for (int i= 0; i < n_in; i++) {
if (N (str_in[i]) > pos_in[i]) {
int m= min (ch[i].sz, N (str_in[i]) - pos_in[i]); // do not fill the
// pipe
int o= ch[i].write (&(str_in[i][pos_in[i]]), m);
if (o >= 0) {
pos_in[i]+= o;
if (N (str_in[i]) == pos_in[i]) ch[i].close ();
else busy= true;
}
}
}
} while (busy);

// wait for process
int wret= process.wait ();
for (int i= 0; i < n_out; ++i)
(*(str_out[i])) << ::string (str[i].data (), str[i].length ());
return (wret);
}

namespace sys_utils {

#ifndef SECURITY_WIN32
#define SECURITY_WIN32
#endif
#include <windef.h>

#include <basetsd.h>
#include <ntsecapi.h>
#include <secext.h>
#include <wtypesbase.h>

::string
mingw_get_username () {
const int MAX_LEN= 100;
WCHAR buffer[MAX_LEN];
DWORD len;

// This API must be called twice, otherwise it returns an empty use name
GetUserNameExW (NameDisplay, buffer, &len);
GetUserNameExW (NameDisplay, buffer, &len);

if (len == 0) return ::string ("");
else return ::string (nowide::narrow (buffer).c_str ());
}
} // namespace sys_utils
26 changes: 26 additions & 0 deletions Plugins/Windows/mingw_sys_utils.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@

/******************************************************************************
* MODULE : mingw_sys_utils.hpp
* DESCRIPTION: external command handling
* COPYRIGHT : (C) 2015 Denis RAUX
*******************************************************************************
* This software falls under the GNU general public license version 3 or later.
* It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
* in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
******************************************************************************/

#ifndef MINGW_SYS_UTILS_H
#define MINGW_SYS_UTILS_H

#include "array.hpp"
#include "string.hpp"

int mingw_system (array< ::string> arg, array<int> fd_in,
array< ::string> str_in, array<int> fd_out,
array< ::string*> str_out);

namespace sys_utils {
::string mingw_get_username ();
}

#endif // defined MINGW_SYS_UTILS_H
140 changes: 140 additions & 0 deletions Plugins/Windows/spawn.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@

/******************************************************************************
* MODULE : spawn.cpp
* DESCRIPTION: external command handling
* COPYRIGHT : (C) 2015 Denis RAUX
*******************************************************************************
* This software falls under the GNU general public license version 3 or later.
* It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
* in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
******************************************************************************/

#include "spawn.hpp"
#include "array.hpp"
#include <errno.h>
#include <windows.h>

Channel::Channel (int s) : sz (s) {
origin = -1;
saved = -1;
fd = -1;
toBeClosed= -1;
str = NULL;
tid = 0;
}

void
Channel::Init (Direction d) {
int pp[2];
if (_pipe (pp, sz, O_NOINHERIT | _O_BINARY) == 0) {
int pr[2];
if (_pipe (pr, sz, _O_BINARY) == 0) {
_close (pr[d]);
_dup2 (pp[otherDirection (d)], pr[otherDirection (d)]);
_close (pp[otherDirection (d)]);
fd = pp[d];
toBeClosed= pr[otherDirection (d)];
}
else _close (pp[d]);
_close (pp[otherDirection (d)]);
}
}

void
Channel::Init (int _fd, Direction d) {
int pp[2];
origin= _fd;
if (_pipe (pp, sz, O_NOINHERIT | _O_BINARY) == 0) {
fd = pp[d];
toBeClosed= pp[otherDirection (d)];
}
else origin= -1;
}

void
Channel::redirect () {
if (origin < 0) return;
saved= _dup (origin);
_dup2 (toBeClosed, origin);
}

void
Channel::read (std::string* _str) {
str= _str;
tid= _beginthreadex (NULL, 0, bkgread, this, 0, NULL);
}

void
Channel::close () {
if (fd >= 0) {
_close (fd);
fd= -1;
}
}

void
Channel::closeUnused () {
if (toBeClosed >= 0) {
_close (toBeClosed);
toBeClosed= -1;
}
restore ();
}

void
Channel::wait () {
if (tid && WaitForSingleObject ((HANDLE) tid, 5000) == 0 &&
CloseHandle ((HANDLE) tid))
tid= 0;
}

void
Channel::restore () {
if (saved >= 0) {
_dup2 (saved, origin);
_close (saved);
saved= -1;
}
}

Channel::~Channel () {
closeUnused ();
close ();
if (tid) {
TerminateThread ((HANDLE) tid, -99);
CloseHandle ((HANDLE) tid);
}
}

unsigned
bkgread (void* thatv) {
char buf[1024];
int cnt;
Channel* that= (Channel*) thatv;
do {
cnt= _read (that->fd, buf, sizeof (buf));
if (cnt > 0) *(that->str)+= std::basic_string<char> (buf, cnt);
else if (cnt == 0) that->close ();
} while (cnt > 0);
return (cnt);
}

spawn_system::spawn_system (array<Channel>& ch, char* name,
const char* const* args)
: channel (ch) {
for (int i= 0; i < N (channel); ++i)
channel[i].redirect ();
pid= _spawnvp (_P_NOWAIT, name, args);
for (int i= 0; i < N (channel); ++i)
channel[i].closeUnused ();
}

int
spawn_system::wait () {
int ret;
if (pid > 0) ret= _cwait (&ret, pid, 0) == -1 ? errno : ret;
else ret= EINVAL;
for (int i= 0; i < N (channel); ++i)
channel[i].wait ();
return (ret);
}
63 changes: 63 additions & 0 deletions Plugins/Windows/spawn.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@

/******************************************************************************
* MODULE : spawn.hpp
* DESCRIPTION: external command handling
* COPYRIGHT : (C) 2015 Gregoire LECERF, Denis RAUX
*******************************************************************************
* This software falls under the GNU general public license version 3 or later.
* It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
* in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
******************************************************************************/

#include "array.hpp"

#include <fcntl.h>
#include <io.h>
#include <process.h>
#include <string>

__stdcall unsigned bkgread (void*);

class Channel {
public:
friend unsigned int bkgread (void*);
enum Direction { CHOUT= 0, CHIN= 1 };
Channel (int s= 2048);
void Init (int fd, Direction d);
void Init (Direction d);
void redirect ();
inline int getPipe () const { return (toBeClosed); }
void read (std::string* str);
inline int write (void* data, int lenght) {
return (_write (fd, data, lenght));
}
void close ();
void closeUnused ();
void wait ();
~Channel ();
const int sz;

private:
inline enum Direction otherDirection (Direction t) {
return (t == CHOUT ? CHIN : CHOUT);
}
int toBeClosed;
int origin;
int saved;
int fd;
std::string* str;
uintptr_t tid;
void restore ();
};

class spawn_system {
public:
spawn_system (array<Channel>& ch, char* name, const char* const* args);
inline int getpid () { return (pid); }
int wait ();
inline bool isRunning () { return (pid ? true : false); }

private:
intptr_t pid;
array<Channel>& channel;
};
Loading
Loading