void mget_css_parse_file( const char *fname, void(*callback_uri)(void *user_ctx, const char *url, size_t len, size_t pos), void(*callback_encoding)(void *user_ctx, const char *url, size_t len), void *user_ctx) { int fd; if (strcmp(fname,"-")) { if ((fd = open(fname, O_RDONLY)) != -1) { struct stat st; if (fstat(fd, &st) == 0) { #ifdef HAVE_MMAP size_t nread = st.st_size; char *buf = mmap(NULL, nread + 1, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); #else char *buf=xmalloc(st.st_size+1); size_t nread=read(fd,buf,st.st_size); #endif if (nread > 0) { buf[nread] = 0; // PROT_WRITE allows this write, MAP_PRIVATE prevents changes in underlying file system mget_css_parse_buffer(buf, callback_uri, callback_encoding, user_ctx); } #ifdef HAVE_MMAP munmap(buf, nread); #else xfree(buf); #endif } close(fd); } else error_printf(_("Failed to open %s\n"), fname); } else { // read data from STDIN. // maybe should use yy_scan_bytes instead of buffering into memory. char tmp[4096]; ssize_t nbytes; mget_buffer_t *buf = mget_buffer_alloc(4096); while ((nbytes = read(STDIN_FILENO, tmp, sizeof(tmp))) > 0) { mget_buffer_memcat(buf, tmp, nbytes); } if (buf->length) mget_css_parse_buffer(buf->data, callback_uri, callback_encoding, user_ctx); mget_buffer_free(&buf); } }
void mget_buffer_deinit(mget_buffer_t *buf) { mget_buffer_free(&buf); }
static void test_buffer(void) { char sbuf[16]; mget_buffer_t buf, *bufp; // testing buffer on stack, using initial stack memory // without resizing mget_buffer_init(&buf, sbuf, sizeof(sbuf)); mget_buffer_deinit(&buf); // testing buffer on stack, using initial stack memory // with resizing mget_buffer_init(&buf, sbuf, sizeof(sbuf)); _test_buffer(&buf, "Test 1"); mget_buffer_deinit(&buf); // testing buffer on stack, using initial heap memory // without resizing mget_buffer_init(&buf, NULL, 16); mget_buffer_deinit(&buf); // testing buffer on stack, using initial heap memory // with resizing mget_buffer_init(&buf, NULL, 16); _test_buffer(&buf, "Test 2"); mget_buffer_deinit(&buf); // testing buffer on heap, using initial stack memory // without resizing bufp = mget_buffer_init(NULL, sbuf, sizeof(sbuf)); mget_buffer_deinit(bufp); bufp = mget_buffer_init(NULL, sbuf, sizeof(sbuf)); mget_buffer_free(&bufp); // testing buffer on heap, using initial stack memory // with resizing bufp = mget_buffer_init(NULL, sbuf, sizeof(sbuf)); _test_buffer(bufp, "Test 3"); mget_buffer_deinit(bufp); bufp = mget_buffer_init(NULL, sbuf, sizeof(sbuf)); _test_buffer(bufp, "Test 4"); mget_buffer_free(&bufp); // testing buffer on heap, using initial heap memory // without resizing bufp = mget_buffer_alloc(16); mget_buffer_free(&bufp); // testing buffer on heap, using initial heap memory // with resizing bufp = mget_buffer_alloc(16); _test_buffer(bufp, "Test 5"); mget_buffer_free(&bufp); // check that appending works mget_buffer_init(&buf, sbuf, sizeof(sbuf)); mget_buffer_strcpy(&buf, "A"); mget_buffer_strcat(&buf, "B"); mget_buffer_memcat(&buf, "C", 1); mget_buffer_memset_append(&buf, 'D', 1); mget_buffer_printf_append2(&buf, "%s", "E"); if (!strcmp(buf.data, "ABCDE")) ok++; else { failed++; info_printf("test_buffer.append: got %s (expected %s)\n", buf.data, "ABCDE"); } mget_buffer_deinit(&buf); // test mget_buffer_trim() mget_buffer_init(&buf, sbuf, sizeof(sbuf)); for (int mid_ws = 0; mid_ws <= 2; mid_ws++) { char expected[16]; snprintf(expected, sizeof(expected), "x%.*sy", mid_ws, " "); for (int lead_ws = 0; lead_ws <= 2; lead_ws++) { for (int trail_ws = 0; trail_ws <= 2; trail_ws++) { mget_buffer_printf2(&buf, "%.*sx%.*sy%.*s", lead_ws, " ", mid_ws, " ", trail_ws, " "); mget_buffer_trim(&buf); if (!strcmp(buf.data, expected)) ok++; else { failed++; info_printf("test_buffer_trim: got '%s' (expected '%s') (%d, %d, %d)\n", buf.data, expected, lead_ws, mid_ws, trail_ws); } } } } mget_buffer_deinit(&buf); }
static void test_iri_relative_to_absolute(void) { static const struct iri_test_data { const char *base, *relative, *result; } test_data[] = { #define H1 "http://x.tld" { H1, "", H1"/" }, { H1, ".", H1"/" }, { H1, "./", H1"/" }, { H1, "..", H1"/" }, { H1, "../", H1"/" }, { H1, "foo", H1"/foo" }, { H1, "foo/bar", H1"/foo/bar" }, { H1, "foo///bar", H1"/foo/bar" }, { H1, "foo/.", H1"/foo/" }, { H1, "foo/./", H1"/foo/" }, { H1, "foo./", H1"/foo./" }, { H1, "foo/../bar", H1"/bar" }, { H1, "foo/../bar/", H1"/bar/" }, { H1, "foo/bar/..", H1"/foo/" }, { H1, "foo/bar/../x", H1"/foo/x" }, { H1, "foo/bar/../x/", H1"/foo/x/" }, { H1, "foo/..", H1"/" }, { H1, "foo/../..", H1"/" }, { H1, "foo/../../..", H1"/" }, { H1, "foo/../../bar/../../baz", H1"/baz" }, { H1, "a/b/../../c", H1"/c" }, { H1, "./a/../b", H1"/b" }, { H1, "/", H1"/" }, { H1, "/.", H1"/" }, { H1, "/./", H1"/" }, { H1, "/..", H1"/" }, { H1, "/../", H1"/" }, { H1, "/foo", H1"/foo" }, { H1, "/foo/bar", H1"/foo/bar" }, { H1, "/foo///bar", H1"/foo/bar" }, { H1, "/foo/.", H1"/foo/" }, { H1, "/foo/./", H1"/foo/" }, { H1, "/foo./", H1"/foo./" }, { H1, "/foo/../bar", H1"/bar" }, { H1, "/foo/../bar/", H1"/bar/" }, { H1, "/foo/bar/..", H1"/foo/" }, { H1, "/foo/bar/../x", H1"/foo/x" }, { H1, "/foo/bar/../x/", H1"/foo/x/" }, { H1, "/foo/..", H1"/" }, { H1, "/foo/../..", H1"/" }, { H1, "/foo/../../..", H1"/" }, { H1, "/foo/../../bar/../../baz", H1"/baz" }, { H1, "/a/b/../../c", H1"/c" }, { H1, "/./a/../b", H1"/b" }, { H1, ".x", H1"/.x" }, { H1, "..x", H1"/..x" }, { H1, "foo/.x", H1"/foo/.x" }, { H1, "foo/bar/.x", H1"/foo/bar/.x" }, { H1, "foo/..x", H1"/foo/..x" }, { H1, "foo/bar/..x", H1"/foo/bar/..x" }, { H1, "/x.php?y=ftp://example.com/&z=1_2", H1"/x.php?y=ftp://example.com/&z=1_2" }, { H1, "//x.y.com/", "http://x.y.com/" }, { H1, "http://x.y.com/", "http://x.y.com/" }, // { H1, "site;sub:.html", H1"/site;sub:.html" }, #undef H1 #define H1 "http://x.tld/" { H1, "", H1"" }, { H1, ".", H1"" }, { H1, "./", H1"" }, { H1, "..", H1"" }, { H1, "../", H1"" }, { H1, "foo", H1"foo" }, { H1, "foo/bar", H1"foo/bar" }, { H1, "foo///bar", H1"foo/bar" }, { H1, "foo/.", H1"foo/" }, { H1, "foo/./", H1"foo/" }, { H1, "foo./", H1"foo./" }, { H1, "foo/../bar", H1"bar" }, { H1, "foo/../bar/", H1"bar/" }, { H1, "foo/bar/..", H1"foo/" }, { H1, "foo/bar/../x", H1"foo/x" }, { H1, "foo/bar/../x/", H1"foo/x/" }, { H1, "foo/..", H1"" }, { H1, "foo/../..", H1"" }, { H1, "foo/../../..", H1"" }, { H1, "foo/../../bar/../../baz", H1"baz" }, { H1, "a/b/../../c", H1"c" }, { H1, "./a/../b", H1"b" }, { H1, "/", H1"" }, { H1, "/.", H1"" }, { H1, "/./", H1"" }, { H1, "/..", H1"" }, { H1, "/../", H1"" }, { H1, "/foo", H1"foo" }, { H1, "/foo/bar", H1"foo/bar" }, { H1, "/foo///bar", H1"foo/bar" }, { H1, "/foo/.", H1"foo/" }, { H1, "/foo/./", H1"foo/" }, { H1, "/foo./", H1"foo./" }, { H1, "/foo/../bar", H1"bar" }, { H1, "/foo/../bar/", H1"bar/" }, { H1, "/foo/bar/..", H1"foo/" }, { H1, "/foo/bar/../x", H1"foo/x" }, { H1, "/foo/bar/../x/", H1"foo/x/" }, { H1, "/foo/..", H1"" }, { H1, "/foo/../..", H1"" }, { H1, "/foo/../../..", H1"" }, { H1, "/foo/../../bar/../../baz", H1"baz" }, { H1, "/a/b/../../c", H1"c" }, { H1, "/./a/../b", H1"b" }, { H1, ".x", H1".x" }, { H1, "..x", H1"..x" }, { H1, "foo/.x", H1"foo/.x" }, { H1, "foo/bar/.x", H1"foo/bar/.x" }, { H1, "foo/..x", H1"foo/..x" }, { H1, "foo/bar/..x", H1"foo/bar/..x" }, { H1, "/x.php?y=ftp://example.com/&z=1_2", H1"x.php?y=ftp://example.com/&z=1_2" }, { H1, "//x.y.com/", "http://x.y.com/" }, { H1, "http://x.y.com/", "http://x.y.com/" }, #undef H1 #define H1 "http://x.tld/file" #define R1 "http://x.tld/" { H1, "", R1"" }, { H1, ".", R1"" }, { H1, "./", R1"" }, { H1, "..", R1"" }, { H1, "../", R1"" }, { H1, "foo", R1"foo" }, { H1, "foo/bar", R1"foo/bar" }, { H1, "foo///bar", R1"foo/bar" }, { H1, "foo/.", R1"foo/" }, { H1, "foo/./", R1"foo/" }, { H1, "foo./", R1"foo./" }, { H1, "foo/../bar", R1"bar" }, { H1, "foo/../bar/", R1"bar/" }, { H1, "foo/bar/..", R1"foo/" }, { H1, "foo/bar/../x", R1"foo/x" }, { H1, "foo/bar/../x/", R1"foo/x/" }, { H1, "foo/..", R1"" }, { H1, "foo/../..", R1"" }, { H1, "foo/../../..", R1"" }, { H1, "foo/../../bar/../../baz", R1"baz" }, { H1, "a/b/../../c", R1"c" }, { H1, "./a/../b", R1"b" }, { H1, "/", R1"" }, { H1, "/.", R1"" }, { H1, "/./", R1"" }, { H1, "/..", R1"" }, { H1, "/../", R1"" }, { H1, "/foo", R1"foo" }, { H1, "/foo/bar", R1"foo/bar" }, { H1, "/foo///bar", R1"foo/bar" }, { H1, "/foo/.", R1"foo/" }, { H1, "/foo/./", R1"foo/" }, { H1, "/foo./", R1"foo./" }, { H1, "/foo/../bar", R1"bar" }, { H1, "/foo/../bar/", R1"bar/" }, { H1, "/foo/bar/..", R1"foo/" }, { H1, "/foo/bar/../x", R1"foo/x" }, { H1, "/foo/bar/../x/", R1"foo/x/" }, { H1, "/foo/..", R1"" }, { H1, "/foo/../..", R1"" }, { H1, "/foo/../../..", R1"" }, { H1, "/foo/../../bar/../../baz", R1"baz" }, { H1, "/a/b/../../c", R1"c" }, { H1, "/./a/../b", R1"b" }, { H1, ".x", R1".x" }, { H1, "..x", R1"..x" }, { H1, "foo/.x", R1"foo/.x" }, { H1, "foo/bar/.x", R1"foo/bar/.x" }, { H1, "foo/..x", R1"foo/..x" }, { H1, "foo/bar/..x", R1"foo/bar/..x" }, { H1, "/x.php?y=ftp://example.com/&z=1_2", R1"x.php?y=ftp://example.com/&z=1_2" }, { H1, "//x.y.com/", "http://x.y.com/" }, { H1, "http://x.y.com/", "http://x.y.com/" }, #undef H1 #undef R1 #define H1 "http://x.tld/dir/" #define R1 "http://x.tld/" { H1, "", H1"" }, { H1, ".", H1"" }, { H1, "./", H1"" }, { H1, "..", R1"" }, { H1, "../", R1"" }, { H1, "foo", H1"foo" }, { H1, "foo/bar", H1"foo/bar" }, { H1, "foo///bar", H1"foo/bar" }, { H1, "foo/.", H1"foo/" }, { H1, "foo/./", H1"foo/" }, { H1, "foo./", H1"foo./" }, { H1, "foo/../bar", H1"bar" }, { H1, "foo/../bar/", H1"bar/" }, { H1, "foo/bar/..", H1"foo/" }, { H1, "foo/bar/../x", H1"foo/x" }, { H1, "foo/bar/../x/", H1"foo/x/" }, { H1, "foo/..", H1"" }, { H1, "foo/../..", R1"" }, { H1, "foo/../../..", R1"" }, { H1, "foo/../../bar/../../baz", R1"baz" }, { H1, "a/b/../../c", H1"c" }, { H1, "./a/../b", H1"b" }, { H1, "/", R1"" }, { H1, "/.", R1"" }, { H1, "/./", R1"" }, { H1, "/..", R1"" }, { H1, "/../", R1"" }, { H1, "/foo", R1"foo" }, { H1, "/foo/bar", R1"foo/bar" }, { H1, "/foo///bar", R1"foo/bar" }, { H1, "/foo/.", R1"foo/" }, { H1, "/foo/./", R1"foo/" }, { H1, "/foo./", R1"foo./" }, { H1, "/foo/../bar", R1"bar" }, { H1, "/foo/../bar/", R1"bar/" }, { H1, "/foo/bar/..", R1"foo/" }, { H1, "/foo/bar/../x", R1"foo/x" }, { H1, "/foo/bar/../x/", R1"foo/x/" }, { H1, "/foo/..", R1"" }, { H1, "/foo/../..", R1"" }, { H1, "/foo/../../..", R1"" }, { H1, "/foo/../../bar/../../baz", R1"baz" }, { H1, "/a/b/../../c", R1"c" }, { H1, "/./a/../b", R1"b" }, { H1, ".x", H1".x" }, { H1, "..x", H1"..x" }, { H1, "foo/.x", H1"foo/.x" }, { H1, "foo/bar/.x", H1"foo/bar/.x" }, { H1, "foo/..x", H1"foo/..x" }, { H1, "foo/bar/..x", H1"foo/bar/..x" }, { H1, "/x.php?y=ftp://example.com/&z=1_2", R1"x.php?y=ftp://example.com/&z=1_2" }, { H1, "//x.y.com/", "http://x.y.com/" }, { H1, "http://x.y.com/", "http://x.y.com/" } #undef H1 #undef R1 }; unsigned it; char uri_buf_static[32]; // use a size that forces allocation in some cases mget_buffer_t *uri_buf = mget_buffer_init(NULL, uri_buf_static, sizeof(uri_buf_static)); mget_iri_t *base; for (it = 0; it < countof(test_data); it++) { const struct iri_test_data *t = &test_data[it]; base = mget_iri_parse(t->base, "utf-8"); mget_iri_relative_to_abs(base, t->relative, strlen(t->relative), uri_buf); if (!strcmp(uri_buf->data, t->result)) ok++; else { failed++; info_printf("Failed [%u]: %s+%s -> %s (expected %s)\n", it, t->base, t->relative, uri_buf->data, t->result); } mget_iri_free(&base); } mget_buffer_free(&uri_buf); }