00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "klone_conf.h"
00012 #include <stdio.h>
00013 #include <stdlib.h>
00014 #include <limits.h>
00015 #include <string.h>
00016 #include <u/libu.h>
00017 #include <klone/klone.h>
00018 #include <klone/translat.h>
00019 #include <klone/parser.h>
00020 #include <klone/utils.h>
00021 #include <klone/codecs.h>
00022
00023 struct code_block_s;
00024
00025 TAILQ_HEAD(code_block_list_s, code_block_s);
00026 struct code_block_s
00027 {
00028 TAILQ_ENTRY(code_block_s) np;
00029 char *buf;
00030 size_t sz;
00031 size_t code_line;
00032 const char *file_in;
00033 };
00034
00035 typedef struct code_block_s code_block_t;
00036 typedef struct code_block_list_s code_block_list_t;
00037
00038 struct lang_c_ctx_s
00039 {
00040 code_block_list_t code_blocks;
00041 trans_info_t *ti;
00042 size_t html_block_cnt;
00043 };
00044
00045 typedef struct lang_c_ctx_s lang_c_ctx_t;
00046
00047 static const char copyright_hdr[] =
00048 "/*\n"
00049 " * Copyright (c) 2005, 2006, 2006 by KoanLogic s.r.l. <http://www.koanlogic.com>\n"
00050 " * All rights reserved.\n"
00051 " *\n"
00052 " * This file is part of KLone, and as such it is subject to the license\n"
00053 " * stated in the LICENSE file which you have received as part of this\n"
00054 " * distribution\n"
00055 " *\n"
00056 " */\n";
00057
00058 static void free_code_block(code_block_t *node)
00059 {
00060 if(node)
00061 {
00062 U_FREE(node->buf);
00063 U_FREE(node);
00064 }
00065 }
00066
00067 static void free_code_blocks(lang_c_ctx_t *ctx)
00068 {
00069 code_block_t *node;
00070 code_block_list_t *head;
00071
00072 dbg_ifb (ctx == NULL) return;
00073
00074 head = &ctx->code_blocks;
00075
00076 while((node = head->tqh_first) != NULL)
00077 {
00078 TAILQ_REMOVE(head, node, np);
00079 free_code_block(node);
00080 }
00081 }
00082
00083 static int push_code_block(lang_c_ctx_t *ctx, parser_t *p,
00084 const char *buf, size_t sz)
00085 {
00086 code_block_t *node;
00087
00088 dbg_return_if (p == NULL, ~0);
00089 dbg_return_if (ctx == NULL, ~0);
00090
00091 node = (code_block_t*)u_zalloc(sizeof(code_block_t));
00092 dbg_err_if(node == NULL);
00093
00094 node->sz = sz;
00095 node->buf = (char*)u_malloc(sz);
00096 dbg_err_if(node->buf == NULL);
00097
00098 node->code_line = p->code_line;
00099 node->file_in = ctx->ti->file_in;
00100
00101 memcpy(node->buf, buf, sz);
00102
00103 TAILQ_INSERT_TAIL(&ctx->code_blocks, node, np);
00104
00105 return 0;
00106 err:
00107 if(node)
00108 free_code_block(node);
00109 return ~0;
00110 }
00111
00112 static void print_header(parser_t *p, lang_c_ctx_t *ctx)
00113 {
00114 const char *file;
00115
00116 dbg_ifb (p == NULL) return;
00117 dbg_ifb (ctx == NULL) return;
00118
00119 (void)ctx;
00120
00121 io_printf(p->out, "%s", copyright_hdr);
00122 io_printf(p->out, "#include <klone/emb.h>\n");
00123
00124 file = ctx->ti->uri + strlen(ctx->ti->uri) - 1;
00125
00126 for(; *file != '/' && file >= ctx->ti->uri; --file)
00127 ;
00128 io_printf(p->out, "static const char *SCRIPT_NAME = \"%s\";\n",
00129 ++file);
00130 }
00131
00132 static int print_var_definition(parser_t *p, int comp, const char *varname,
00133 const char *buf, size_t bufsz)
00134 {
00135 codec_t *zip = NULL;
00136 io_t *ios = NULL;
00137 int rc, i;
00138 unsigned char c;
00139
00140 dbg_err_if(p == NULL);
00141 dbg_err_if(varname == NULL);
00142 dbg_err_if(buf == NULL);
00143
00144
00145 dbg_err_if(io_mem_create((char*)buf, bufsz, 0, &ios));
00146
00147 #ifdef HAVE_LIBZ
00148
00149 if(comp)
00150 {
00151
00152 dbg_err_if(codec_gzip_create(GZIP_COMPRESS, &zip));
00153 dbg_err_if(io_codec_add_tail(ios, zip));
00154 zip = NULL;
00155 }
00156 #endif
00157
00158 io_printf(p->out, "static unsigned char %s[] = {\n", varname);
00159
00160 for(i = 1; (rc = io_getc(ios, (char*)&c)) > 0; ++i)
00161 {
00162 io_printf(p->out, "0x%02X, ", c);
00163 if(i % 12 == 0)
00164 io_printf(p->out, "\n");
00165 }
00166 dbg_err_if(rc < 0);
00167
00168 io_printf(p->out, "};\n");
00169
00170 io_free(ios);
00171
00172 return 0;
00173 err:
00174 if(zip)
00175 codec_free(zip);
00176 if(ios)
00177 io_free(ios);
00178 return ~0;
00179 }
00180
00181 static void print_code_blocks(parser_t *p, lang_c_ctx_t *ctx)
00182 {
00183 code_block_t *node;
00184 code_block_list_t *head;
00185
00186 dbg_ifb (p == NULL) return;
00187 dbg_ifb (ctx == NULL) return;
00188
00189 io_printf(p->out,
00190 "\n\n"
00191 "static void exec_page(request_t *request, response_t *response, \n"
00192 " session_t *session) { \n"
00193 " io_t *out = response_io(response); \n"
00194 );
00195
00196 head = &ctx->code_blocks;
00197 for(node = head->tqh_first; node != NULL; node = node->np.tqe_next)
00198 io_write(p->out, node->buf, node->sz);
00199
00200 io_printf(p->out,
00201 "klone_script_exit: \n"
00202 " return; \n"
00203 "} \n"
00204 );
00205 }
00206
00207 static void print_static_page_block(io_t *out, lang_c_ctx_t *ctx)
00208 {
00209 dbg_ifb (out == NULL) return;
00210 dbg_ifb (ctx == NULL) return;
00211 dbg_ifb (ctx->ti == NULL) return;
00212
00213 io_printf(out,
00214 "static embfile_t e; \n"
00215 "static void res_ctor(void) \n"
00216 "{ \n"
00217 " e.res.type = ET_FILE; \n"
00218 " e.res.filename = \"%s\"; \n"
00219 " e.data = data; \n"
00220 " e.size = sizeof(data); \n"
00221 " e.file_size = %u; \n"
00222 " e.mime_type = \"%s\"; \n"
00223 " e.mtime = %lu; \n"
00224 " e.comp = %d; \n"
00225 " e.encrypted = %d; \n"
00226 "} \n",
00227 ctx->ti->uri,
00228
00229 ctx->ti->file_size,
00230 u_guess_mime_type(ctx->ti->uri),
00231 ctx->ti->mtime,
00232 ctx->ti->comp,
00233 ctx->ti->encrypt);
00234 }
00235
00236 static void print_dynamic_page_block(io_t *out, lang_c_ctx_t *ctx)
00237 {
00238 dbg_ifb (out == NULL) return;
00239 dbg_ifb (ctx == NULL) return;
00240 dbg_ifb (ctx->ti == NULL) return;
00241
00242 io_printf(out,
00243 "static embpage_t e; \n"
00244 "static void res_ctor(void) \n"
00245 "{ \n"
00246 " e.res.type = ET_PAGE; \n"
00247 " e.res.filename = \"%s\"; \n"
00248 " e.run = exec_page; \n"
00249 "} \n",
00250 ctx->ti->uri);
00251 }
00252
00253 static void print_register_block(io_t *out, lang_c_ctx_t *ctx)
00254 {
00255 char md5[MD5_DIGEST_BUFSZ];
00256
00257 dbg_ifb (out == NULL) return;
00258 dbg_ifb (ctx == NULL) return;
00259 dbg_ifb (ctx->ti == NULL) return;
00260
00261 u_md5(ctx->ti->uri, strlen(ctx->ti->uri), md5);
00262
00263 io_printf(out,
00264 "#ifdef __cplusplus \n"
00265 "extern \"C\" { \n"
00266 "#endif \n"
00267 "void module_init_%s(void) \n"
00268 "{ \n"
00269 " res_ctor(); \n"
00270 " emb_register((embres_t*)&e); \n"
00271 "} \n"
00272 "void module_term_%s(void) \n"
00273 "{ \n"
00274 " emb_unregister((embres_t*)&e); \n"
00275 "} \n"
00276 "#ifdef __cplusplus \n"
00277 "} \n"
00278 "#endif \n",
00279 md5, md5);
00280 }
00281
00282 static int print_c_line(parser_t *p, lang_c_ctx_t *ctx)
00283 {
00284 dbg_err_if (p == NULL);
00285 dbg_err_if (ctx == NULL);
00286 dbg_err_if (ctx->ti == NULL);
00287
00288 dbg_err_if(io_printf(p->out, "#line %d \"%s\"\n", p->code_line,
00289 ctx->ti->file_in) < 0);
00290
00291 return 0;
00292 err:
00293 return ~0;
00294 }
00295
00296 static int process_declaration(parser_t *p, void *arg, const char *buf,
00297 size_t sz)
00298 {
00299 u_unused_args(arg);
00300
00301 dbg_err_if (p == NULL);
00302
00303 dbg_err_if(io_write(p->out, buf, sz) < 0);
00304
00305 return 0;
00306 err:
00307 return ~0;
00308 }
00309
00310 static int process_expression(parser_t *p, void *arg, const char *buf,
00311 size_t sz)
00312 {
00313 lang_c_ctx_t *ctx;
00314 const char before[] = "io_printf(out, \"%s\",";
00315 const char after[] = ");";
00316
00317 dbg_err_if (p == NULL);
00318 dbg_err_if (arg == NULL);
00319
00320 ctx = (lang_c_ctx_t*)arg;
00321
00322 dbg_err_if(push_code_block(ctx, p, before, strlen(before)));
00323 dbg_err_if(push_code_block(ctx, p, buf, sz));
00324 dbg_err_if(push_code_block(ctx, p, after, strlen(after)));
00325
00326 return 0;
00327 err:
00328 return ~0;
00329 }
00330
00331 static int process_code(parser_t *p, void *arg, const char *buf, size_t sz)
00332 {
00333 lang_c_ctx_t *ctx;
00334
00335 dbg_err_if (p == NULL);
00336 dbg_err_if (arg == NULL);
00337
00338 ctx = (lang_c_ctx_t*)arg;
00339
00340 dbg_err_if(push_code_block(ctx, p, buf, sz));
00341
00342 return 0;
00343 err:
00344 return ~0;
00345 }
00346
00347 static int translate_set_error(trans_info_t *ti, parser_t *p, const char *msg)
00348 {
00349 char file[U_FILENAME_MAX];
00350
00351 dbg_err_if (ti == NULL);
00352 dbg_err_if (p == NULL || p->in == NULL);
00353
00354 dbg_err_if(io_name_get(p->in, file, U_FILENAME_MAX));
00355
00356 dbg_err_if(u_snprintf(ti->emsg, EMSG_BUFSZ, "[%s:%d] %s",
00357 file, p->line, msg));
00358
00359 return 0;
00360 err:
00361 return ~0;
00362 }
00363
00364 static int cb_html_block(parser_t *p, void *arg, const char *buf, size_t sz)
00365 {
00366 enum { CODESZ = 128, VARNSZ = 32 };
00367 lang_c_ctx_t *ctx;
00368 char code[CODESZ];
00369 char varname[VARNSZ];
00370
00371 dbg_err_if (p == NULL);
00372 dbg_err_if (arg == NULL);
00373
00374 ctx = (lang_c_ctx_t*)arg;
00375
00376 if(ctx->ti->comp)
00377 {
00378 dbg_err_if(u_snprintf(varname, VARNSZ, "klone_html_zblock_%lu",
00379 ctx->html_block_cnt));
00380
00381 dbg_err_if(print_var_definition(p, 1 , varname, buf, sz));
00382
00383 dbg_err_if(u_snprintf(code, CODESZ,
00384 "\ndbg_if(u_io_unzip_copy(out, klone_html_zblock_%lu, "
00385 " sizeof(klone_html_zblock_%lu)));\n",
00386 ctx->html_block_cnt, ctx->html_block_cnt));
00387
00388 } else {
00389
00390 dbg_err_if(u_snprintf(varname, VARNSZ, "klone_html_%lu",
00391 ctx->html_block_cnt));
00392
00393 dbg_err_if(print_var_definition(p, 0, varname, buf, sz));
00394
00395 dbg_err_if(u_snprintf(code, CODESZ,
00396 "\ndbg_if(io_write(out, klone_html_%lu, "
00397 " sizeof(klone_html_%lu)) < 0);\n",
00398 ctx->html_block_cnt, ctx->html_block_cnt));
00399 }
00400
00401 dbg_err_if(push_code_block(ctx, p, code, strlen(code)));
00402
00403 ctx->html_block_cnt++;
00404
00405 return 0;
00406 err:
00407 return ~0;
00408 }
00409
00410 static int cb_code_block(parser_t *p, int cmd, void *arg, const char *buf,
00411 size_t sz)
00412 {
00413 lang_c_ctx_t *ctx;
00414
00415 dbg_err_if (p == NULL);
00416 dbg_err_if (arg == NULL);
00417
00418 ctx = (lang_c_ctx_t *)arg;
00419
00420 switch(cmd)
00421 {
00422 case 0:
00423 process_code(p, arg, buf, sz);
00424 break;
00425 case '@':
00426 dbg_err_if("the file should have already been preprocessed");
00427 break;
00428 case '!':
00429 process_declaration(p, arg, buf, sz);
00430 break;
00431 case '=':
00432 process_expression(p, arg, buf, sz);
00433 break;
00434 default:
00435 translate_set_error(ctx->ti, p, "bad command char after <%");
00436 warn_err("unknown code type");
00437 }
00438 return 0;
00439 err:
00440 return ~0;
00441 }
00442
00443
00444 int translate_opaque_to_c(io_t *in, io_t *out, trans_info_t *ti)
00445 {
00446 lang_c_ctx_t ctx;
00447 int i = 0;
00448 ssize_t rc;
00449 unsigned char c;
00450
00451 dbg_err_if (in == NULL);
00452 dbg_err_if (out == NULL);
00453 dbg_err_if (ti == NULL);
00454
00455 memset(&ctx, 0, sizeof(lang_c_ctx_t));
00456 TAILQ_INIT(&ctx.code_blocks);
00457 ctx.ti = ti;
00458
00459 io_printf(out, "%s", copyright_hdr);
00460 io_printf(out, "#include <klone/emb.h>\n");
00461
00462 io_printf(out, "static unsigned char data[] = {\n");
00463
00464 for(i = 1; (rc = io_getc(in, (char*)&c)) > 0; ++i)
00465 {
00466 io_printf(out, "0x%02X, ", c);
00467 if(i % 12 == 0)
00468 io_printf(out, "\n");
00469 }
00470 dbg_err_if(rc < 0);
00471
00472 io_printf(out, "};\n");
00473
00474 print_static_page_block(out, &ctx);
00475 print_register_block(out, &ctx);
00476
00477 return 0;
00478 err:
00479 return ~0;
00480 }
00481
00482 int translate_script_to_c(io_t *in, io_t *out, trans_info_t *ti)
00483 {
00484 parser_t *p = NULL;
00485 lang_c_ctx_t ctx;
00486
00487 dbg_return_if (in == NULL, ~0);
00488 dbg_return_if (out == NULL, ~0);
00489 dbg_return_if (ti == NULL, ~0);
00490
00491
00492 memset(&ctx, 0, sizeof(lang_c_ctx_t));
00493 TAILQ_INIT(&ctx.code_blocks);
00494 ctx.ti = ti;
00495
00496
00497 dbg_err_if(parser_create(&p));
00498
00499 parser_set_io(p, in, out);
00500
00501 parser_set_cb_arg(p, &ctx);
00502 parser_set_cb_code(p, cb_code_block);
00503 parser_set_cb_html(p, cb_html_block);
00504
00505 print_header(p, &ctx);
00506
00507 dbg_err_if(parser_run(p));
00508
00509 print_code_blocks(p, &ctx);
00510
00511 print_dynamic_page_block(p->out, &ctx);
00512
00513 print_register_block(p->out, &ctx);
00514
00515 free_code_blocks(&ctx);
00516
00517 parser_free(p);
00518
00519 return 0;
00520 err:
00521 free_code_blocks(&ctx);
00522 if(p)
00523 parser_free(p);
00524 return ~0;
00525 }