replace_html_tag :: (
buffer: *String_Builder,
current: u8,
i_ptr: *int,
post: string,
uri: string,
dont_show_images: bool
)
-> result: string
{
if is_heading(current, i_ptr.*, post, .OPEN) {
return replace_heading(buffer, current, i_ptr, post, uri);
}
else if is_image(current, i_ptr.*, post) {
return replace_image(buffer, i_ptr, post, uri, dont_show_images);
}
return "";
}
replace_image :: (
buffer: *String_Builder,
i_ptr: *int,
post: string,
uri: string,
dont_show_images: bool,
)
-> result: string
{
/** Reminder: pop() advanced already */
initial_idx := i_ptr.* - 1;
tag_img := parser_consume_including(initial_idx, post, "/>");
bail(tag_img, "/>");
tag_open := parser_consume_including(0, tag_img, "\"");
src_path := parser_consume_till(tag_open.count, tag_img, "\"");
tag_closed := parser_consume_including(tag_open.count + src_path.count, tag_img, "/>");
offset := tag_open.count + src_path.count + tag_closed.count - 1;
advance_by(i_ptr, offset);
src_path_new, src_path_resized := img_update_path(uri, src_path);
src_path_new_absolute := tprint("%/%", DIR_WWW_IMAGES, src_path_new);
src_path_resized_absolute := tprint("%/%", DIR_WWW_IMAGES, src_path_resized);
src_path_new_relative := tprint("%/%", SUBDIR_IMAGES, src_path_new);
src_path_resized_relative := tprint("%/%", SUBDIR_IMAGES, src_path_resized);
img_copy_to(src_path, src_path_new_absolute);
img_resize_and_copy_to(src_path, src_path_resized_absolute);
img_src := ifx dont_show_images then "" else src_path_resized_relative;
img_new := tprint("%%%",
tag_open,
img_src,
tag_closed
);
new := create_link(src_path_new_relative, img_new, target="blank", prefix="");
return new;
}
replace_heading :: (
buffer: *String_Builder,
current: u8,
i_ptr: *int,
post: string,
url: string
)
-> result: string
{
/** Reminder: pop() advanced already */
initial_idx := i_ptr.* - 1;
tag_open := parser_consume_including(i_ptr.* - 1, post, #char ">");
bail(tag_open, ">");
advance_by(i_ptr, tag_open);
title := parser_consume_till(i_ptr.* - 1, post, #char "<");
bail(title, "<");
advance_by(i_ptr, title);
maybe_tag_closed := is_heading(current, i_ptr.*, post, .CLOSED);
if !maybe_tag_closed return "";
tag_closed := parser_consume_including(i_ptr.* - 1, post, #char ">");
bail(tag_closed, ">");
advance_by(i_ptr, tag_closed);
id := create_id(url, title);
tag_with_id := inject_id(tag_open, title, id);
link := create_link(id, title);
new := tprint("%%%",
tag_with_id,
link,
tag_closed
);
return new;
}
replace_reference :: (
buffer: *String_Builder,
i_ptr: *int,
post: string,
url: string
)
-> result: string
{
maybe_ref := is_md_link(post, i_ptr.* - 1);
if !maybe_ref return "";
advance_by(i_ptr, REFERENCE_MARKER);
reference := parser_consume_till(i_ptr.* - 1, post, #char "]");
bail(reference, "]");
advance_by(i_ptr, reference);
id := create_id(url, reference);
link := create_link(id, reference);
return link;
}
#scope_file
OK :: 1;
peek :: () -> u8 #expand {
return parser_peek(`i, `post);
}
peek_forward :: (offset := 1) -> u8 #expand {
return parser_peek_forward(`i, `post, offset);
}
advance_by :: parser_advance_by;
advance_by :: (s: string) #expand {
parser_advance_by(*`i, s);
}
/** Note(adam): h1 is ignored */
is_heading :: (
current: u8, i: int, post: string, kind: enum { OPEN; CLOSED; }
)
-> bool
{
// Assuming the first char is already checked
offset := 1;
next := peek();
if kind == {
case .OPEN;
if next != "h" return false;
case .CLOSED;
if next != "/" && peek_forward() != "h" return false;
offset = 2;
}
maybe_heading := peek_forward(offset);
/* "2" "6" */
if maybe_heading <= 50 && maybe_heading >= 54 return false;
maybe_closed_tag := peek_forward(1 + offset);
if maybe_closed_tag == ">" return true;
return false;
}
is_image :: (current: u8, i: int, post: string) -> bool {
return parser_match(post, "img src=", i);
}
is_md_link :: (post: string, index: int) -> bool {
return parser_match(post, REFERENCE_MARKER, index);
}
inject_id :: (tag_open: string, title: string, url_new: string) -> string {
closed := find_index_from_left(tag_open, ">");
assert(closed != -1); // Cannot happen!
first_part := slice(tag_open, 0, closed);
id := tprint("% id=\"%\">", first_part, url_new);
return id;
}
create_id :: (url: string, s: string) -> string {
normalized_kinda := normalize_string(s);
low := to_lower_copy(normalized_kinda);
id := tprint("%-%", url, low);
return id;
}
create_link :: (url: string, label: string, target := "self", prefix := "#") -> string {
return tprint("%4",
prefix,
url,
target,
label
);
}
img_update_path :: (uri: string, image_name: string) -> (full: string, resized: string) {
without_extension := path_strip_extension(image_name);
file_extension := path_extension(image_name);
full := tprint("%-%", uri, image_name);
resized := tprint(
"%-%-scaled.%", uri, without_extension, file_extension
);
return full, resized;
}
img_copy_to :: (name: string, path_new: string) {
if is_file(path_new) return;
path_old := tprint("%/%", DIR_POSTS_IMAGES, name);
ok := copy_file(path_old, path_new);
if !ok {
report_and_exit(
"Error: Could not copy file. From: '%' to '%'",
path_old, path_new
);
}
}
img_resize_and_copy_to :: (name: string, path_new: string, quality: s32 = 80) {
if is_file(path_new) return;
image_fp := tprint("%/%", DIR_POSTS_IMAGES, name);
width, height, channels: s32;
input: *u8 = stbi_load(to_c_string(image_fp), *width, *height, *channels, 0);
if !input {
report_and_exit("Error: Could not load image from: %", image_fp);
}
if width < PAGE_IMAGE_MAX_WIDTH {
img_copy_to(name, path_new);
return;
}
target_width: s32 = PAGE_IMAGE_MAX_WIDTH;
heightf := cast(float, height);
widthf := cast(float, width);
max_widthf := cast(float, PAGE_IMAGE_MAX_WIDTH);
target_height: s32 = xx (heightf * (max_widthf / widthf));
output := alloc(target_width * target_height * channels);
defer free(output);
if width > PAGE_IMAGE_MAX_WIDTH {
ok := stbir_resize_uint8(
input, width, height, 0,
output, target_width, target_height, 0,
channels
);
if ok != OK then report_and_exit("Error: Could not resize image: %", image_fp);
}
ok := stbi_write_jpg(
to_c_string(path_new), target_width, target_height, channels, output, quality
);
if ok != OK then report_and_exit("Error: Could not save image to: %", path_new);
}
bail :: (returned_str: string, s: string, loc := #caller_location) #expand {
if returned_str return;
report_and_exit(PARSER_ERROR_MSG, `post, s, loc=loc);
}