Skip to content

Commit

Permalink
[10_1] migrate basic windows files from mogan
Browse files Browse the repository at this point in the history
  • Loading branch information
Charonxin authored Aug 15, 2023
1 parent 07bf7a1 commit 704ee8a
Show file tree
Hide file tree
Showing 6 changed files with 466 additions and 0 deletions.
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

0 comments on commit 704ee8a

Please sign in to comment.