Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Symlinks? Yeah, no thanks

commit 04c57c805c99776fba85067a58067b17dee444a0 1 parent 4e46727
@vmg authored
View
10 Rakefile
@@ -50,7 +50,7 @@ file package('.gem') => %w[pkg/ rinku.gemspec] + $spec.files do |f|
end
# GEMSPEC HELPERS ==========================================================
-task :gather => 'sundown/src/autolink.h' do |t|
+task :gather => 'sundown:checkout' do |t|
files =
FileList[
'sundown/src/{buffer,autolink}.h',
@@ -61,7 +61,9 @@ task :gather => 'sundown/src/autolink.h' do |t|
:verbose => true
end
-
-file 'sundown/src/autolink.h' do |t|
- abort "The Sundown submodule is required."
+task 'sundown:checkout' do |t|
+ unless File.exists?('sundown/src/markdown.h')
+ sh 'git submodule init'
+ sh 'git submodule update'
+ end
end
View
1  ext/rinku/autolink.c
View
296 ext/rinku/autolink.c
@@ -0,0 +1,296 @@
+/*
+ * Copyright (c) 2011, Vicent Marti
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "buffer.h"
+#include "autolink.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#if defined(_WIN32)
+#define strncasecmp _strnicmp
+#endif
+
+int
+sd_autolink_issafe(const uint8_t *link, size_t link_len)
+{
+ static const size_t valid_uris_count = 5;
+ static const char *valid_uris[] = {
+ "/", "http://", "https://", "ftp://", "mailto:"
+ };
+
+ size_t i;
+
+ for (i = 0; i < valid_uris_count; ++i) {
+ size_t len = strlen(valid_uris[i]);
+
+ if (link_len > len &&
+ strncasecmp((char *)link, valid_uris[i], len) == 0 &&
+ isalnum(link[len]))
+ return 1;
+ }
+
+ return 0;
+}
+
+static size_t
+autolink_delim(uint8_t *data, size_t link_end, size_t max_rewind, size_t size)
+{
+ uint8_t cclose, copen = 0;
+ size_t i;
+
+ for (i = 0; i < link_end; ++i)
+ if (data[i] == '<') {
+ link_end = i;
+ break;
+ }
+
+ while (link_end > 0) {
+ if (strchr("?!.,", data[link_end - 1]) != NULL)
+ link_end--;
+
+ else if (data[link_end - 1] == ';') {
+ size_t new_end = link_end - 2;
+
+ while (new_end > 0 && isalpha(data[new_end]))
+ new_end--;
+
+ if (new_end < link_end - 2 && data[new_end] == '&')
+ link_end = new_end;
+ else
+ link_end--;
+ }
+ else break;
+ }
+
+ if (link_end == 0)
+ return 0;
+
+ cclose = data[link_end - 1];
+
+ switch (cclose) {
+ case '"': copen = '"'; break;
+ case '\'': copen = '\''; break;
+ case ')': copen = '('; break;
+ case ']': copen = '['; break;
+ case '}': copen = '{'; break;
+ }
+
+ if (copen != 0) {
+ size_t closing = 0;
+ size_t opening = 0;
+ size_t i = 0;
+
+ /* Try to close the final punctuation sign in this same line;
+ * if we managed to close it outside of the URL, that means that it's
+ * not part of the URL. If it closes inside the URL, that means it
+ * is part of the URL.
+ *
+ * Examples:
+ *
+ * foo http://www.pokemon.com/Pikachu_(Electric) bar
+ * => http://www.pokemon.com/Pikachu_(Electric)
+ *
+ * foo (http://www.pokemon.com/Pikachu_(Electric)) bar
+ * => http://www.pokemon.com/Pikachu_(Electric)
+ *
+ * foo http://www.pokemon.com/Pikachu_(Electric)) bar
+ * => http://www.pokemon.com/Pikachu_(Electric))
+ *
+ * (foo http://www.pokemon.com/Pikachu_(Electric)) bar
+ * => foo http://www.pokemon.com/Pikachu_(Electric)
+ */
+
+ while (i < link_end) {
+ if (data[i] == copen)
+ opening++;
+ else if (data[i] == cclose)
+ closing++;
+
+ i++;
+ }
+
+ if (closing != opening)
+ link_end--;
+ }
+
+ return link_end;
+}
+
+static size_t
+check_domain(uint8_t *data, size_t size, int allow_short)
+{
+ size_t i, np = 0;
+
+ if (!isalnum(data[0]))
+ return 0;
+
+ for (i = 1; i < size - 1; ++i) {
+ if (data[i] == '.') np++;
+ else if (!isalnum(data[i]) && data[i] != '-') break;
+ }
+
+ if (allow_short) {
+ /* We don't need a valid domain in the strict sense (with
+ * least one dot; so just make sure it's composed of valid
+ * domain characters and return the length of the the valid
+ * sequence. */
+ return i;
+ } else {
+ /* a valid domain needs to have at least a dot.
+ * that's as far as we get */
+ return np ? i : 0;
+ }
+}
+
+size_t
+sd_autolink__www(
+ size_t *rewind_p,
+ struct buf *link,
+ uint8_t *data,
+ size_t max_rewind,
+ size_t size,
+ unsigned int flags)
+{
+ size_t link_end;
+
+ if (max_rewind > 0 && !ispunct(data[-1]) && !isspace(data[-1]))
+ return 0;
+
+ if (size < 4 || memcmp(data, "www.", strlen("www.")) != 0)
+ return 0;
+
+ link_end = check_domain(data, size, 0);
+
+ if (link_end == 0)
+ return 0;
+
+ while (link_end < size && !isspace(data[link_end]))
+ link_end++;
+
+ link_end = autolink_delim(data, link_end, max_rewind, size);
+
+ if (link_end == 0)
+ return 0;
+
+ bufput(link, data, link_end);
+ *rewind_p = 0;
+
+ return (int)link_end;
+}
+
+size_t
+sd_autolink__email(
+ size_t *rewind_p,
+ struct buf *link,
+ uint8_t *data,
+ size_t max_rewind,
+ size_t size,
+ unsigned int flags)
+{
+ size_t link_end, rewind;
+ int nb = 0, np = 0;
+
+ for (rewind = 0; rewind < max_rewind; ++rewind) {
+ uint8_t c = data[-rewind - 1];
+
+ if (isalnum(c))
+ continue;
+
+ if (strchr(".+-_", c) != NULL)
+ continue;
+
+ break;
+ }
+
+ if (rewind == 0)
+ return 0;
+
+ for (link_end = 0; link_end < size; ++link_end) {
+ uint8_t c = data[link_end];
+
+ if (isalnum(c))
+ continue;
+
+ if (c == '@')
+ nb++;
+ else if (c == '.' && link_end < size - 1)
+ np++;
+ else if (c != '-' && c != '_')
+ break;
+ }
+
+ if (link_end < 2 || nb != 1 || np == 0)
+ return 0;
+
+ link_end = autolink_delim(data, link_end, max_rewind, size);
+
+ if (link_end == 0)
+ return 0;
+
+ bufput(link, data - rewind, link_end + rewind);
+ *rewind_p = rewind;
+
+ return link_end;
+}
+
+size_t
+sd_autolink__url(
+ size_t *rewind_p,
+ struct buf *link,
+ uint8_t *data,
+ size_t max_rewind,
+ size_t size,
+ unsigned int flags)
+{
+ size_t link_end, rewind = 0, domain_len;
+
+ if (size < 4 || data[1] != '/' || data[2] != '/')
+ return 0;
+
+ while (rewind < max_rewind && isalpha(data[-rewind - 1]))
+ rewind++;
+
+ if (!sd_autolink_issafe(data - rewind, size + rewind))
+ return 0;
+
+ link_end = strlen("://");
+
+ domain_len = check_domain(
+ data + link_end,
+ size - link_end,
+ flags & SD_AUTOLINK_SHORT_DOMAINS);
+
+ if (domain_len == 0)
+ return 0;
+
+ link_end += domain_len;
+ while (link_end < size && !isspace(data[link_end]))
+ link_end++;
+
+ link_end = autolink_delim(data, link_end, max_rewind, size);
+
+ if (link_end == 0)
+ return 0;
+
+ bufput(link, data - rewind, link_end + rewind);
+ *rewind_p = rewind;
+
+ return link_end;
+}
+
View
1  ext/rinku/autolink.h
View
51 ext/rinku/autolink.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2011, Vicent Marti
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef UPSKIRT_AUTOLINK_H
+#define UPSKIRT_AUTOLINK_H
+
+#include "buffer.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum {
+ SD_AUTOLINK_SHORT_DOMAINS = (1 << 0),
+};
+
+int
+sd_autolink_issafe(const uint8_t *link, size_t link_len);
+
+size_t
+sd_autolink__www(size_t *rewind_p, struct buf *link,
+ uint8_t *data, size_t offset, size_t size, unsigned int flags);
+
+size_t
+sd_autolink__email(size_t *rewind_p, struct buf *link,
+ uint8_t *data, size_t offset, size_t size, unsigned int flags);
+
+size_t
+sd_autolink__url(size_t *rewind_p, struct buf *link,
+ uint8_t *data, size_t offset, size_t size, unsigned int flags);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/* vim: set filetype=c: */
View
1  ext/rinku/buffer.c
View
225 ext/rinku/buffer.c
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2008, Natacha Porté
+ * Copyright (c) 2011, Vicent Martí
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define BUFFER_MAX_ALLOC_SIZE (1024 * 1024 * 16) //16mb
+
+#include "buffer.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+/* MSVC compat */
+#if defined(_MSC_VER)
+# define _buf_vsnprintf _vsnprintf
+#else
+# define _buf_vsnprintf vsnprintf
+#endif
+
+int
+bufprefix(const struct buf *buf, const char *prefix)
+{
+ size_t i;
+ assert(buf && buf->unit);
+
+ for (i = 0; i < buf->size; ++i) {
+ if (prefix[i] == 0)
+ return 0;
+
+ if (buf->data[i] != prefix[i])
+ return buf->data[i] - prefix[i];
+ }
+
+ return 0;
+}
+
+/* bufgrow: increasing the allocated size to the given value */
+int
+bufgrow(struct buf *buf, size_t neosz)
+{
+ size_t neoasz;
+ void *neodata;
+
+ assert(buf && buf->unit);
+
+ if (neosz > BUFFER_MAX_ALLOC_SIZE)
+ return BUF_ENOMEM;
+
+ if (buf->asize >= neosz)
+ return BUF_OK;
+
+ neoasz = buf->asize + buf->unit;
+ while (neoasz < neosz)
+ neoasz += buf->unit;
+
+ neodata = realloc(buf->data, neoasz);
+ if (!neodata)
+ return BUF_ENOMEM;
+
+ buf->data = neodata;
+ buf->asize = neoasz;
+ return BUF_OK;
+}
+
+
+/* bufnew: allocation of a new buffer */
+struct buf *
+bufnew(size_t unit)
+{
+ struct buf *ret;
+ ret = malloc(sizeof (struct buf));
+
+ if (ret) {
+ ret->data = 0;
+ ret->size = ret->asize = 0;
+ ret->unit = unit;
+ }
+ return ret;
+}
+
+/* bufnullterm: NULL-termination of the string array */
+const char *
+bufcstr(struct buf *buf)
+{
+ assert(buf && buf->unit);
+
+ if (buf->size < buf->asize && buf->data[buf->size] == 0)
+ return (char *)buf->data;
+
+ if (buf->size + 1 <= buf->asize || bufgrow(buf, buf->size + 1) == 0) {
+ buf->data[buf->size] = 0;
+ return (char *)buf->data;
+ }
+
+ return NULL;
+}
+
+/* bufprintf: formatted printing to a buffer */
+void
+bufprintf(struct buf *buf, const char *fmt, ...)
+{
+ va_list ap;
+ int n;
+
+ assert(buf && buf->unit);
+
+ if (buf->size >= buf->asize && bufgrow(buf, buf->size + 1) < 0)
+ return;
+
+ va_start(ap, fmt);
+ n = _buf_vsnprintf((char *)buf->data + buf->size, buf->asize - buf->size, fmt, ap);
+ va_end(ap);
+
+ if (n < 0) {
+#ifdef _MSC_VER
+ va_start(ap, fmt);
+ n = _vscprintf(fmt, ap);
+ va_end(ap);
+#else
+ return;
+#endif
+ }
+
+ if ((size_t)n >= buf->asize - buf->size) {
+ if (bufgrow(buf, buf->size + n + 1) < 0)
+ return;
+
+ va_start(ap, fmt);
+ n = _buf_vsnprintf((char *)buf->data + buf->size, buf->asize - buf->size, fmt, ap);
+ va_end(ap);
+ }
+
+ if (n < 0)
+ return;
+
+ buf->size += n;
+}
+
+/* bufput: appends raw data to a buffer */
+void
+bufput(struct buf *buf, const void *data, size_t len)
+{
+ assert(buf && buf->unit);
+
+ if (buf->size + len > buf->asize && bufgrow(buf, buf->size + len) < 0)
+ return;
+
+ memcpy(buf->data + buf->size, data, len);
+ buf->size += len;
+}
+
+/* bufputs: appends a NUL-terminated string to a buffer */
+void
+bufputs(struct buf *buf, const char *str)
+{
+ bufput(buf, str, strlen(str));
+}
+
+
+/* bufputc: appends a single uint8_t to a buffer */
+void
+bufputc(struct buf *buf, int c)
+{
+ assert(buf && buf->unit);
+
+ if (buf->size + 1 > buf->asize && bufgrow(buf, buf->size + 1) < 0)
+ return;
+
+ buf->data[buf->size] = c;
+ buf->size += 1;
+}
+
+/* bufrelease: decrease the reference count and free the buffer if needed */
+void
+bufrelease(struct buf *buf)
+{
+ if (!buf)
+ return;
+
+ free(buf->data);
+ free(buf);
+}
+
+
+/* bufreset: frees internal data of the buffer */
+void
+bufreset(struct buf *buf)
+{
+ if (!buf)
+ return;
+
+ free(buf->data);
+ buf->data = NULL;
+ buf->size = buf->asize = 0;
+}
+
+/* bufslurp: removes a given number of bytes from the head of the array */
+void
+bufslurp(struct buf *buf, size_t len)
+{
+ assert(buf && buf->unit);
+
+ if (len >= buf->size) {
+ buf->size = 0;
+ return;
+ }
+
+ buf->size -= len;
+ memmove(buf->data, buf->data + len, buf->size);
+}
+
View
1  ext/rinku/buffer.h
View
96 ext/rinku/buffer.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2008, Natacha Porté
+ * Copyright (c) 2011, Vicent Martí
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef BUFFER_H__
+#define BUFFER_H__
+
+#include <stddef.h>
+#include <stdarg.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(_MSC_VER)
+#define __attribute__(x)
+#define inline
+#endif
+
+typedef enum {
+ BUF_OK = 0,
+ BUF_ENOMEM = -1,
+} buferror_t;
+
+/* struct buf: character array buffer */
+struct buf {
+ uint8_t *data; /* actual character data */
+ size_t size; /* size of the string */
+ size_t asize; /* allocated size (0 = volatile buffer) */
+ size_t unit; /* reallocation unit size (0 = read-only buffer) */
+};
+
+/* CONST_BUF: global buffer from a string litteral */
+#define BUF_STATIC(string) \
+ { (uint8_t *)string, sizeof string -1, sizeof string, 0, 0 }
+
+/* VOLATILE_BUF: macro for creating a volatile buffer on the stack */
+#define BUF_VOLATILE(strname) \
+ { (uint8_t *)strname, strlen(strname), 0, 0, 0 }
+
+/* BUFPUTSL: optimized bufputs of a string litteral */
+#define BUFPUTSL(output, literal) \
+ bufput(output, literal, sizeof literal - 1)
+
+/* bufgrow: increasing the allocated size to the given value */
+int bufgrow(struct buf *, size_t);
+
+/* bufnew: allocation of a new buffer */
+struct buf *bufnew(size_t) __attribute__ ((malloc));
+
+/* bufnullterm: NUL-termination of the string array (making a C-string) */
+const char *bufcstr(struct buf *);
+
+/* bufprefix: compare the beginning of a buffer with a string */
+int bufprefix(const struct buf *buf, const char *prefix);
+
+/* bufput: appends raw data to a buffer */
+void bufput(struct buf *, const void *, size_t);
+
+/* bufputs: appends a NUL-terminated string to a buffer */
+void bufputs(struct buf *, const char *);
+
+/* bufputc: appends a single char to a buffer */
+void bufputc(struct buf *, int);
+
+/* bufrelease: decrease the reference count and free the buffer if needed */
+void bufrelease(struct buf *);
+
+/* bufreset: frees internal data of the buffer */
+void bufreset(struct buf *);
+
+/* bufslurp: removes a given number of bytes from the head of the array */
+void bufslurp(struct buf *, size_t);
+
+/* bufprintf: formatted printing to a buffer */
+void bufprintf(struct buf *, const char *, ...) __attribute__ ((format (printf, 2, 3)));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Please sign in to comment.
Something went wrong with that request. Please try again.