10
10
import java .nio .file .Path ;
11
11
import java .nio .file .StandardOpenOption ;
12
12
import java .util .ArrayList ;
13
- import java .util .Arrays ;
14
13
import java .util .List ;
15
14
16
15
import org .perl6 .nqp .runtime .ExceptionHandling ;
@@ -20,8 +19,11 @@ public class FileHandle extends SyncHandle implements IIOSeekable, IIOLockable {
20
19
21
20
FileChannel fc ;
22
21
FileLock lock ;
22
+ private boolean truncate = false ;
23
+ private boolean create = false ;
24
+ private boolean append = false ;
23
25
24
- public static OpenOption [] resolveOpenMode (String mode ) {
26
+ public OpenOption [] resolveOpenMode (String mode ) {
25
27
if (mode .length () == 0 )
26
28
return null ;
27
29
@@ -52,6 +54,34 @@ public static OpenOption[] resolveOpenMode(String mode) {
52
54
default : return null ;
53
55
}
54
56
57
+ /* work around differences between Perl 6 and FileChannel.open */
58
+ List <OpenOption > optsToRemove = new ArrayList <OpenOption >();
59
+ if (opts .contains (StandardOpenOption .READ )) {
60
+ if (!opts .contains (StandardOpenOption .WRITE )) {
61
+ /* TRUNCATE_EXISTING is ignored when the file is opened only for reading. */
62
+ if (opts .contains (StandardOpenOption .TRUNCATE_EXISTING )) {
63
+ truncate = true ;
64
+ optsToRemove .add (StandardOpenOption .TRUNCATE_EXISTING );
65
+ }
66
+ /* CREATE is ignored when the file is opened only for reading. */
67
+ if (opts .contains (StandardOpenOption .CREATE )) {
68
+ create = true ;
69
+ optsToRemove .add (StandardOpenOption .CREATE );
70
+ }
71
+ }
72
+ /* APPEND may not be used in conjunction with READ. */
73
+ if (opts .contains (StandardOpenOption .APPEND )) {
74
+ append = true ;
75
+ optsToRemove .add (StandardOpenOption .APPEND );
76
+ }
77
+ }
78
+ /* APPEND may not be used in conjunction with TRUNCATE_EXISTING. */
79
+ else if (opts .contains (StandardOpenOption .TRUNCATE_EXISTING ) && opts .contains (StandardOpenOption .APPEND )) {
80
+ append = true ;
81
+ optsToRemove .add (StandardOpenOption .APPEND );
82
+ }
83
+ opts .removeAll (optsToRemove );
84
+
55
85
return opts .toArray (new OpenOption [opts .size ()]);
56
86
}
57
87
@@ -63,19 +93,12 @@ public FileHandle(ThreadContext tc, String filename, String mode) {
63
93
OpenOption [] opts = resolveOpenMode (mode );
64
94
if (opts == null )
65
95
ExceptionHandling .dieInternal (tc , "Unhandled file open mode '" + mode + "'" );
66
-
67
- // work around differences between Perl 6 and FileChannel.open
68
- if (Arrays .asList (opts ).contains (StandardOpenOption .READ ) && !Arrays .asList (opts ).contains (StandardOpenOption .WRITE )) {
69
- // TRUNCATE_EXISTING is ignored when the file is opened only for reading.
70
- if (Arrays .asList (opts ).contains (StandardOpenOption .TRUNCATE_EXISTING ))
71
- if (Files .exists (p ))
72
- Files .write (p , new byte [0 ]);
73
- // CREATE is ignored when the file is opened only for reading.
74
- if (Arrays .asList (opts ).contains (StandardOpenOption .CREATE ))
75
- if (!Files .exists (p ))
76
- Files .createFile (p );
77
- }
78
-
96
+ if (truncate )
97
+ if (Files .exists (p ))
98
+ Files .write (p , new byte [0 ]);
99
+ if (create )
100
+ if (!Files .exists (p ))
101
+ Files .createFile (p );
79
102
fc = FileChannel .open (p , opts );
80
103
chan = fc ;
81
104
setEncoding (tc , Charset .forName ("UTF-8" ));
@@ -84,6 +107,34 @@ public FileHandle(ThreadContext tc, String filename, String mode) {
84
107
}
85
108
}
86
109
110
+ public long write (ThreadContext tc , byte [] array ) {
111
+ if (append ) {
112
+ try {
113
+ fc .position (fc .size ());
114
+ } catch (IOException e ) {
115
+ throw ExceptionHandling .dieInternal (tc , e );
116
+ }
117
+ /* Reset readBuffer and eof after calling fc.position. */
118
+ readBuffer = null ;
119
+ eof = false ;
120
+ }
121
+ return super .write (tc , array );
122
+ }
123
+
124
+ public long print (ThreadContext tc , String s ) {
125
+ if (append ) {
126
+ try {
127
+ fc .position (fc .size ());
128
+ } catch (IOException e ) {
129
+ throw ExceptionHandling .dieInternal (tc , e );
130
+ }
131
+ /* Reset readBuffer and eof after calling fc.position. */
132
+ readBuffer = null ;
133
+ eof = false ;
134
+ }
135
+ return super .print (tc , s );
136
+ }
137
+
87
138
public void seek (ThreadContext tc , long offset , long whence ) {
88
139
try {
89
140
switch ((int )whence ) {
0 commit comments