Example #1
0
/*
 * Like JSEnumerateOp, but enum provides contextual information as follows:
 *
 * JSENUMERATE_INIT: allocate private enum struct in state_p, return number
 * of elements in *id_p
 * JSENUMERATE_NEXT: return next property id in *id_p, and if no new property
 * free state_p and set to JSVAL_NULL
 * JSENUMERATE_DESTROY : destroy state_p
 *
 * Note that in a for ... in loop, this will be called first on the object,
 * then on its prototype.
 *
 */
static JSBool
importer_new_enumerate(JSContext  *context,
                       JSObject  **object,
                       JSIterateOp enum_op,
                       jsval      *state_p,
                       jsid       *id_p)
{
    ImporterIterator *iter;

    switch (enum_op) {
    case JSENUMERATE_INIT_ALL:
    case JSENUMERATE_INIT: {
        Importer *priv;
        JSObject *search_path;
        jsval search_path_val;
        guint32 search_path_len;
        guint32 i;
        jsid search_path_name;

        if (state_p)
            *state_p = JSVAL_NULL;

        if (id_p)
            *id_p = INT_TO_JSID(0);

        priv = priv_from_js(context, *object);

        if (!priv)
            /* we are enumerating the prototype properties */
            return JS_TRUE;

        search_path_name = gjs_runtime_get_const_string(JS_GetRuntime(context),
                                                        GJS_STRING_SEARCH_PATH);
        if (!gjs_object_require_property(context, *object, "importer", search_path_name, &search_path_val))
            return JS_FALSE;

        if (!JSVAL_IS_OBJECT(search_path_val)) {
            gjs_throw(context, "searchPath property on importer is not an object");
            return JS_FALSE;
        }

        search_path = JSVAL_TO_OBJECT(search_path_val);

        if (!JS_IsArrayObject(context, search_path)) {
            gjs_throw(context, "searchPath property on importer is not an array");
            return JS_FALSE;
        }

        if (!JS_GetArrayLength(context, search_path, &search_path_len)) {
            gjs_throw(context, "searchPath array has no length");
            return JS_FALSE;
        }

        iter = importer_iterator_new();

        for (i = 0; i < search_path_len; ++i) {
            char *dirname = NULL;
            char *init_path;
            const char *filename;
            jsval elem;
            GDir *dir = NULL;

            elem = JSVAL_VOID;
            if (!JS_GetElement(context, search_path, i, &elem)) {
                /* this means there was an exception, while elem == JSVAL_VOID
                 * means no element found
                 */
                importer_iterator_free(iter);
                return JS_FALSE;
            }

            if (JSVAL_IS_VOID(elem))
                continue;

            if (!JSVAL_IS_STRING(elem)) {
                gjs_throw(context, "importer searchPath contains non-string");
                importer_iterator_free(iter);
                return JS_FALSE;
            }

            if (!gjs_string_to_utf8(context, elem, &dirname)) {
                importer_iterator_free(iter);
                return JS_FALSE; /* Error message already set */
            }

            init_path = g_build_filename(dirname, MODULE_INIT_FILENAME,
                                         NULL);

            load_module_elements(context, *object, iter, init_path);

            g_free(init_path);

            dir = g_dir_open(dirname, 0, NULL);

            if (!dir) {
                g_free(dirname);
                continue;
            }

            while ((filename = g_dir_read_name(dir))) {
                char *full_path;

                /* skip hidden files and directories (.svn, .git, ...) */
                if (filename[0] == '.')
                    continue;

                /* skip module init file */
                if (strcmp(filename, MODULE_INIT_FILENAME) == 0)
                    continue;

                full_path = g_build_filename(dirname, filename, NULL);

                if (g_file_test(full_path, G_FILE_TEST_IS_DIR)) {
                    g_ptr_array_add(iter->elements, g_strdup(filename));
                } else {
                    if (g_str_has_suffix(filename, "."G_MODULE_SUFFIX) ||
                        g_str_has_suffix(filename, ".js")) {
                        g_ptr_array_add(iter->elements,
                                        g_strndup(filename, strlen(filename) - 3));
                    }
                }

                g_free(full_path);
            }
            g_dir_close(dir);

            g_free(dirname);
        }

        if (state_p)
            *state_p = PRIVATE_TO_JSVAL(iter);

        if (id_p)
            *id_p = INT_TO_JSID(iter->elements->len);

        break;
    }

    case JSENUMERATE_NEXT: {
        jsval element_val;

        if (!state_p) {
            gjs_throw(context, "Enumerate with no iterator set?");
            return JS_FALSE;
        }

        if (JSVAL_IS_NULL(*state_p)) /* Iterating prototype */
            return JS_TRUE;

        iter = JSVAL_TO_PRIVATE(*state_p);

        if (iter->index < iter->elements->len) {
            if (!gjs_string_from_utf8(context,
                                         g_ptr_array_index(iter->elements,
                                                           iter->index++),
                                         -1,
                                         &element_val))
                return JS_FALSE;

            if (!JS_ValueToId(context, element_val, id_p))
                return JS_FALSE;

            break;
        }
        /* else fall through to destroying the iterator */
    }

    case JSENUMERATE_DESTROY: {
        if (state_p && !JSVAL_IS_NULL(*state_p)) {
            iter = JSVAL_TO_PRIVATE(*state_p);

            importer_iterator_free(iter);

            *state_p = JSVAL_NULL;
        }
    }
    }

    return JS_TRUE;
}
Example #2
0
/*
 * Like JSEnumerateOp, but enum provides contextual information as follows:
 *
 * JSENUMERATE_INIT: allocate private enum struct in state_p, return number
 * of elements in *id_p
 * JSENUMERATE_NEXT: return next property id in *id_p, and if no new property
 * free state_p and set to JSVAL_NULL
 * JSENUMERATE_DESTROY : destroy state_p
 *
 * Note that in a for ... in loop, this will be called first on the object,
 * then on its prototype.
 *
 */
static JSBool
importer_new_enumerate(JSContext  *context,
                       JS::HandleObject object,
                       JSIterateOp enum_op,
                       JS::MutableHandleValue statep,
                       JS::MutableHandleId idp)
{
    ImporterIterator *iter;

    switch (enum_op) {
    case JSENUMERATE_INIT_ALL:
    case JSENUMERATE_INIT: {
        Importer *priv;
        JSObject *search_path;
        jsval search_path_val;
        uint32_t search_path_len;
        uint32_t i;
        jsid search_path_name;

        statep.set(JSVAL_NULL);

        idp.set(INT_TO_JSID(0));

        priv = priv_from_js(context, object);

        if (!priv)
            /* we are enumerating the prototype properties */
            return JS_TRUE;

        search_path_name = gjs_context_get_const_string(context, GJS_STRING_SEARCH_PATH);
        if (!gjs_object_require_property(context, object, "importer", search_path_name, &search_path_val))
            return JS_FALSE;

        if (!search_path_val.isObject()) {
            gjs_throw(context, "searchPath property on importer is not an object");
            return JS_FALSE;
        }

        search_path = JSVAL_TO_OBJECT(search_path_val);

        if (!JS_IsArrayObject(context, search_path)) {
            gjs_throw(context, "searchPath property on importer is not an array");
            return JS_FALSE;
        }

        if (!JS_GetArrayLength(context, search_path, &search_path_len)) {
            gjs_throw(context, "searchPath array has no length");
            return JS_FALSE;
        }

        iter = importer_iterator_new();

        for (i = 0; i < search_path_len; ++i) {
            std::string dirname;
            std::string init_path;
            const char *filename;
            jsval elem;
            std::vector<std::string> dir;

            elem = JSVAL_VOID;
            if (!JS_GetElement(context, search_path, i, &elem)) {
                /* this means there was an exception, while elem == JSVAL_VOID
                 * means no element found
                 */
                importer_iterator_free(iter);
                return JS_FALSE;
            }

            if (JSVAL_IS_VOID(elem))
                continue;

            if (!JSVAL_IS_STRING(elem)) {
                gjs_throw(context, "importer searchPath contains non-string");
                importer_iterator_free(iter);
                return JS_FALSE;
            }

            if (!gjs_string_to_utf8(context, elem, dirname)) {
                importer_iterator_free(iter);
                return JS_FALSE; /* Error message already set */
            }

            init_path = pathCombine(dirname, MODULE_INIT_FILENAME);

            load_module_elements(context, object, iter, init_path);

            dir = enumerateFilesInDirectory(dirname);

            if (dir.size() == 0) {
                continue;
            }

            for(auto filename : dir) {
                std::string full_path;

                /* skip hidden files and directories (.svn, .git, ...) */
                if (filename[0] == '.')
                    continue;

                /* skip module init file */
                if (filename == MODULE_INIT_FILENAME)
                    continue;

                full_path = pathCombine(dirname, filename);

                if (is_directory(full_path)) {
                    iter->elements.push_back(filename);
                } else {
                    if (filename.rfind(MODULE_SUFFIX) != std::string::npos ||
                        filename.rfind(JS_SUFFIX) != std::string::npos) {
                        iter->elements.push_back(filename.substr(0, filename.size()-3));
                    }
                }
            }
        }

        statep.set(PRIVATE_TO_JSVAL(iter));

        idp.set(INT_TO_JSID(iter->elements.size()));

        break;
    }

    case JSENUMERATE_NEXT: {
        jsval element_val;

        if (JSVAL_IS_NULL(statep)) /* Iterating prototype */
            return JS_TRUE;

        iter = (ImporterIterator*) JSVAL_TO_PRIVATE(statep);

        if (iter->index < iter->elements.size()) {
            if (!gjs_string_from_utf8(context,
                                         iter->elements.at(iter->index++),
                                         &element_val))
                return JS_FALSE;

            jsid id;
            if (!JS_ValueToId(context, element_val, &id))
                return JS_FALSE;
            idp.set(id);

            break;
        }
        /* else fall through to destroying the iterator */
    }

    case JSENUMERATE_DESTROY: {
        if (!JSVAL_IS_NULL(statep)) {
            iter = (ImporterIterator*) JSVAL_TO_PRIVATE(statep);

            importer_iterator_free(iter);

            statep.set(JSVAL_NULL);
        }
    }
    }

    return JS_TRUE;
}