relicense to 0BSD
[pforth] / fth / file.fth
... / ...
CommitLineData
1\ READ-LINE and WRITE-LINE
2\
3\ This code is part of pForth.
4\
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.
16
17private{
18
1910 constant \N
2013 constant \R
21
22\ Unread one char from file FILEID.
23: UNREAD { fileid -- ior }
24 fileid file-position ( ud ior )
25 ?dup
26 IF nip nip \ IO error
27 ELSE 1 s>d d- fileid reposition-file
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.
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 )
36 ?dup
37 IF \ Read error?
38 nip
39 ELSE ( u )
40 0=
41 IF \ End of file?
42 0
43 ELSE
44 c-addr c@ \n = ( is-it-a-\n? )
45 IF 0
46 ELSE fileid unread
47 THEN
48 THEN
49 THEN
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
56\ Standard throw code
57\ See: http://lars.nocrew.org/forth2012/exception.html#table:throw
58-72 constant THROW_RENAME_FILE
59
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
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
74;
75
76}private
77
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 )
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 )
86 0= IF i i 0<> 0 UNLOOP EXIT THEN \ End of file? ( )
87 a i chars + c@
88 CASE
89 \n OF i true 0 UNLOOP EXIT ENDOF
90 \r OF
91 \ Detect \r\n
92 a i chars + f skip-\n ( ior )
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
100;
101
102: WRITE-LINE ( c-addr u fileid -- ior )
103 { f }
104 f write-file ( ior )
105 ?dup
106 IF \ IO error
107 ELSE line-terminator f write-file
108 THEN
109;
110
111: RENAME-FILE ( c-addr1 u1 c-addr2 u2 -- ior )
112 { a1 u1 a2 u2 | new }
113 \ Convert the file-names to C-strings by copying them after HERE.
114 a1 u1 here place-cstr
115 here u1 1+ chars + to new
116 a2 u2 new place-cstr
117 here new (rename-file) 0=
118 IF 0
119 ELSE throw_rename_file
120 THEN
121;
122
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
139: ( ( "comment<rparen>" -- )
140 source-id
141 CASE
142 -1 OF postpone ( ENDOF
143 0 OF postpone ( ENDOF
144 \ for input from files
145 multi-line-comment
146 ENDCASE
147; immediate
148
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).)
155: FILE-STATUS ( c-addr u -- 0 ior )
156 r/o bin open-file ( fileid ior1 )
157 ?dup
158 IF nip 0 swap ( 0 ior1 )
159 ELSE close-file 0 swap ( 0 ior2 )
160 THEN
161;
162
163privatize