00001 #include <errno.h>
00002 #include <stdio.h>
00003 #include <string.h>
00004 #include <sys/types.h>
00005 #include <sys/stat.h>
00006 #include "data.h"
00007 #include "iolib.h"
00008
00009 static void ghostDestroy(void* g);
00010 naGhostType naIOGhostType = { ghostDestroy, "iofile" };
00011
00012 static struct naIOGhost* ioghost(naRef r)
00013 {
00014 if(naGhost_type(r) == &naIOGhostType && IOGHOST(r)->handle)
00015 return naGhost_ptr(r);
00016 return 0;
00017 }
00018
00019 static naRef f_close(naContext c, naRef me, int argc, naRef* args)
00020 {
00021 struct naIOGhost* g = argc==1 ? ioghost(args[0]) : 0;
00022 if(!g) naRuntimeError(c, "bad argument to close()");
00023 if(g->handle) g->type->close(c, g->handle);
00024 g->handle = 0;
00025 return naNil();
00026 }
00027
00028 static naRef f_read(naContext c, naRef me, int argc, naRef* args)
00029 {
00030 struct naIOGhost* g = argc > 0 ? ioghost(args[0]) : 0;
00031 naRef str = argc > 1 ? args[1] : naNil();
00032 naRef len = argc > 2 ? naNumValue(args[2]) : naNil();
00033 if(!g || !MUTABLE(str) || !IS_NUM(len))
00034 naRuntimeError(c, "bad argument to read()");
00035 if(naStr_len(str) < (int)len.num)
00036 naRuntimeError(c, "string not big enough for read");
00037 return naNum(g->type->read(c, g->handle, naStr_data(str),
00038 (int)len.num));
00039 }
00040
00041 static naRef f_write(naContext c, naRef me, int argc, naRef* args)
00042 {
00043 struct naIOGhost* g = argc > 0 ? ioghost(args[0]) : 0;
00044 naRef str = argc > 1 ? args[1] : naNil();
00045 if(!g || !IS_STR(str))
00046 naRuntimeError(c, "bad argument to write()");
00047 return naNum(g->type->write(c, g->handle, naStr_data(str),
00048 naStr_len(str)));
00049 }
00050
00051 static naRef f_seek(naContext c, naRef me, int argc, naRef* args)
00052 {
00053 struct naIOGhost* g = argc > 0 ? ioghost(args[0]) : 0;
00054 naRef pos = argc > 1 ? naNumValue(args[1]) : naNil();
00055 naRef whn = argc > 2 ? naNumValue(args[2]) : naNil();
00056 if(!g || !IS_NUM(pos) || !IS_NUM(whn))
00057 naRuntimeError(c, "bad argument to seek()");
00058 g->type->seek(c, g->handle, (int)pos.num, (int)whn.num);
00059 return naNil();
00060 }
00061
00062 static naRef f_tell(naContext c, naRef me, int argc, naRef* args)
00063 {
00064 struct naIOGhost* g = argc==1 ? ioghost(args[0]) : 0;
00065 if(!g)
00066 naRuntimeError(c, "bad argument to tell()");
00067 return naNum(g->type->tell(c, g->handle));
00068 }
00069
00070 static naRef f_flush(naContext c, naRef me, int argc, naRef* args)
00071 {
00072 struct naIOGhost* g = argc==1 ? ioghost(args[0]) : 0;
00073 if(!g)
00074 naRuntimeError(c, "bad argument to flush()");
00075 g->type->flush(c, g->handle);
00076 return naNil();
00077 }
00078
00079 static void ghostDestroy(void* g)
00080 {
00081 struct naIOGhost* io = (struct naIOGhost*)g;
00082 io->type->destroy(io->handle);
00083 naFree(io);
00084 }
00085
00087
00088
00089 static void ioclose(naContext c, void* f)
00090 {
00091 if(f)
00092 if(fclose(f) != 0 && c) naRuntimeError(c, strerror(errno));
00093 }
00094
00095 static int ioread(naContext c, void* f, char* buf, unsigned int len)
00096 {
00097 int n;
00098 naModUnlock(); n = fread(buf, 1, len, f); naModLock();
00099 if(n < len && !feof((FILE*)f)) naRuntimeError(c, strerror(errno));
00100 return n;
00101 }
00102
00103 static int iowrite(naContext c, void* f, char* buf, unsigned int len)
00104 {
00105 int n;
00106 naModUnlock(); n = fwrite(buf, 1, len, f); naModLock();
00107 if(ferror((FILE*)f)) naRuntimeError(c, strerror(errno));
00108 return n;
00109 }
00110
00111 static void ioseek(naContext c, void* f, unsigned int off, int whence)
00112 {
00113 if(fseek(f, off, whence) != 0) naRuntimeError(c, strerror(errno));
00114 }
00115
00116 static int iotell(naContext c, void* f)
00117 {
00118 int n = ftell(f);
00119 if(n < 0) naRuntimeError(c, strerror(errno));
00120 return n;
00121 }
00122
00123 static void ioflush(naContext c, void* f)
00124 {
00125 if(fflush(f)) naRuntimeError(c, strerror(errno));
00126 }
00127
00128 static void iodestroy(void* f)
00129 {
00130 if(f != stdin && f != stdout && f != stderr)
00131 ioclose(0, f);
00132 }
00133
00134 struct naIOType naStdIOType = { ioclose, ioread, iowrite, ioseek,
00135 iotell, ioflush, iodestroy };
00136
00137 naRef naIOGhost(naContext c, FILE* f)
00138 {
00139 struct naIOGhost* ghost = naAlloc(sizeof(struct naIOGhost));
00140 ghost->type = &naStdIOType;
00141 ghost->handle = f;
00142 return naNewGhost(c, &naIOGhostType, ghost);
00143 }
00144
00145 static naRef f_open(naContext c, naRef me, int argc, naRef* args)
00146 {
00147 FILE* f;
00148 naRef file = argc > 0 ? naStringValue(c, args[0]) : naNil();
00149 naRef mode = argc > 1 ? naStringValue(c, args[1]) : naNil();
00150 if(!IS_STR(file)) naRuntimeError(c, "bad argument to open()");
00151 f = fopen(naStr_data(file), IS_STR(mode) ? naStr_data(mode) : "rb");
00152 if(!f) naRuntimeError(c, strerror(errno));
00153 return naIOGhost(c, f);
00154 }
00155
00156
00157 static int getcguard(naContext ctx, FILE* f, void* buf)
00158 {
00159 int c;
00160 naModUnlock(); c = fgetc(f); naModLock();
00161 if(ferror(f)) {
00162 naFree(buf);
00163 naRuntimeError(ctx, strerror(errno));
00164 }
00165 return c;
00166 }
00167
00168
00169
00170
00171 static naRef f_readln(naContext ctx, naRef me, int argc, naRef* args)
00172 {
00173 naRef result;
00174 struct naIOGhost* g = argc==1 ? ioghost(args[0]) : 0;
00175 int i=0, c, sz = 128;
00176 char *buf;
00177 if(!g || g->type != &naStdIOType)
00178 naRuntimeError(ctx, "bad argument to readln()");
00179 buf = naAlloc(sz);
00180 while(1) {
00181 c = getcguard(ctx, g->handle, buf);
00182 if(c == EOF || c == '\n') break;
00183 if(c == '\r') {
00184 int c2 = getcguard(ctx, g->handle, buf);
00185 if(c2 != EOF && c2 != '\n')
00186 if(EOF == ungetc(c2, g->handle))
00187 break;
00188 break;
00189 }
00190 buf[i++] = c;
00191 if(i >= sz) buf = naRealloc(buf, sz *= 2);
00192 }
00193 result = c == EOF ? naNil() : naStr_fromdata(naNewString(ctx), buf, i);
00194 naFree(buf);
00195 return result;
00196 }
00197
00198 #ifdef _WIN32
00199 #define S_ISLNK(m) 0
00200 #define S_ISSOCK(m) 0
00201 #endif
00202 #ifdef _MSC_VER
00203 #define S_ISREG(m) (((m)&_S_IFMT)==_S_IFREG)
00204 #define S_ISDIR(m) (((m)&_S_IFMT)==_S_IFDIR)
00205 #define S_ISCHR(m) (((m)&_S_IFMT)==_S_IFCHR)
00206 #define S_ISFIFO(m) (((m)&_S_IFMT)==_S_IFIFO)
00207 #define S_ISBLK(m) 0
00208 typedef unsigned short mode_t;
00209 #endif
00210 static naRef ftype(naContext ctx, mode_t m)
00211 {
00212 const char* t = "unk";
00213 if(S_ISREG(m)) t = "reg";
00214 else if(S_ISDIR(m)) t = "dir"; else if(S_ISCHR(m)) t = "chr";
00215 else if(S_ISBLK(m)) t = "blk"; else if(S_ISFIFO(m)) t = "fifo";
00216 else if(S_ISLNK(m)) t = "lnk"; else if(S_ISSOCK(m)) t = "sock";
00217 return naStr_fromdata(naNewString(ctx), t, strlen(t));
00218 }
00219
00220 static naRef f_stat(naContext ctx, naRef me, int argc, naRef* args)
00221 {
00222 int n=0;
00223 struct stat s;
00224 naRef result, path = argc > 0 ? naStringValue(ctx, args[0]) : naNil();
00225 if(!IS_STR(path)) naRuntimeError(ctx, "bad argument to stat()");
00226 if(stat(naStr_data(path), &s) < 0) {
00227 if(errno == ENOENT) return naNil();
00228 naRuntimeError(ctx, strerror(errno));
00229 }
00230 result = naNewVector(ctx);
00231 naVec_setsize(result, 12);
00232 #define FLD(x) naVec_set(result, n++, naNum(s.st_##x));
00233 FLD(dev); FLD(ino); FLD(mode); FLD(nlink); FLD(uid); FLD(gid);
00234 FLD(rdev); FLD(size); FLD(atime); FLD(mtime); FLD(ctime);
00235 #undef FLD
00236 naVec_set(result, n++, ftype(ctx, s.st_mode));
00237 return result;
00238 }
00239
00240 static naCFuncItem funcs[] = {
00241 { "close", f_close },
00242 { "read", f_read },
00243 { "write", f_write },
00244 { "seek", f_seek },
00245 { "tell", f_tell },
00246 { "flush", f_flush },
00247 { "open", f_open },
00248 { "readln", f_readln },
00249 { "stat", f_stat },
00250 { 0 }
00251 };
00252
00253 naRef naInit_io(naContext c)
00254 {
00255 naRef ns = naGenLib(c, funcs);
00256 naAddSym(c, ns, "SEEK_SET", naNum(SEEK_SET));
00257 naAddSym(c, ns, "SEEK_CUR", naNum(SEEK_CUR));
00258 naAddSym(c, ns, "SEEK_END", naNum(SEEK_END));
00259 naAddSym(c, ns, "stdin", naIOGhost(c, stdin));
00260 naAddSym(c, ns, "stdout", naIOGhost(c, stdout));
00261 naAddSym(c, ns, "stderr", naIOGhost(c, stderr));
00262 return ns;
00263 }