Skip to content

Commit f947824

Browse files
committed
added dynamic resolution of executables
1 parent c691b86 commit f947824

5 files changed

Lines changed: 327 additions & 4 deletions

File tree

TODO

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,14 @@
1-
falls sysopen nicht zu viel code ist, rüberkopieren und tiny_io als dep für beide plattformen verwenden
1+
funktion zum auflösen eines relativen pfad auf einen absoluten pafd. sowohl für unix als auch für windows. "inspiration" von cruby holen
2+
3+
https://github.com/ruby/ruby/blob/202bbda2bf5f25343e286099140fb9282880ecba/dln_find.c
4+
dln_find_exe_r
5+
6+
wenn fertig eingebunden und getestet seb schreiben, damit der pull request schreiben kann..
7+
8+
mruby-io
9+
grundsätzlich mruby-io auf einen ähnlichen stand bringen wie mruby process, heisst alles das, was noch nicht für windows funktioniert, für windows zum funktionieren bringen
10+
wenn bei mruby-io als dependency mruby-process drin ist, das auf unseren mruby-process fork windows branch ändern.
11+
12+
pipes, den sysopenmock den ich gemacht habe
13+
14+
für die CI systeme configurieren

src/dln.c

Lines changed: 291 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,291 @@
1+
2+
#include "mruby.h"
3+
#define dln_warning mrb_warn
4+
#define dln_warning_arg
5+
6+
//#include "dln.h"
7+
8+
#include <stdlib.h>
9+
#include <strings.h>
10+
#include <stdio.h>
11+
#include <string.h>
12+
#include <unistd.h>
13+
14+
#if defined(_WIN32)
15+
//#include "missing/file.h"
16+
#endif
17+
18+
#include <sys/types.h>
19+
#include <sys/stat.h>
20+
21+
#ifndef S_ISDIR
22+
# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
23+
#endif
24+
25+
26+
27+
28+
// TODO makros weg, wrong usage. blergh
29+
#ifndef PATH_ENV
30+
#define PATH_ENV "path"
31+
#endif
32+
#ifndef PATH_SEP
33+
#define PATH_SEP ";"
34+
#endif
35+
36+
#if !defined(_WIN32) && !HAVE_DECL_GETENV
37+
char *getenv();
38+
#endif
39+
40+
static char *dln_find_1(const char *fname, const char *path, char *buf, size_t size, int exe_flag /*DLN_FIND_EXTRA_ARG_DECL*/);
41+
char* dln_find_exe_r(const char *fname, const char *path, char *buf, size_t size /*DLN_FIND_EXTRA_ARG_DECL*/);
42+
char* dln_find_file_r(const char *fname, const char *path, char *buf, size_t size /* DLN_FIND_EXTRA_ARG_DECL*/);
43+
44+
45+
46+
char*
47+
dln_find_exe_r(const char *fname, const char *path, char *buf, size_t size /*DLN_FIND_EXTRA_ARG_DECL*/)
48+
{
49+
char *envpath = 0;
50+
if (!path) {
51+
path = getenv(PATH_ENV);
52+
if (path)
53+
path = envpath = strdup(path);
54+
}
55+
56+
if (!path) {
57+
path =
58+
"/usr/local/bin" PATH_SEP
59+
"/usr/ucb" PATH_SEP
60+
"/usr/bin" PATH_SEP
61+
"/bin" PATH_SEP
62+
".";
63+
}
64+
buf = dln_find_1(fname, path, buf, size, 1 /*DLN_FIND_EXTRA_ARG*/);
65+
if (envpath)
66+
free(envpath);
67+
return buf;
68+
}
69+
70+
char *
71+
dln_find_file_r(const char *fname, const char *path, char *buf, size_t size
72+
/*DLN_FIND_EXTRA_ARG_DECL*/)
73+
{
74+
if (!path) path = ".";
75+
return dln_find_1(fname, path, buf, size, 0 /*DLN_FIND_EXTRA_ARG*/);
76+
}
77+
78+
static char *
79+
dln_find_1(const char *fname, const char *path, char *fbuf, size_t size,
80+
int exe_flag /* non 0 if looking for executable. */
81+
/*DLN_FIND_EXTRA_ARG_DECL*/)
82+
{
83+
register const char *dp;
84+
register const char *ep;
85+
register char *bp;
86+
struct stat st;
87+
size_t i, fnlen, fspace;
88+
89+
90+
#ifdef DOSISH
91+
static const char extension[][5] = {
92+
EXECUTABLE_EXTS,
93+
};
94+
size_t j;
95+
int is_abs = 0, has_path = 0;
96+
const char *ext = 0;
97+
#endif
98+
99+
100+
101+
const char *p = fname;
102+
103+
static const char pathname_too_long[] = "openpath: pathname too long (ignored)\n\
104+
\tDirectory \"%.*s\"%s\n\tFile \"%.*s\"%s\n";
105+
/*#define PATHNAME_TOO_LONG() dln_warning(dln_warning_arg pathname_too_long, \
106+
((bp - fbuf) > 100 ? 100 : (int)(bp - fbuf)), fbuf, \
107+
((bp - fbuf) > 100 ? "..." : ""), \
108+
(fnlen > 100 ? 100 : (int)fnlen), fname, \
109+
(fnlen > 100 ? "..." : ""))*/
110+
111+
#define RETURN_IF(expr) if (expr) return (char *)fname;
112+
113+
RETURN_IF(!fname);
114+
fnlen = strlen(fname);
115+
if (fnlen >= size) {
116+
/*dln_warning(dln_warning_arg
117+
"openpath: pathname too long (ignored)\n\tFile \"%.*s\"%s\n",
118+
(fnlen > 100 ? 100 : (int)fnlen), fname,
119+
(fnlen > 100 ? "..." : ""));*/
120+
return NULL;
121+
}
122+
123+
124+
#ifdef DOSISH
125+
# ifndef CharNext
126+
# define CharNext(p) ((p)+1)
127+
# endif
128+
# ifdef DOSISH_DRIVE_LETTER
129+
if (((p[0] | 0x20) - 'a') < 26 && p[1] == ':') {
130+
p += 2;
131+
is_abs = 1;
132+
}
133+
# endif
134+
switch (*p) {
135+
case '/': case '\\':
136+
is_abs = 1;
137+
p++;
138+
}
139+
has_path = is_abs;
140+
while (*p) {
141+
switch (*p) {
142+
case '/': case '\\':
143+
has_path = 1;
144+
ext = 0;
145+
p++;
146+
break;
147+
case '.':
148+
ext = p;
149+
p++;
150+
break;
151+
default:
152+
p = CharNext(p);
153+
}
154+
}
155+
if (ext) {
156+
for (j = 0; STRCASECMP(ext, extension[j]); ) {
157+
if (++j == sizeof(extension) / sizeof(extension[0])) {
158+
ext = 0;
159+
break;
160+
}
161+
}
162+
}
163+
ep = bp = 0;
164+
printf("returned at %s", "something?");
165+
if (!exe_flag) {
166+
printf("returned at %s", "exe_flag?");
167+
RETURN_IF(is_abs);
168+
printf("nope\n");
169+
}
170+
else if (has_path) {
171+
printf("returned at %s", "if ext?");
172+
RETURN_IF(ext);
173+
printf("nope\n");
174+
i = p - fname;
175+
if (i + 1 > size) goto toolong;
176+
fspace = size - i - 1;
177+
bp = fbuf;
178+
ep = p;
179+
printf("ep is here %s\n", ep);
180+
memcpy(fbuf, fname, i + 1);
181+
goto needs_extension;
182+
}
183+
p = fname;
184+
#endif
185+
186+
187+
if (*p == '.' && *++p == '.') ++p;
188+
RETURN_IF(*p == '/');
189+
RETURN_IF(exe_flag && strchr(fname, '/'));
190+
191+
#undef RETURN_IF
192+
193+
for (dp = path;; dp = ++ep) {
194+
register size_t l;
195+
196+
/* extract a component */
197+
ep = strchr(dp, PATH_SEP[0]);
198+
if (ep == NULL){
199+
ep = dp+strlen(dp);
200+
}
201+
/* find the length of that component */
202+
l = ep - dp;
203+
bp = fbuf;
204+
fspace = size - 2;
205+
if (l > 0) {
206+
/*
207+
** If the length of the component is zero length,
208+
** start from the current directory. If the
209+
** component begins with "~", start from the
210+
** user's $HOME environment variable. Otherwise
211+
** take the path literally.
212+
*/
213+
if (*dp == '~' && (l == 1 ||
214+
#if defined(DOSISH)
215+
dp[1] == '\\' ||
216+
#endif
217+
dp[1] == '/')) {
218+
219+
char *home;
220+
221+
home = getenv("HOME");
222+
if (home != NULL) {
223+
i = strlen(home);
224+
if (fspace < i)
225+
goto toolong;
226+
fspace -= i;
227+
memcpy(bp, home, i);
228+
bp += i;
229+
}
230+
dp++;
231+
l--;
232+
}
233+
if (l > 0) {
234+
if (fspace < l)
235+
goto toolong;
236+
fspace -= l;
237+
memcpy(bp, dp, l);
238+
bp += l;
239+
}
240+
241+
/* add a "/" between directory and filename */
242+
if (ep[-1] != '/')
243+
*bp++ = '/';
244+
}
245+
246+
/* now append the file name */
247+
i = fnlen;
248+
if (fspace < i) {
249+
toolong:
250+
printf("Pathname is too long \n" );//PATHNAME_TOO_LONG();
251+
goto next;
252+
}
253+
fspace -= i;
254+
memcpy(bp, fname, i + 1);
255+
256+
#if defined(DOSISH)
257+
if (exe_flag && !ext) {
258+
needs_extension:
259+
for (j = 0; j < sizeof(extension) / sizeof(extension[0]); j++) {
260+
if (fspace < strlen(extension[j])) {
261+
PATHNAME_TOO_LONG();
262+
continue;
263+
}
264+
strlcpy(bp + i, extension[j], fspace);
265+
if (stat(fbuf, &st) == 0){
266+
return fbuf;
267+
}
268+
}
269+
goto next;
270+
}
271+
#endif
272+
273+
#ifndef S_ISREG
274+
# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
275+
#endif
276+
if (stat(fbuf, &st) == 0 && S_ISREG(st.st_mode)) {
277+
if (exe_flag == 0){
278+
return fbuf;
279+
}
280+
/* looking for executable */
281+
if (access(fbuf, X_OK) == 0) return fbuf;
282+
}
283+
next:
284+
/* if not, and no other alternatives, life is bleak */
285+
if (*ep == '\0') {
286+
return NULL;
287+
}
288+
289+
/* otherwise try the next component in the search path */
290+
}
291+
}

src/internal.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "mruby/hash.h"
2828
#include "mruby/array.h"
2929
#include "mruby/string.h"
30+
#include "dln.c"
3031

3132

3233

@@ -86,6 +87,7 @@ mrb_execarg_fill(mrb_state *mrb, mrb_value env, mrb_value *argv, mrb_int argc, m
8687
char **result;
8788
char *shell;
8889
const char *tCmd;
90+
char fbuf[/*MAXPATHLEN*/80]; // TODO
8991
mrb_value argv0 = mrb_nil_value();
9092

9193
ai = mrb_gc_arena_save(mrb);
@@ -112,9 +114,13 @@ mrb_execarg_fill(mrb_state *mrb, mrb_value env, mrb_value *argv, mrb_int argc, m
112114
argc = 3;
113115
result = (char **)mrb_malloc(mrb, sizeof(char *) * (argc + 1));
114116

117+
118+
119+
120+
115121
#if defined(__APPLE__) || defined(__linux__)
116122
shell = getenv("SHELL");
117-
if (!shell) shell = strdup("/bin/sh");
123+
if (!shell) shell = strdup(dln_find_exe_r("sh", 0, fbuf, sizeof(fbuf)));
118124
result[1] = strdup("-c");
119125
#else
120126
shell = getenv("ComSpec");
@@ -129,7 +135,7 @@ mrb_execarg_fill(mrb_state *mrb, mrb_value env, mrb_value *argv, mrb_int argc, m
129135

130136
#if defined(__APPLE__) || defined(__linux__)
131137
if (result[0][0] != '/') {
132-
argv0 = mrb_str_new(mrb, "/bin/", 5);
138+
argv0 = mrb_str_new(mrb, "/bin/", 5); //TODO redundand?
133139
}
134140
#else
135141
if (result[0][1] != ':') {

src/process.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "mruby/error.h"
2828

2929
#include "internal.c"
30+
3031
#include "status.c"
3132
#include "signal.c"
3233

test/process.rb

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ def assert_windows(*args, &block)
138138
assert_equal var, read('tmp/spawn.txt')
139139
end
140140

141-
# TODO: More tests for edge cases!
141+
# TODO: More tests for edge cases! whatif no valid pipe,
142142
assert('Process.spawn', 'pipe') do
143143
begin
144144
var = ENV['RAND']
@@ -159,6 +159,18 @@ def assert_windows(*args, &block)
159159
end
160160
end
161161

162+
assert('Process.spawn', 'pipe error') do
163+
begin
164+
pip = IO.sysopen('tmp/pipe_error.txt', 'w')
165+
pid = spawn("ls -asdw", err: pip)
166+
167+
wait_for_pid(pid)
168+
assert_equal "ls: option requires an argument -- 'w'\nTry 'ls --help' for more information.", read('tmp/pipe_error.txt')
169+
ensure
170+
IO._sysclose(pip) if OS.posix?
171+
end
172+
end
173+
162174
assert('Process.exec', 'invalid signatures') do
163175
assert_raise(ArgumentError) { exec }
164176
assert_raise(TypeError) { exec 123 }

0 commit comments

Comments
 (0)