Skip to content

Commit b836603

Browse files
committed

File tree

7 files changed

+150
-88
lines changed

7 files changed

+150
-88
lines changed

src/boot/natives.reb

+3-6
Original file line numberDiff line numberDiff line change
@@ -106,12 +106,6 @@ continue: native [
106106
{Throws control back to top of loop.}
107107
]
108108

109-
;dir?: native [
110-
; {Returns true if file is a directory.}
111-
; file [any-string! none!]
112-
; /any {Allow * or ? wildcards for directory}
113-
;]
114-
115109
;disarm: native [
116110
; {(Deprecated - not needed) Converts error to an object. Other types not modified.}
117111
; error [any-type!]
@@ -706,6 +700,9 @@ change-dir: native [
706700
path [file!]
707701
]
708702

703+
;dir?: in %n-io.c
704+
;wildcard?: in %n-io.c
705+
709706
;-- Series Natives
710707

711708
first: native [

src/core/n-io.c

+53
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,59 @@ static REBSER *Read_All_File(char *fname)
468468
return R_RET;
469469
}
470470

471+
// Blog: http://www.rebol.net/cgi-bin/r3blog.r?view=0319
472+
/***********************************************************************
473+
**
474+
*/ REBNATIVE(dirq)
475+
/*
476+
// dir?: native [
477+
// "Returns TRUE if the value looks like a directory spec (ends with a slash (or backslash))."
478+
// target [file! url! none!]
479+
// /check "If the file is a directory on local storage (don't have to end with a slash)"
480+
// ]
481+
***********************************************************************/
482+
{
483+
REBVAL *path = D_ARG(1);
484+
REBINT len;
485+
REBSER *ser;
486+
REBREQ file;
487+
REBUNI ch;
488+
489+
if (!ANY_STR(path) || VAL_LEN(path) == 0) return R_FALSE;
490+
491+
if (D_REF(2)) {
492+
// use OS check if path really exists and is a directory
493+
if (IS_FILE(path)) {
494+
CLEARS(&file);
495+
ser = Value_To_OS_Path(path, TRUE);
496+
file.file.path = (REBCHR*)(ser->data);
497+
file.device = RDI_FILE;
498+
len = OS_DO_DEVICE(&file, RDC_QUERY);
499+
FREE_SERIES(ser);
500+
if (len == DR_DONE && GET_FLAG(file.modes, RFM_DIR)) return R_TRUE;
501+
}
502+
}
503+
// without OS check
504+
ch = GET_ANY_CHAR(VAL_SERIES(path), VAL_TAIL(path)-1);
505+
if (ch == '/' || ch == '\\') return R_TRUE;
506+
507+
return R_FALSE;
508+
}
509+
510+
/***********************************************************************
511+
**
512+
*/ REBNATIVE(wildcardq)
513+
/*
514+
// wildcard?: native [
515+
// "Return true if file contains wildcard chars (* or ?)"
516+
// path [file!]
517+
// ]
518+
***********************************************************************/
519+
{
520+
REBVAL *path = D_ARG(1);
521+
REBCNT index = Find_Str_Wild(VAL_SERIES(path), VAL_INDEX(path), VAL_TAIL(path));
522+
return index == NOT_FOUND ? R_FALSE : R_TRUE;
523+
}
471524

472525
/***********************************************************************
473526
**

src/core/p-dir.c

+8-70
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
// Special policy: Win32 does not wanting tail slash for dir info
3333
#define REMOVE_TAIL_SLASH (1<<10)
3434

35+
#define WILD_PATH(p) (Find_Str_Wild(VAL_SERIES(p), VAL_INDEX(p), VAL_TAIL(p)) != NOT_FOUND)
36+
3537

3638
/***********************************************************************
3739
**
@@ -78,79 +80,10 @@
7880
Set_Series(REB_FILE, Append_Value(files), name);
7981
}
8082

81-
if (result < 0 && dir->error != -RFE_OPEN_FAIL
82-
&& (FIND_CHR(dir->file.path, '*') || FIND_CHR(dir->file.path, '?')))
83-
result = 0; // no matches found, but not an error
84-
8583
return result;
8684
}
8785

8886

89-
#ifdef REMOVED
90-
// It's problematic. See blog. Moved to mezz.
91-
92-
/***********************************************************************
93-
**
94-
*/ REBNATIVE(dirq)
95-
/*
96-
** Refinements:
97-
** /any -- allow * and ? wildcards
98-
**
99-
** Patterns:
100-
** abc/ is true
101-
** abc/*.reb is true
102-
** abc/?.reb is true
103-
** abc - ask the file system
104-
**
105-
***********************************************************************/
106-
{
107-
REBVAL *path = D_ARG(1);
108-
REBINT len;
109-
REBINT i;
110-
REBCNT dot;
111-
REBUNI c;
112-
REBSER *ser = VAL_SERIES(path);
113-
114-
if (!ANY_STR(path)) return R_FALSE;
115-
116-
len = (REBINT)VAL_LEN(path);
117-
if (len == 0) return R_FALSE;
118-
119-
// We cannot tell from above, so we must check it (if file):
120-
if (IS_FILE(path)) {
121-
REBSER *ser;
122-
REBREQ file;
123-
124-
CLEARS(&file);
125-
ser = Value_To_OS_Path(path, TRUE);
126-
file.file.path = (REBCHR*)(ser->data);
127-
file.device = RDI_FILE;
128-
len = OS_DO_DEVICE(&file, RDC_QUERY);
129-
FREE_SERIES(ser);
130-
if (len == DR_DONE && GET_FLAG(file.modes, RFM_DIR)) return R_TRUE;
131-
}
132-
133-
// Search backward for abc/, abc/def, abc/*, etc:
134-
len = (REBINT)VAL_LEN(path);
135-
dot = 0;
136-
for (i = 0; i < len; i++) {
137-
c = GET_ANY_CHAR(ser, VAL_TAIL(path)-1-i);
138-
if (c == '/' || c == '\\') {
139-
if (i == 0 || dot) return R_TRUE;
140-
break;
141-
}
142-
if (c == '.') {
143-
if (i == 0 || dot) dot = 1;
144-
}
145-
else dot = 0;
146-
if ((c == '*' || c == '?') && D_REF(2)) return R_TRUE;
147-
}
148-
149-
return R_FALSE;
150-
}
151-
#endif
152-
153-
15487
/***********************************************************************
15588
**
15689
*/ static void Init_Dir_Path(REBREQ *dir, REBVAL *path, REBINT wild, REBCNT policy)
@@ -268,7 +201,12 @@
268201
Set_Block(state, Make_Block(7)); // initial guess
269202
result = Read_Dir(&dir, VAL_SERIES(state));
270203
///OS_FREE(dir.file.path);
271-
if (result < 0) Trap_Port(RE_CANNOT_OPEN, port, dir.error);
204+
205+
// don't throw an error if the original path contains wildcard chars * or ?
206+
if (result < 0 && !(dir.error == (REBCNT)-RFE_OPEN_FAIL && WILD_PATH(path)) ) {
207+
Trap_Port(RE_CANNOT_OPEN, port, dir.error);
208+
}
209+
272210
*D_RET = *state;
273211
SET_NONE(state);
274212
} else {

src/core/s-find.c

+18
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,24 @@
569569
}
570570

571571

572+
/***********************************************************************
573+
**
574+
*/ REBCNT Find_Str_Wild(REBSER *ser, REBCNT index, REBCNT tail)
575+
/*
576+
** Returns index of first * or ? chars in series
577+
**
578+
***********************************************************************/
579+
{
580+
REBUNI ch;
581+
582+
for (; index < tail; index++) {
583+
ch = GET_ANY_CHAR(ser, index);
584+
if (ch == '*' || ch == '?') return index;
585+
}
586+
return NOT_FOUND;
587+
}
588+
589+
572590
#ifdef old
573591
/***********************************************************************
574592
**

src/mezz/base-files.reb

+3-10
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,6 @@ suffix?: func [
6262
]
6363
]
6464

65-
dir?: func [
66-
{Returns TRUE if the file or url ends with a slash (or backslash).}
67-
target [file! url!]
68-
][
69-
true? find "/\" last target
70-
]
71-
7265
dirize: func [
7366
{Returns a copy (always) of the path as a directory (ending slash).}
7467
path [file! string! url!]
@@ -87,9 +80,9 @@ make-dir: func [
8780
if empty? path [return path]
8881
if slash <> last path [path: dirize path]
8982

90-
if exists? path [
91-
if dir? path [return path]
92-
cause-error 'access 'cannot-open path
83+
switch exists? path [
84+
dir [return path]
85+
file [cause-error 'access 'cannot-open path]
9386
]
9487

9588
if any [not deep url? path] [

src/mezz/sys-ports.reb

+5-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,11 @@ make-port*: func [
2525
; The first job is to identify the scheme specified:
2626
case [
2727
file? spec [
28-
name: pick [dir file] dir? spec
28+
name: case [
29+
wildcard? spec ['dir]
30+
dir?/check spec [spec: dirize spec 'dir]
31+
true ['file]
32+
]
2933
spec: join [ref:] spec
3034
]
3135
url? spec [

src/tests/units/port-test.r3

+60-1
Original file line numberDiff line numberDiff line change
@@ -60,17 +60,73 @@ Rebol [
6060
d/size = none
6161
]
6262
delete %dir-606/
63+
64+
--test-- "make-dir/delete/exists? with path without a slash"
65+
;@@ https://github.com/Oldes/Rebol-issues/issues/499
66+
--assert %dir-606/ = make-dir %dir-606
67+
--assert not error? try [delete %dir-606]
68+
--assert not exists? %dir-606
69+
70+
--test-- "make-dir if file exists"
71+
;@@ https://github.com/Oldes/Rebol-issues/issues/1777
72+
--assert not error? try [write %issue-1777.txt "test"]
73+
--assert error? er: try [make-dir %issue-1777.txt/]
74+
--assert er/id = 'no-create
75+
--assert not error? try [delete %issue-1777.txt]
76+
77+
--test-- "open %."
78+
;@@ https://github.com/Oldes/Rebol-issues/issues/117
79+
--assert port? p: open %.
80+
--assert 'dir = p/scheme/name
81+
--assert 'dir = p/spec/scheme
82+
--assert %./ = p/spec/ref
83+
--assert port? close p
84+
85+
--test-- "open wildcard"
86+
;@@ https://github.com/Oldes/Rebol-issues/issues/158
87+
--assert all [
88+
port? p: try [open %*.r3]
89+
'dir = p/scheme/name
90+
'dir = p/spec/scheme
91+
%*.r3 = p/spec/ref
92+
port? close p
93+
]
94+
6395
--test-- "DIR?"
6496
;@@ https://github.com/Oldes/Rebol-issues/issues/602
6597
; dir? only checks if the last char is / or \
6698
--assert dir? %doesnotexists/
6799
--assert not dir? %doesnotexists
68100
--assert dir? %./
69101
--assert not dir? %.
102+
; dir?/check
103+
--assert not dir?/check %doesnotexists
104+
--assert dir?/check %.
105+
--assert dir?/check %./
106+
107+
--test-- "READ on existing dir-name"
108+
;@@ https://github.com/Oldes/Rebol-issues/issues/635
109+
;@@ https://github.com/Oldes/Rebol-issues/issues/1675
110+
;@@ https://github.com/Oldes/Rebol-issues/issues/2379
111+
--assert block? b1: read %.
112+
--assert block? b2: read %./
113+
--assert b1 = b2
114+
;@@ https://github.com/Oldes/Rebol-issues/issues/604
115+
--assert 'dir = exists? %.
116+
--assert 'dir = exists? %./
117+
70118
--test-- "READ on non-existing dir-name"
71119
;@@ https://github.com/Oldes/Rebol-issues/issues/500
72120
--assert error? e: try [read %carl-for-president/]
73121
--assert e/id = 'cannot-open
122+
123+
--test-- "READ wildcard"
124+
;@@ https://github.com/Oldes/Rebol-issues/issues/158
125+
--assert all [block? b: try [read %*.r3] not empty? b]
126+
--assert all [block? b: try [read %run-tests.?3] not empty? b]
127+
--assert all [block? b: try [read %units/files/*.r3] not empty? b]
128+
--assert all [block? b: try [read %*.xxx] empty? b]
129+
74130
--test-- "DELETE-DIR"
75131
;@@ https://github.com/Oldes/Rebol-issues/issues/1545
76132
--assert all [
@@ -79,6 +135,8 @@ Rebol [
79135
not error? delete-dir %units/temp-dir/
80136
not exists? %units/temp-dir/
81137
]
138+
if system/platform = 'Windows [
139+
;@@ it looks that on Linux there is no lock on opened file
82140
--assert all [
83141
all [
84142
not error? try [make-dir/deep %units/temp-dir/]
@@ -96,6 +154,7 @@ Rebol [
96154
not error? delete-dir %units/temp-dir/
97155
]
98156
]
157+
]
99158

100159
--test-- "RENAME dir"
101160
;@@ https://github.com/Oldes/Rebol-issues/issues/1533
@@ -262,7 +321,7 @@ if "true" <> get-env "CONTINUOUS_INTEGRATION" [
262321
;- don't do these tests on Travis CI
263322
===start-group=== "WHOIS scheme"
264323
--test-- "read WHOIS"
265-
--assert string? try [read whois://google.com]
324+
--assert string? probe try [read whois://google.com]
266325
--test-- "write WHOIS"
267326
--assert string? try [write whois://whois.nic.cz "seznam.cz"]
268327
===end-group===

0 commit comments

Comments
 (0)