Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Converted to Xcode8 / Swift 3 #4

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -147,3 +147,8 @@ Pods/
# Carthage
Carthage.pkg
Carthage/Build

# Swift PM
.build
.swiftpm
Hoedown.xcodeproj
1 change: 0 additions & 1 deletion Cartfile

This file was deleted.

1 change: 0 additions & 1 deletion Cartfile.resolved

This file was deleted.

1 change: 0 additions & 1 deletion Carthage/Checkouts/hoedown
Submodule hoedown deleted from 2a5eed
31 changes: 31 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// swift-tools-version:5.3
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription

let package = Package(
name: "SwiftHoedown",
products: [
.library(
name: "SwiftHoedown",
targets: ["SwiftHoedown"]
),
.executable(
name: "DemoApp",
targets: ["DemoApp"]
)
],
targets: [
.target(
name: "SwiftHoedown",
dependencies: ["CHoedown"]),
.target(
name: "DemoApp",
dependencies: ["SwiftHoedown"]),
.target(
name: "CHoedown",
dependencies: []),
.testTarget(
name: "HoedownTest",
dependencies: ["SwiftHoedown"])
]
)
281 changes: 281 additions & 0 deletions Sources/CHoedown/autolink.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,281 @@
#include "autolink.h"

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>

#ifndef _MSC_VER
#include <strings.h>
#else
#define strncasecmp _strnicmp
#endif

int
hoedown_autolink_is_safe(const uint8_t *data, size_t size)
{
static const size_t valid_uris_count = 6;
static const char *valid_uris[] = {
"http://", "https://", "/", "#", "ftp://", "mailto:"
};
static const size_t valid_uris_size[] = { 7, 8, 1, 1, 6, 7 };
size_t i;

for (i = 0; i < valid_uris_count; ++i) {
size_t len = valid_uris_size[i];

if (size > len &&
strncasecmp((char *)data, valid_uris[i], len) == 0 &&
isalnum(data[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 (strchr(".:", data[i]) != NULL) 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
hoedown_autolink__www(
size_t *rewind_p,
hoedown_buffer *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;

hoedown_buffer_put(link, data, link_end);
*rewind_p = 0;

return (int)link_end;
}

size_t
hoedown_autolink__email(
size_t *rewind_p,
hoedown_buffer *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[-1 - rewind];

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 ||
!isalpha(data[link_end - 1]))
return 0;

link_end = autolink_delim(data, link_end, max_rewind, size);

if (link_end == 0)
return 0;

hoedown_buffer_put(link, data - rewind, link_end + rewind);
*rewind_p = rewind;

return link_end;
}

size_t
hoedown_autolink__url(
size_t *rewind_p,
hoedown_buffer *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[-1 - rewind]))
rewind++;

if (!hoedown_autolink_is_safe(data - rewind, size + rewind))
return 0;

link_end = strlen("://");

domain_len = check_domain(
data + link_end,
size - link_end,
flags & HOEDOWN_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;

hoedown_buffer_put(link, data - rewind, link_end + rewind);
*rewind_p = rewind;

return link_end;
}
Loading