-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[10_1] migrate basic windows files from mogan
- Loading branch information
Showing
6 changed files
with
466 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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
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 |
This file contains 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
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 |
This file contains 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
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); | ||
} |
This file contains 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
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; | ||
}; |
Oops, something went wrong.