File: file.fth

package info (click to toggle)
cloc 2.06-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 8,064 kB
  • sloc: perl: 30,146; cpp: 1,219; python: 623; ansic: 334; asm: 267; makefile: 244; sh: 186; sql: 144; java: 136; ruby: 111; cs: 104; pascal: 52; lisp: 50; haskell: 35; f90: 35; cobol: 35; objc: 25; php: 22; javascript: 15; fortran: 9; ml: 8; xml: 7; tcl: 2
file content (161 lines) | stat: -rw-r--r-- 4,757 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
\ https://github.com/philburk/pforth/fth/file.fth
\ READ-LINE and WRITE-LINE
\
\ This code is part of pForth.
\
\ The pForth software code is dedicated to the public domain,
\ and any third party may reproduce, distribute and modify
\ the pForth software code or any derivative works thereof
\ without any compensation or license.  The pForth software
\ code is provided on an "as is" basis without any warranty
\ of any kind, including, without limitation, the implied
\ warranties of merchantability and fitness for a particular
\ purpose and their equivalents under the laws of any jurisdiction.

private{

10 constant \N
13 constant \R

\ Unread one char from file FILEID.
: UNREAD { fileid -- ior }
    fileid file-position          ( ud ior )
    ?dup
    IF   nip nip \ IO error
    ELSE 1 s>d d- fileid reposition-file
    THEN
;

\ Read the next available char from file FILEID and if it is a \n then
\ skip it; otherwise unread it.  IOR is non-zero if an error occured.
\ C-ADDR is a buffer that can hold at least one char.
: SKIP-\N { c-addr fileid -- ior }
    c-addr 1 fileid read-file     ( u ior )
    ?dup
    IF \ Read error?
        nip
    ELSE                          ( u )
        0=
        IF \ End of file?
            0
        ELSE
            c-addr c@ \n =        ( is-it-a-\n? )
            IF   0
            ELSE fileid unread
            THEN
        THEN
    THEN
;

\ This is just s\" \n" but s\" isn't yet available.
create (LINE-TERMINATOR) \n c,
: LINE-TERMINATOR ( -- c-addr u ) (line-terminator) 1 ;

\ Standard throw code
\ See: http://lars.nocrew.org/forth2012/exception.html#table:throw
-72 constant THROW_RENAME_FILE

\ Copy the string C-ADDR/U1 to C-ADDR2 and append a NUL.
: PLACE-CSTR  ( c-addr1 u1 c-addr2 -- )
    2dup 2>r          ( c-addr1 u1 c-addr2 )  ( r: u1 c-addr2 )
    swap cmove        ( ) ( r: u1 c-addr2 )
    0 2r> + c!        ( )
;

: MULTI-LINE-COMMENT ( "comment<rparen>" -- )
    BEGIN
        >in @ ')' parse         ( >in c-addr len )
        nip + >in @ =           ( delimiter-not-found? )
    WHILE                       ( )
        refill 0= IF EXIT THEN  ( )
    REPEAT
;

}private

\ This treats \n, \r\n, and \r as line terminator.  Reading is done
\ one char at a time with READ-FILE hence READ-FILE should probably do
\ some form of buffering for good efficiency.
: READ-LINE ( c-addr u1 fileid -- u2 flag ior )
    { a u f }
    u 0 ?DO
        a i chars + 1 f read-file                                  ( u ior' )
        ?dup IF nip i false rot UNLOOP EXIT THEN \ Read error?     ( u )
        0= IF i i 0<> 0 UNLOOP EXIT THEN         \ End of file?    ( )
        a i chars + c@
        CASE
            \n OF i true 0 UNLOOP EXIT ENDOF
            \r OF
                \ Detect \r\n
                a i chars + f skip-\n                              ( ior )
                ?dup IF i false rot UNLOOP EXIT THEN \ IO Error?   ( )
                i true 0 UNLOOP EXIT
	    ENDOF
        ENDCASE
    LOOP
    \ Line doesn't fit in buffer
    u true 0
;

: WRITE-LINE ( c-addr u fileid -- ior )
    { f }
    f write-file                  ( ior )
    ?dup
    IF \ IO error
    ELSE line-terminator f write-file
    THEN
;

: RENAME-FILE ( c-addr1 u1 c-addr2 u2 -- ior )
    { a1 u1 a2 u2 | new }
    \ Convert the file-names to C-strings by copying them after HERE.
    a1 u1 here place-cstr
    here u1 1+ chars + to new
    a2 u2 new place-cstr
    here new (rename-file) 0=
    IF 0
    ELSE throw_rename_file
    THEN
;

\ A limit used to perform a sanity check on the size argument for
\ RESIZE-FILE.
2variable RESIZE-FILE-LIMIT
10000000 0 resize-file-limit 2!  \ 10MB is somewhat arbitrarily chosen

: RESIZE-FILE ( ud fileid -- ior )
    -rot 2dup resize-file-limit 2@ d>             ( fileid ud big? )
    IF
        ." Argument (" 0 d.r ." ) is larger then RESIZE-FILE-LIMIT." cr
        ." (You can increase RESIZE-FILE-LIMIT with 2!)" cr
        abort
    ELSE
        rot (resize-file)
    THEN
;

: (  ( "comment<rparen>"  -- )
    source-id
    CASE
        -1 OF postpone ( ENDOF
        0  OF postpone ( ENDOF
        \ for input from files
        multi-line-comment
    ENDCASE
; immediate

\ We basically try to open the file in read-only mode.  That seems to
\ be the best that we can do with ANSI C.  If we ever want to do
\ something more sophisticated, like calling access(2), we must create
\ a proper primitive.  (OTOH, portable programs can't assume much
\ about FILE-STATUS and non-portable programs could create a custom
\ function for access(2).)
: FILE-STATUS ( c-addr u -- 0 ior )
    r/o bin open-file           ( fileid ior1 )
    ?dup
    IF   nip 0 swap             ( 0 ior1 )
    ELSE close-file 0 swap      ( 0 ior2 )
    THEN
;

privatize