relicense to 0BSD
[pforth] / fth / file.fth
CommitLineData
593eb738
HE
1\ READ-LINE and WRITE-LINE
2\
938d9dba 3\ This code is part of pForth.
593eb738 4\
1f99f95d
S
5\ Permission to use, copy, modify, and/or distribute this
6\ software for any purpose with or without fee is hereby granted.
7\
8\ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
9\ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
10\ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
11\ THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
12\ CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
13\ FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
14\ CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15\ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
593eb738
HE
16
17private{
18
938d9dba
HE
1910 constant \N
2013 constant \R
593eb738
HE
21
22\ Unread one char from file FILEID.
938d9dba
HE
23: UNREAD { fileid -- ior }
24 fileid file-position ( ud ior )
593eb738
HE
25 ?dup
26 IF nip nip \ IO error
938d9dba 27 ELSE 1 s>d d- fileid reposition-file
593eb738
HE
28 THEN
29;
30
31\ Read the next available char from file FILEID and if it is a \n then
32\ skip it; otherwise unread it. IOR is non-zero if an error occured.
938d9dba
HE
33\ C-ADDR is a buffer that can hold at least one char.
34: SKIP-\N { c-addr fileid -- ior }
35 c-addr 1 fileid read-file ( u ior )
aad4537d
HE
36 ?dup
37 IF \ Read error?
38 nip
39 ELSE ( u )
40 0=
41 IF \ End of file?
42 0
43 ELSE
938d9dba 44 c-addr c@ \n = ( is-it-a-\n? )
aad4537d 45 IF 0
938d9dba 46 ELSE fileid unread
aad4537d
HE
47 THEN
48 THEN
49 THEN
593eb738
HE
50;
51
52\ This is just s\" \n" but s\" isn't yet available.
53create (LINE-TERMINATOR) \n c,
54: LINE-TERMINATOR ( -- c-addr u ) (line-terminator) 1 ;
55
662a735a
HE
56\ Standard throw code
57\ See: http://lars.nocrew.org/forth2012/exception.html#table:throw
6f3de396
HE
58-72 constant THROW_RENAME_FILE
59
662a735a
HE
60\ Copy the string C-ADDR/U1 to C-ADDR2 and append a NUL.
61: PLACE-CSTR ( c-addr1 u1 c-addr2 -- )
62 2dup 2>r ( c-addr1 u1 c-addr2 ) ( r: u1 c-addr2 )
63 swap cmove ( ) ( r: u1 c-addr2 )
64 0 2r> + c! ( )
65;
66
fe6f537b
HE
67: MULTI-LINE-COMMENT ( "comment<rparen>" -- )
68 BEGIN
69 >in @ ')' parse ( >in c-addr len )
70 nip + >in @ = ( delimiter-not-found? )
71 WHILE ( )
72 refill 0= IF EXIT THEN ( )
73 REPEAT
fe6f537b
HE
74;
75
593eb738
HE
76}private
77
593eb738
HE
78\ This treats \n, \r\n, and \r as line terminator. Reading is done
79\ one char at a time with READ-FILE hence READ-FILE should probably do
80\ some form of buffering for good efficiency.
81: READ-LINE ( c-addr u1 fileid -- u2 flag ior )
aad4537d
HE
82 { a u f }
83 u 0 ?DO
84 a i chars + 1 f read-file ( u ior' )
85 ?dup IF nip i false rot UNLOOP EXIT THEN \ Read error? ( u )
938d9dba 86 0= IF i i 0<> 0 UNLOOP EXIT THEN \ End of file? ( )
aad4537d
HE
87 a i chars + c@
88 CASE
89 \n OF i true 0 UNLOOP EXIT ENDOF
90 \r OF
91 \ Detect \r\n
938d9dba 92 a i chars + f skip-\n ( ior )
aad4537d
HE
93 ?dup IF i false rot UNLOOP EXIT THEN \ IO Error? ( )
94 i true 0 UNLOOP EXIT
95 ENDOF
96 ENDCASE
97 LOOP
98 \ Line doesn't fit in buffer
99 u true 0
593eb738
HE
100;
101
102: WRITE-LINE ( c-addr u fileid -- ior )
aad4537d
HE
103 { f }
104 f write-file ( ior )
105 ?dup
106 IF \ IO error
107 ELSE line-terminator f write-file
108 THEN
593eb738
HE
109;
110
6f3de396
HE
111: RENAME-FILE ( c-addr1 u1 c-addr2 u2 -- ior )
112 { a1 u1 a2 u2 | new }
662a735a
HE
113 \ Convert the file-names to C-strings by copying them after HERE.
114 a1 u1 here place-cstr
6f3de396 115 here u1 1+ chars + to new
662a735a 116 a2 u2 new place-cstr
6f3de396
HE
117 here new (rename-file) 0=
118 IF 0
119 ELSE throw_rename_file
120 THEN
121;
122
0b1e2489
HE
123\ A limit used to perform a sanity check on the size argument for
124\ RESIZE-FILE.
1252variable RESIZE-FILE-LIMIT
12610000000 0 resize-file-limit 2! \ 10MB is somewhat arbitrarily chosen
127
128: RESIZE-FILE ( ud fileid -- ior )
129 -rot 2dup resize-file-limit 2@ d> ( fileid ud big? )
130 IF
131 ." Argument (" 0 d.r ." ) is larger then RESIZE-FILE-LIMIT." cr
132 ." (You can increase RESIZE-FILE-LIMIT with 2!)" cr
133 abort
134 ELSE
135 rot (resize-file)
136 THEN
137;
138
fe6f537b
HE
139: ( ( "comment<rparen>" -- )
140 source-id
141 CASE
142 -1 OF postpone ( ENDOF
143 0 OF postpone ( ENDOF
646bd2a8 144 \ for input from files
fe6f537b
HE
145 multi-line-comment
146 ENDCASE
147; immediate
148
8d2c2052
HE
149\ We basically try to open the file in read-only mode. That seems to
150\ be the best that we can do with ANSI C. If we ever want to do
151\ something more sophisticated, like calling access(2), we must create
152\ a proper primitive. (OTOH, portable programs can't assume much
153\ about FILE-STATUS and non-portable programs could create a custom
154\ function for access(2).)
f2087087 155: FILE-STATUS ( c-addr u -- 0 ior )
8d2c2052
HE
156 r/o bin open-file ( fileid ior1 )
157 ?dup
f2087087 158 IF nip 0 swap ( 0 ior1 )
8d2c2052
HE
159 ELSE close-file 0 swap ( 0 ior2 )
160 THEN
161;
162
593eb738 163privatize