#include "parse.h"
-gpointer parse(FILE *input, const char *name,
+gpointer parse(const char *name, FILE *input,
GList **data, GList **code);
int main(int argc, char **argv)
{
const char *name = "stdin";
+
/* Parse arguments */
char *option_output = NULL;
GOptionEntry entries[] = {
/* Handle input and output */
FILE *input = stdin;
- if (argv[1] && !g_str_equal(input, "-")) {
+ if (argv[1] && !g_str_equal(argv[1], "-")) {
name = argv[1];
input = fopen(argv[1], "r");
}
/* Start compiling */
GList *data = NULL;
GList *code = NULL;
- parse(input, name, &data, &code);
+ parse(name, 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
<html>
<body>
<% body(); %>
-
- <a><%= "%05.2f" %></a>
</body>
</html>
<% } %>
#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)
--- /dev/null
+# Settings
+PROG = ct
+CC = gcc
+YACC = bison
+LEX = flex
+
+CFLAGS = -Wall -Werror -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: all
-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);
-extern int yylineno;
-static const char *name;
-static GList *code;
-static GList *data;
+static const char *name = NULL;
+static GList *code = NULL;
+static GList *data = NULL;
%}
%error-verbose
%parse-param {gpointer root};
-%token START END DATA FMT 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;
data = g_list_prepend(data, g_strdup_printf(
- "#line %d \"%s\"\n"
"static char data%d[] = \"%s\";\n",
- yylineno, name, i, g_strescape($1, "")));
+ i, g_strescape($1, "")));
code = g_list_prepend(code, g_strdup_printf(
- "#line %d \"%s\"\n"
"fwrite(data%d, sizeof(data%d)-1, 1, stdout);\n",
- yylineno, name, i, i));
+ i, i));
i++;
};
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 FMT DATA END {
- code = g_list_prepend(code, g_strdup_printf("printf(%s);\n", $3));
+out : START OUT DATA END {
+ code = g_list_prepend(code, g_strdup_printf("printf(\"%%s\", %s);\n", $3));
};
-print : 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, const char *_name,
+gpointer parse(const char *_name, FILE *_input,
GList **_data, GList **_code)
{
- yyin = input;
name = _name;
+ yyin = _input;
yyparse(NULL);
*_data = data;
*_code = code;
%option nounput
%option noinput
%option yylineno
+%option never-interactive
/* %option nodebug */
START [ \t]*<%
END [ \t]*%>