--- /dev/null
+/* $Id: js_dir.c,v 1.1 2006/09/08 12:50:43 mmondor Exp $ */
+
+/*
+ * Copyright (c) 2006, Matthew Mondor
+ * ALL RIGHTS RESERVED.
+ */
+
+
+
+#include <sys/types.h>
+#include <sys/dirent.h>
+
+#include <stdint.h>
+
+#include <assert.h>
+#include <dirent.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <jsapi.h>
+
+#include <js_dir.h>
+
+
+
+
+#define QUEUE_EXCEPTION(s) do { \
+ JS_SetPendingException(cx, \
+ STRING_TO_JSVAL(JS_NewStringCopyZ(cx, (s)))); \
+} while (/* CONSTCOND */0)
+
+
+struct property_spec {
+ const char *name;
+ int value;
+};
+
+#define SP(n) \
+ { #n, n }
+
+
+
+/*
+ * Static prototypes
+ */
+static JSBool dir_constructor(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static void dir_finalize(JSContext *, JSObject *);
+
+static JSBool dir_m_read(JSContext *, JSObject *, uintN, jsval *, jsval *);
+static JSBool dir_m_tell(JSContext *, JSObject *, uintN, jsval *, jsval *);
+static JSBool dir_m_seek(JSContext *, JSObject *, uintN, jsval *, jsval *);
+static JSBool dir_m_rewind(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool dir_m_close(JSContext *, JSObject *, uintN, jsval *, jsval *);
+
+
+
+/*
+ * Static globals
+ */
+
+/* PG class */
+static JSClass dir_class = {
+ "Dir", JSCLASS_HAS_PRIVATE, JS_PropertyStub, JS_PropertyStub,
+ JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, JS_ResolveStub,
+ JS_ConvertStub, dir_finalize
+};
+
+/* Provided methods */
+static JSFunctionSpec dir_methods[] = {
+ { "read", dir_m_read, 0, 0, 0 },
+ { "tell", dir_m_tell, 0, 0, 0 },
+ { "seek", dir_m_seek, 1, 0, 0 },
+ { "rewind", dir_m_rewind, 0, 0, 0 },
+ { "close", dir_m_close, 0, 0, 0 }
+};
+
+/* Static properties */
+
+static struct property_spec dir_sprops[] = {
+ SP(DT_UNKNOWN),
+ SP(DT_FIFO),
+ SP(DT_CHR),
+ SP(DT_DIR),
+ SP(DT_BLK),
+ SP(DT_REG),
+ SP(DT_LNK),
+ SP(DT_SOCK),
+#ifdef DT_WHT
+ SP(DT_WHT)
+#endif
+};
+
+
+
+/*
+ * Dir object control
+ */
+
+JSObject *
+js_InitDirClass(JSContext *cx, JSObject *obj)
+{
+ JSObject *proto, *ctor;
+ struct property_spec *sp;
+
+ if ((proto = JS_InitClass(cx, obj, NULL, &dir_class, dir_constructor,
+ 0, NULL, dir_methods, NULL, NULL)) == NULL) {
+ (void) fprintf(stderr, "Error initializing CGI class\n");
+ goto err;
+ }
+
+ /* Create static properties. */
+ if ((ctor = JS_GetConstructor(cx, proto)) == NULL) {
+ (void) fprintf(stderr, "Dir: JS_GetConstructor == NULL\n");
+ return NULL;
+ }
+ for (sp = dir_sprops; sp->name != NULL; sp++) {
+ if (JS_DefineProperty(cx, ctor, sp->name,
+ INT_TO_JSVAL(sp->value), NULL, NULL,
+ JSPROP_READONLY | JSPROP_PERMANENT) == JS_FALSE) {
+ (void) fprintf(stderr,
+ "Dir: Error defining property %s\n", sp->name);
+ return NULL;
+ }
+ }
+
+ return proto;
+
+err:
+ return NULL;
+}
+
+static JSBool
+dir_constructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ DIR *dir = NULL;
+ char *path;
+
+ if (!JS_IsConstructing(cx)) {
+ QUEUE_EXCEPTION("Constructor called as a function");
+ goto err;
+ }
+
+ if (argc != 1) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ goto err;
+ }
+ if (!JSVAL_IS_STRING(argv[0])) {
+ QUEUE_EXCEPTION("Argument not a string");
+ goto err;
+ }
+
+ path = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]));
+ if ((dir = opendir(path)) == NULL) {
+ char str[256];
+
+ (void) snprintf(str, sizeof(str), "opendir('%s'): %s",
+ str, strerror(errno));
+ QUEUE_EXCEPTION(str);
+ goto err;
+ }
+
+ if (!JS_SetPrivate(cx, obj, dir)) {
+ QUEUE_EXCEPTION("Internal error!");
+ goto err;
+ }
+
+ return JS_TRUE;
+
+err:
+ *rval = OBJECT_TO_JSVAL(NULL);
+ if (dir != NULL)
+ (void) closedir(dir);
+
+ return JS_FALSE;
+}
+
+static void
+dir_finalize(JSContext *cx, JSObject *obj)
+{
+ DIR *dir;
+
+ if ((dir = JS_GetInstancePrivate(cx, obj, &dir_class, NULL)) != NULL) {
+ (void) closedir(dir);
+ (void) JS_SetPrivate(cx, obj, NULL);
+ }
+}
+
+
+
+/* Methods */
+static JSBool
+dir_m_read(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ DIR *dir;
+ struct dirent *de;
+ JSObject *o;
+ jsval val;
+ JSString *str;
+
+ if (argc != 0) {
+ QUEUE_EXCEPTION("Function allows no arguments");
+ *rval = OBJECT_TO_JSVAL(NULL);
+ return JS_FALSE;
+ }
+
+ dir = JS_GetInstancePrivate(cx, obj, &dir_class, NULL);
+ assert(dir != NULL);
+
+ if ((de = readdir(dir)) == NULL) {
+ *rval = OBJECT_TO_JSVAL(NULL);
+ return JS_TRUE;
+ }
+
+ if ((o = JS_NewObject(cx, NULL, NULL, NULL)) == NULL) {
+ QUEUE_EXCEPTION("Internal error!");
+ *rval = OBJECT_TO_JSVAL(NULL);
+ return JS_FALSE;
+ }
+ *rval = OBJECT_TO_JSVAL(o);
+
+ /* d_fileno is u_int32_t and so could exceed a JS int, so use this */
+ if (!JS_NewNumberValue(cx, (jsdouble)de->d_fileno, &val) ||
+ !JS_DefineProperty(cx, o, "fileno", val, NULL, NULL,
+ JSPROP_ENUMERATE))
+ goto err;
+
+ if (!JS_DefineProperty(cx, o, "type", INT_TO_JSVAL(de->d_type), NULL,
+ NULL, JSPROP_ENUMERATE))
+ goto err;
+
+ if ((str = JS_NewStringCopyN(cx, de->d_name, de->d_namlen)) == NULL ||
+ !JS_DefineProperty(cx, o, "name", STRING_TO_JSVAL(str), NULL,
+ NULL, JSPROP_ENUMERATE))
+ goto err;
+
+ return JS_TRUE;
+
+err:
+ QUEUE_EXCEPTION("Internal error!");
+ *rval = OBJECT_TO_JSVAL(NULL);
+ return JS_FALSE;
+}
+
+static JSBool
+dir_m_tell(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ DIR *dir;
+ long v;
+
+ if (argc != 0) {
+ QUEUE_EXCEPTION("Function allows no arguments");
+ *rval = OBJECT_TO_JSVAL(NULL);
+ return JS_FALSE;
+ }
+
+ dir = JS_GetInstancePrivate(cx, obj, &dir_class, NULL);
+ assert(dir != NULL);
+
+ v = telldir(dir);
+
+ if (!JS_NewNumberValue(cx, (jsdouble)v, rval)) {
+ QUEUE_EXCEPTION("Internal error!");
+ *rval = OBJECT_TO_JSVAL(NULL);
+ return JS_FALSE;
+ }
+
+ return JS_TRUE;
+}
+
+static JSBool
+dir_m_seek(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ DIR *dir;
+ jsdouble v;
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ if (argc != 1) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_NUMBER(argv[0]) ||
+ !JS_ValueToNumber(cx, argv[0], &v)) {
+ QUEUE_EXCEPTION("Argument 1 not a number");
+ return JS_FALSE;
+ }
+
+ dir = JS_GetInstancePrivate(cx, obj, &dir_class, NULL);
+ assert(dir != NULL);
+
+ seekdir(dir, (long)v);
+
+ return JS_TRUE;
+}
+
+static JSBool
+dir_m_rewind(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ DIR *dir;
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ if (argc != 0) {
+ QUEUE_EXCEPTION("Function allows no arguments");
+ return JS_FALSE;
+ }
+
+ dir = JS_GetInstancePrivate(cx, obj, &dir_class, NULL);
+ assert(dir != NULL);
+
+ rewinddir(dir);
+
+ return JS_TRUE;
+}
+
+static JSBool
+dir_m_close(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ DIR *dir;
+
+ if (argc != 0) {
+ QUEUE_EXCEPTION("Function allows no arguments");
+ *rval = OBJECT_TO_JSVAL(NULL);
+ return JS_FALSE;
+ }
+
+ dir = JS_GetInstancePrivate(cx, obj, &dir_class, NULL);
+ assert(dir != NULL);
+
+ *rval = INT_TO_JSVAL(closedir(dir));
+ (void) JS_SetPrivate(cx, obj, NULL);
+
+ return JS_TRUE;
+}