9 static void ghostDestroy(void* g);
10 naGhostType naIOGhostType = { ghostDestroy, "iofile" };
12 static struct naIOGhost* ioghost(naRef r)
14 if(naGhost_type(r) == &naIOGhostType && IOGHOST(r)->handle)
15 return naGhost_ptr(r);
19 static naRef f_close(naContext c, naRef me, int argc, naRef* args)
21 struct naIOGhost* g = argc==1 ? ioghost(args[0]) : 0;
22 if(!g) naRuntimeError(c, "bad argument to close()");
23 if(g->handle) g->type->close(c, g->handle);
28 static naRef f_read(naContext c, naRef me, int argc, naRef* args)
30 struct naIOGhost* g = argc > 0 ? ioghost(args[0]) : 0;
31 naRef str = argc > 1 ? args[1] : naNil();
32 naRef len = argc > 2 ? naNumValue(args[2]) : naNil();
33 if(!g || !MUTABLE(str) || !IS_NUM(len))
34 naRuntimeError(c, "bad argument to read()");
35 if(naStr_len(str) < (int)len.num)
36 naRuntimeError(c, "string not big enough for read");
37 return naNum(g->type->read(c, g->handle, naStr_data(str),
41 static naRef f_write(naContext c, naRef me, int argc, naRef* args)
43 struct naIOGhost* g = argc > 0 ? ioghost(args[0]) : 0;
44 naRef str = argc > 1 ? args[1] : naNil();
45 if(!g || !IS_STR(str))
46 naRuntimeError(c, "bad argument to write()");
47 return naNum(g->type->write(c, g->handle, naStr_data(str),
51 static naRef f_seek(naContext c, naRef me, int argc, naRef* args)
53 struct naIOGhost* g = argc > 0 ? ioghost(args[0]) : 0;
54 naRef pos = argc > 1 ? naNumValue(args[1]) : naNil();
55 naRef whn = argc > 2 ? naNumValue(args[2]) : naNil();
56 if(!g || !IS_NUM(pos) || !IS_NUM(whn))
57 naRuntimeError(c, "bad argument to seek()");
58 g->type->seek(c, g->handle, (int)pos.num, (int)whn.num);
62 static naRef f_tell(naContext c, naRef me, int argc, naRef* args)
64 struct naIOGhost* g = argc==1 ? ioghost(args[0]) : 0;
66 naRuntimeError(c, "bad argument to tell()");
67 return naNum(g->type->tell(c, g->handle));
70 static naRef f_flush(naContext c, naRef me, int argc, naRef* args)
72 struct naIOGhost* g = argc==1 ? ioghost(args[0]) : 0;
74 naRuntimeError(c, "bad argument to flush()");
75 g->type->flush(c, g->handle);
79 static void ghostDestroy(void* g)
81 struct naIOGhost* io = (struct naIOGhost*)g;
82 io->type->destroy(io->handle);
86 ////////////////////////////////////////////////////////////////////////
87 // stdio library implementation below:
89 static void ioclose(naContext c, void* f)
92 if(fclose(f) != 0 && c) naRuntimeError(c, strerror(errno));
95 static int ioread(naContext c, void* f, char* buf, unsigned int len)
98 naModUnlock(); n = fread(buf, 1, len, f); naModLock();
99 if(n < len && !feof((FILE*)f)) naRuntimeError(c, strerror(errno));
103 static int iowrite(naContext c, void* f, char* buf, unsigned int len)
106 naModUnlock(); n = fwrite(buf, 1, len, f); naModLock();
107 if(ferror((FILE*)f)) naRuntimeError(c, strerror(errno));
111 static void ioseek(naContext c, void* f, unsigned int off, int whence)
113 if(fseek(f, off, whence) != 0) naRuntimeError(c, strerror(errno));
116 static int iotell(naContext c, void* f)
119 if(n < 0) naRuntimeError(c, strerror(errno));
123 static void ioflush(naContext c, void* f)
125 if(fflush(f)) naRuntimeError(c, strerror(errno));
128 static void iodestroy(void* f)
130 if(f != stdin && f != stdout && f != stderr)
134 struct naIOType naStdIOType = { ioclose, ioread, iowrite, ioseek,
135 iotell, ioflush, iodestroy };
137 naRef naIOGhost(naContext c, FILE* f)
139 struct naIOGhost* ghost = naAlloc(sizeof(struct naIOGhost));
140 ghost->type = &naStdIOType;
142 return naNewGhost(c, &naIOGhostType, ghost);
145 static naRef f_open(naContext c, naRef me, int argc, naRef* args)
148 naRef file = argc > 0 ? naStringValue(c, args[0]) : naNil();
149 naRef mode = argc > 1 ? naStringValue(c, args[1]) : naNil();
150 if(!IS_STR(file)) naRuntimeError(c, "bad argument to open()");
151 f = fopen(naStr_data(file), IS_STR(mode) ? naStr_data(mode) : "rb");
152 if(!f) naRuntimeError(c, strerror(errno));
153 return naIOGhost(c, f);
156 // frees buffer before tossing an error
157 static int getcguard(naContext ctx, FILE* f, void* buf)
160 naModUnlock(); c = fgetc(f); naModLock();
163 naRuntimeError(ctx, strerror(errno));
168 // Handles multiple EOL conventions by using stdio's ungetc. Will not
169 // work for other IO types without converting them to FILE* with
170 // fdopen() or whatnot...
171 static naRef f_readln(naContext ctx, naRef me, int argc, naRef* args)
174 struct naIOGhost* g = argc==1 ? ioghost(args[0]) : 0;
175 int i=0, c, sz = 128;
177 if(!g || g->type != &naStdIOType)
178 naRuntimeError(ctx, "bad argument to readln()");
181 c = getcguard(ctx, g->handle, buf);
182 if(c == EOF || c == '\n') break;
184 int c2 = getcguard(ctx, g->handle, buf);
185 if(c2 != EOF && c2 != '\n')
186 if(EOF == ungetc(c2, g->handle))
191 if(i >= sz) buf = naRealloc(buf, sz *= 2);
193 result = c == EOF ? naNil() : naStr_fromdata(naNewString(ctx), buf, i);
200 #define S_ISSOCK(m) 0
203 #define S_ISREG(m) (((m)&_S_IFMT)==_S_IFREG)
204 #define S_ISDIR(m) (((m)&_S_IFMT)==_S_IFDIR)
205 #define S_ISCHR(m) (((m)&_S_IFMT)==_S_IFCHR)
206 #define S_ISFIFO(m) (((m)&_S_IFMT)==_S_IFIFO)
208 typedef unsigned short mode_t;
210 static naRef ftype(naContext ctx, mode_t m)
212 const char* t = "unk";
213 if(S_ISREG(m)) t = "reg";
214 else if(S_ISDIR(m)) t = "dir"; else if(S_ISCHR(m)) t = "chr";
215 else if(S_ISBLK(m)) t = "blk"; else if(S_ISFIFO(m)) t = "fifo";
216 else if(S_ISLNK(m)) t = "lnk"; else if(S_ISSOCK(m)) t = "sock";
217 return naStr_fromdata(naNewString(ctx), t, strlen(t));
220 static naRef f_stat(naContext ctx, naRef me, int argc, naRef* args)
224 naRef result, path = argc > 0 ? naStringValue(ctx, args[0]) : naNil();
225 if(!IS_STR(path)) naRuntimeError(ctx, "bad argument to stat()");
226 if(stat(naStr_data(path), &s) < 0) {
227 if(errno == ENOENT) return naNil();
228 naRuntimeError(ctx, strerror(errno));
230 result = naNewVector(ctx);
231 naVec_setsize(ctx, result, 12);
232 #define FLD(x) naVec_set(result, n++, naNum(s.st_##x));
233 FLD(dev); FLD(ino); FLD(mode); FLD(nlink); FLD(uid); FLD(gid);
234 FLD(rdev); FLD(size); FLD(atime); FLD(mtime); FLD(ctime);
236 naVec_set(result, n++, ftype(ctx, s.st_mode));
240 static naCFuncItem funcs[] = {
241 { "close", f_close },
243 { "write", f_write },
246 { "flush", f_flush },
248 { "readln", f_readln },
253 naRef naInit_io(naContext c)
255 naRef ns = naGenLib(c, funcs);
256 naAddSym(c, ns, "SEEK_SET", naNum(SEEK_SET));
257 naAddSym(c, ns, "SEEK_CUR", naNum(SEEK_CUR));
258 naAddSym(c, ns, "SEEK_END", naNum(SEEK_END));
259 naAddSym(c, ns, "stdin", naIOGhost(c, stdin));
260 naAddSym(c, ns, "stdout", naIOGhost(c, stdout));
261 naAddSym(c, ns, "stderr", naIOGhost(c, stderr));