-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathIOHandle.java
More file actions
216 lines (183 loc) · 7.16 KB
/
IOHandle.java
File metadata and controls
216 lines (183 loc) · 7.16 KB
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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
package org.perlonjava.runtime.perlmodule;
import org.perlonjava.runtime.runtimetypes.*;
/**
* Java::System - Perl module for accessing IO::Handle internals
*/
public class IOHandle extends PerlModuleBase {
public IOHandle() {
super("IO::Handle", false);
}
public static void initialize() {
IOHandle ioHandle = new IOHandle();
try {
// Register all methods
ioHandle.registerMethod("ungetc", null);
ioHandle.registerMethod("_error", "*");
ioHandle.registerMethod("_clearerr", "*");
ioHandle.registerMethod("_sync", "*");
ioHandle.registerMethod("_blocking", "*;$");
ioHandle.registerMethod("_setbuf", "*$");
ioHandle.registerMethod("_setvbuf", "*$$$");
ioHandle.registerMethod("_untaint", "*");
ioHandle.registerMethod("_set_input_line_number", "*$");
} catch (NoSuchMethodException e) {
System.err.println("Warning: Missing IOHandle method: " + e.getMessage());
}
}
/**
* Call internal ungetc
*/
public static RuntimeList ungetc(RuntimeArray args, int ctx) {
if (args.size() != 2) {
throw new IllegalArgumentException("ungetc requires 2 arguments");
}
RuntimeIO fh = args.get(0).getRuntimeIO();
if (fh instanceof TieHandle) {
throw new PerlCompilerException("can't ungetc on tied handle");
}
RuntimeScalar arg1 = args.get(1);
// int c = arg1.toString().codePointAt(0);
int c = arg1.getInt();
fh.ioHandle.ungetc(c);
return arg1.getList();
}
/**
* Check if handle has experienced errors
*/
public static RuntimeList _error(RuntimeArray args, int ctx) {
if (args.size() != 1) {
throw new IllegalStateException("Bad number of arguments for _error");
}
RuntimeIO fh = RuntimeIO.getRuntimeIO(args.get(0));
if (fh == null || fh.ioHandle == null) {
return new RuntimeList(new RuntimeScalar(1)); // Invalid handle has error
}
// Check if there's an error in $!
String error = GlobalVariable.getGlobalVariable("main::!").toString();
return new RuntimeList(new RuntimeScalar(error.isEmpty() ? 0 : 1));
}
/**
* Clear error indicator
*/
public static RuntimeList _clearerr(RuntimeArray args, int ctx) {
if (args.size() != 1) {
throw new IllegalStateException("Bad number of arguments for _clearerr");
}
RuntimeIO fh = RuntimeIO.getRuntimeIO(args.get(0));
if (fh == null || fh.ioHandle == null) {
return new RuntimeList(new RuntimeScalar(-1));
}
// Clear $!
GlobalVariable.getGlobalVariable("main::!").set("");
return new RuntimeList(new RuntimeScalar(0));
}
/**
* Sync file's in-memory state with physical medium (fsync).
*
* <p>This synchronizes a file's in-memory state with that on the physical medium.
* It operates at the file descriptor level (like sysread, sysseek), not at the
* perlio API level. Data buffered at the perlio level must be flushed first
* with flush().</p>
*
* <p>Returns "0 but true" on success, undef on error or invalid handle.</p>
*
* @see <a href="https://perldoc.perl.org/IO::Handle#$io-%3Esync">IO::Handle->sync</a>
*/
public static RuntimeList _sync(RuntimeArray args, int ctx) {
if (args.size() != 1) {
throw new IllegalStateException("Bad number of arguments for _sync");
}
RuntimeIO fh = RuntimeIO.getRuntimeIO(args.get(0));
if (fh == null || fh.ioHandle == null) {
return new RuntimeList(); // undef for invalid handle
}
try {
// First flush any perlio-level buffered data
fh.flush();
// Now call sync() to force fsync on the file descriptor
RuntimeScalar result = fh.ioHandle.sync();
if (result.getBoolean()) {
// Return "0 but true" on success per Perl convention
return new RuntimeList(new RuntimeScalar("0 but true"));
} else {
return new RuntimeList(); // undef on error
}
} catch (Exception e) {
RuntimeIO.handleIOError("sync failed: " + e.getMessage());
return new RuntimeList(); // undef on error
}
}
/**
* Get/set blocking mode
*/
public static RuntimeList _blocking(RuntimeArray args, int ctx) {
if (args.size() < 1 || args.size() > 2) {
throw new IllegalStateException("Bad number of arguments for _blocking");
}
RuntimeIO fh = RuntimeIO.getRuntimeIO(args.get(0));
if (fh == null || fh.ioHandle == null) {
RuntimeIO.handleIOError("Bad filehandle");
return new RuntimeList();
}
// Get current blocking status (always true in JVM)
boolean currentBlocking = true;
if (args.size() == 2) {
// Setting blocking mode
boolean newBlocking = args.get(1).getBoolean();
if (!newBlocking) {
// Non-blocking I/O is not easily supported in JVM
RuntimeIO.handleIOError("Non-blocking I/O not supported");
return new RuntimeList();
}
}
return new RuntimeList(new RuntimeScalar(currentBlocking ? 1 : 0));
}
/**
* Set buffer (not implemented in JVM)
*/
public static RuntimeList _setbuf(RuntimeArray args, int ctx) {
if (args.size() != 2) {
throw new IllegalStateException("Bad number of arguments for _setbuf");
}
RuntimeIO.handleIOError("setbuf not implemented");
return new RuntimeList();
}
/**
* Set buffer with type (not implemented in JVM)
*/
public static RuntimeList _setvbuf(RuntimeArray args, int ctx) {
if (args.size() != 4) {
throw new IllegalStateException("Bad number of arguments for _setvbuf");
}
RuntimeIO.handleIOError("setvbuf not implemented");
return new RuntimeList();
}
/**
* Mark handle as taint-clean
*/
public static RuntimeList _untaint(RuntimeArray args, int ctx) {
if (args.size() != 1) {
throw new IllegalStateException("Bad number of arguments for _untaint");
}
RuntimeIO fh = RuntimeIO.getRuntimeIO(args.get(0));
if (fh == null || fh.ioHandle == null) {
return new RuntimeList(new RuntimeScalar(-1));
}
// In JVM, we don't have real taint checking, so just return success
return new RuntimeList(new RuntimeScalar(0));
}
/**
* Set input line number for handle
*/
public static RuntimeList _set_input_line_number(RuntimeArray args, int ctx) {
if (args.size() != 2) {
throw new IllegalStateException("Bad number of arguments for _set_input_line_number");
}
RuntimeIO fh = RuntimeIO.getRuntimeIO(args.get(0));
int lineNum = args.get(1).getInt();
if (fh != null) {
fh.currentLineNumber = lineNum;
}
return new RuntimeList();
}
}