#include "parse.h"
-gpointer parse(FILE *input, GList **data, GList **code);
+gpointer parse(char *name, FILE *input, GList **data, GList **code);
int main(int argc, char **argv)
{
/* Handle input and output */
FILE *input = stdin;
- if (argv[1] && !g_str_equal(input, "-"))
+ if (argv[1] && !g_str_equal(argv[1], "-"))
input = fopen(argv[1], "r");
if (!input)
g_error("invalid input file");
/* Start compiling */
GList *data = NULL;
GList *code = NULL;
- parse(input, &data, &code);
+ parse(argv[1], input, &data, &code);
data = g_list_reverse(data);
code = g_list_reverse(code);
--- /dev/null
+#ifndef CT_H
+#define CT_H
+
+/* Misc */
+void ct_print_header(const char *content_type, const char *charset);
+
+/* Environment */
+const gchar *ct_get_query_string(void);
+
+const gchar *ct_get_path_info(void);
+
+const GHashTable *ct_get_query(void);
+
+/* Markup escaping */
+void ct_use_escape(void);
+
+#endif
#include <glib.h>
#include <glib/gstdio.h>
+#include <ct.h>
#include "html.h"
-void resize(gchar *orig, gchar *thumb)
+void resize(gchar *orig, gchar *thumb, gchar *size)
{
- gchar *argv[] = {"convert", "-resize", "200x200", orig, thumb, NULL};
+ gchar *argv[] = {"convert", "-resize", size, orig, thumb, NULL};
/* god damn glib */
g_spawn_sync(NULL, argv, NULL, G_SPAWN_SEARCH_PATH,
NULL, NULL, NULL, NULL, NULL, NULL);
GList *gen_thumbs(GList *images)
{
- if (!g_file_test("thumbs", G_FILE_TEST_EXISTS))
- g_mkdir("thumbs", 0644);
- if (!g_file_test("images", G_FILE_TEST_EXISTS))
- g_mkdir("images", 0644);
+ if (!g_file_test("large", G_FILE_TEST_EXISTS)) g_mkdir("large", 0775);
+ if (!g_file_test("small", G_FILE_TEST_EXISTS)) g_mkdir("small", 0775);
+ if (!g_file_test("thumb", G_FILE_TEST_EXISTS)) g_mkdir("thumb", 0775);
for (GList *cur = images; cur; cur = cur->next) {
gchar *name = cur->data;
- gchar *thumb = g_strconcat("thumbs/", name, NULL);
- gchar *image = g_strconcat("images/", name, NULL);
- if (!g_file_test(thumb, G_FILE_TEST_EXISTS))
- resize(image, thumb);
+ gchar *large = g_build_filename("large", name, NULL);
+ gchar *small = g_build_filename("small", name, NULL);
+ gchar *thumb = g_build_filename("thumb", name, NULL);
+ if (!g_file_test(thumb, G_FILE_TEST_EXISTS)) {
+ resize(large, thumb, "200x200");
+ resize(large, small, "800x800");
+ }
+ g_free(large);
+ g_free(small);
g_free(thumb);
- g_free(image);
}
return images;
}
GList *images = NULL;
while ((name = g_dir_read_name(dir)))
images = g_list_prepend(images, g_strdup(name));
+ images = g_list_sort(images, (GCompareFunc)g_strcmp0);
return images;
}
int main()
{
- header();
- g_print("\n");
+ ct_print_header("text/html", NULL);
- const gchar *query_string = g_getenv("QUERY_STRING");
- if (query_string == NULL)
+ const gchar *path = ct_get_path_info();
+ const gchar *query = ct_get_query_string();
+
+ GList *thumbs = gen_thumbs(read_dir("large"));
+
+ if (!path || g_str_equal(path, "/"))
frame_index();
- else if (g_str_equal(query_string, "noframe"))
- frame_nav(TRUE, gen_thumbs(read_dir("images")));
- else if (g_str_equal(query_string, "nav"))
- frame_nav(FALSE, gen_thumbs(read_dir("images")));
- else if (g_str_equal(query_string, "head"))
+ else if (g_str_equal(path, "/head"))
frame_head();
- else if (g_str_equal(query_string, "content"))
- frame_content();
- else
- frame_index();
+ else if (g_str_equal(path, "/nav"))
+ frame_nav(FALSE, thumbs);
+ else if (g_str_equal(path, "/noframe"))
+ frame_nav(TRUE, thumbs);
+ else if (g_str_equal(path, "/show_small"))
+ frame_show("small", "show_large", query);
+ else if (g_str_equal(path, "/show_large"))
+ frame_show("large", "show_small", query);
}
+++ /dev/null
-Options +ExecCGI
-AddHandler cgi-script .bin
-RewriteEngine on
-RewriteRule ^$ "index.bin"
--- /dev/null
+Options +ExecCGI
+AddHandler cgi-script .bin
+RewriteEngine on
+RewriteRule ^(?!thumb/|small/|large/|images/|mid/|index.bin).*$ "index.bin/$0"
<% #include <glib.h> %>
-
-<% void header() { %>
-Content-Type: text/html; charset=UTF-8
-<% } %>
-
-
<% void frame_index(){ %>
<html>
<frameset rows="20, *">
- <frame name="head" src="?head">
+ <frame name="head" src="head">
<frameset cols="248,*">
- <frame name="nav" src="?nav">
- <frame name="content" src="?content">
+ <frame name="nav" src="nav">
+ <frame name="content" src="content">
</frameset>
</frameset>
</html>
</head>
<body>
<center>
- <a href="?noframe" target="parent">No Frames</a>
+ <a href="noframe" target="parent">No Frames</a>
</center>
</body>
</html>
<% for (GList *cur = images; cur; cur = cur->next) { %>
<% gchar *img = (gchar *)cur->data; %>
<div class="align">
- <a class="box" target="content" href="images/<%= "%s", img %>">
- <img src="thumbs/<%= "%s", img %>"></a>
+ <a class="box" target="content" href="show_small?<%= "%s", img %>">
+ <img src="thumb/<%= "%s", img %>"></a>
</div>
<% } %>
</body>
</html>
<% } %>
-
-<% void frame_content(){ %>
-<html>
-</html>
+<% void frame_show(char *this, char *link, char *image){ %>
+<html>
+ <body style="text-align:center;">
+ <a href="<%= "%s?%s", link, image %>">
+ <img src="<%= "%s/%s", this, image %>">
+ </a>
+ </body>
+</html>
<% } %>
void frame_nav(int square, GList *images);
-void frame_content();
+void frame_show();
-PROGS=gallery
-PKGS=glib-2.0
-CLEAN=html.c
+PROGS = gallery
+PKGS = glib-2.0
+CLEAN = html.c
+CPPFLAGS = -I..
+CFLAGS = --std=c99 -Wall -Wno-format -g
-default:V: run
-gallery: gallery.o html.o
+default:V: gallery
+ QUERY_STRING=foo ./gallery
+
+gallery: gallery.o html.o ../lib.o
<../mkcommon
--- /dev/null
+#!/bin/bash
+
+mkdir -p large small thumb
+mv "$@" large
+
+chgrp apache small thumb
+chmod 775 small thumb
+
+ln -s ~/git/ct/gallery/gallery index.bin
+ln -s ~/git/ct/gallery/htaccess .htaccess
#define _GNU_SOURCE
+#include <glib.h>
#include <stdio.h>
#include <stdlib.h>
#include <printf.h>
+/* Misc */
+void ct_print_header(const char *content_type, const char *charset)
+{
+ if (!content_type) content_type = "text/html";
+ if (!charset) charset = "UTF-8";
+ printf("Content-Type: %s; charset=%s\n\n",
+ content_type, charset);
+}
+
+/* Environment */
+const gchar *ct_get_path_info(void)
+{
+ return g_getenv("PATH_INFO") ?: "";
+}
+
+const gchar *ct_get_query_string(void)
+{
+ return g_getenv("QUERY_STRING") ?: "";
+}
+
+const GHashTable *ct_get_query(void)
+{
+ const gchar *query_string = g_getenv("QUERY_STRING");
+ GHashTable *query = g_hash_table_new(g_str_hash, g_str_equal);
+ if (query_string) {
+ gchar **vars = g_strsplit(query_string, "&", -1);
+ for (int i = 0; vars[i]; i++) {
+ gchar **parts = g_strsplit(vars[i], "=", 2);
+ gchar *lhs = parts[0] ? parts[0] : "";
+ gchar *rhs = parts[0] && parts[1] ? parts[1] : "";
+ g_hash_table_insert(query, lhs, rhs);
+ g_free(parts); // keep lhs/rhs
+ }
+ g_strfreev(vars);
+ }
+ return query;
+}
+
+/* Markup escaping */
static int printf_markup(FILE *stream,
const struct printf_info *info,
const void *const *args)
register_printf_specifier('M', printf_markup, printf_markup_arginfo);
}
-int main(void)
+void ct_test(void)
{
ct_use_escape();
printf("%M\n", "<Hello, World>");
printf("%M\n", "<Hello, World>");
printf("%M\n", "<Hello, World>");
- return 0;
}
--- /dev/null
+# Settings
+PROG = ct
+CC = gcc
+YACC = bison
+LEX = flex
+
+CFLAGS = -Wall -g --std=c99
+CPPFLAGS = $(shell pkg-config --cflags glib-2.0)
+LDFLAGS = $(shell pkg-config --libs glib-2.0)
+
+# Targets
+default: test
+
+all: $(PROG)
+
+test: $(PROG)
+ ./$(PROG) example/html.ct
+
+clean:
+ rm -f $(PROG) *.o *.a parse.h parse.c scan.c
+
+# Rules
+$(PROG): ct.o parse.o scan.o
+ $(CC) $(CFLAGS) -o $@ $+ $(LDFLAGS)
+
+%.o: %.c parse.h
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
+
+%.c: %.l parse.h
+ $(LEX) -o $@ $<
+
+%.c %.h: %.y
+ $(YACC) -d -o $*.c $*.y
+
+.SECONDARY:
+++ /dev/null
-%.c: %.ct
- (cd .. && mk)
- ../ct <$prereq >$target
- ex +'norm gg=G' +'wq' $target
-
-<$HOME/lib/mkcommon
+++ /dev/null
-PROGS=ct lib
-PKGS=glib-2.0
-default:V: run
-lib-run:V: lib
- ./lib
-ct-run:V: ct
- ./ct < example/html.ct
-ct: ct.o parse.o scan.o
-ct.o: parse.h
-parse.h parse.c: parse.y
- bison -d -o parse.c parse.y
-scan.c: scan.l parse.h
- flex -o scan.c scan.l
-CLEAN=parse.h parse.c scan.c
-<$HOME/lib/mkcommon
#include <stdio.h>
#include <glib.h>
extern FILE *yyin;
+extern int yylineno;
int yylex(void);
void yyerror(gpointer node, char const *s);
+static char *name = NULL;
static GList *code = NULL;
static GList *data = NULL;
%}
%error-verbose
%parse-param {gpointer root};
-%token START END DATA OUT
+%token START END DATA OUT FMT
%%
input : all | all input ;
-all : data | code | print ;
+all : data | code | out | fmt ;
data : DATA {
static int i = 0;
};
code : START DATA END {
+ code = g_list_prepend(code, g_strdup_printf("#line %d \"%s\"\n", yylineno, name));
code = g_list_prepend(code, g_strdup_printf("%s\n", $2));
};
-print : START OUT DATA END {
+out : START OUT DATA END {
+ code = g_list_prepend(code, g_strdup_printf("printf(\"%%s\", %s);\n", $3));
+};
+
+fmt : START FMT DATA END {
code = g_list_prepend(code, g_strdup_printf("printf(%s);\n", $3));
};
%%
-gpointer parse(FILE *input, GList **_data, GList **_code) {
- yyin = input;
+gpointer parse(char *_name, FILE *_input, GList **_data, GList **_code) {
+ name = _name;
+ yyin = _input;
yyparse(NULL);
*_data = data;
*_code = code;
%option noyywrap
%option nounput
%option noinput
+%option yylineno
+%option never-interactive
/* %option nodebug */
START [ \t]*<%
END [ \t]*%>[ \t]*
DATA ([^<\n]|<[^%])*\n*
CODE [ \t\n]([^%\n]|%[^>])*\n*
-%s IN FMT
+%s IN
%%
[[:space:]]*\n { debug("NL [%s]"); }
<INITIAL>{START} { debug("START [%s]"); yylval = g_strdup(yytext); BEGIN(IN); return START; }
<INITIAL>{DATA} { debug("DATA [%s]"); yylval = g_strdup(yytext); return DATA; }
<IN>{END} { debug("END [%s]"); yylval = g_strdup(yytext); BEGIN(INITIAL); return END; }
<IN>= { debug("OUT [%s]"); yylval = g_strdup(yytext); return OUT; }
+<IN>% { debug("FMT [%s]"); yylval = g_strdup(yytext); return FMT; }
<IN>{CODE} { debug("CODE [%s]"); yylval = g_strdup(yytext); return DATA; }
%%