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
00306 dbg_err_if(io_printf(p->out, "\n") < 0);
00307
00308 return 0;
00309 err:
00310 return ~0;
00311 }
00312
00313 static int process_expression(parser_t *p, void *arg, const char *buf,
00314 size_t sz)
00315 {
00316 lang_c_ctx_t *ctx;
00317 const char before[] = "io_printf(out, \"%s\",";
00318 const char after[] = ");";
00319
00320 dbg_err_if (p == NULL);
00321 dbg_err_if (arg == NULL);
00322
00323 ctx = (lang_c_ctx_t*)arg;
00324
00325 dbg_err_if(push_code_block(ctx, p, before, strlen(before)));
00326 dbg_err_if(push_code_block(ctx, p, buf, sz));
00327 dbg_err_if(push_code_block(ctx, p, after, strlen(after)));
00328
00329 return 0;
00330 err:
00331 return ~0;
00332 }
00333
00334 static int process_code(parser_t *p, void *arg, const char *buf, size_t sz)
00335 {
00336 lang_c_ctx_t *ctx;
00337
00338 dbg_err_if (p == NULL);
00339 dbg_err_if (arg == NULL);
00340
00341 ctx = (lang_c_ctx_t*)arg;
00342
00343 dbg_err_if(push_code_block(ctx, p, buf, sz));
00344
00345 return 0;
00346 err:
00347 return ~0;
00348 }
00349
00350 static int translate_set_error(trans_info_t *ti, parser_t *p, const char *msg)
00351 {
00352 char file[U_FILENAME_MAX];
00353
00354 dbg_err_if (ti == NULL);
00355 dbg_err_if (p == NULL || p->in == NULL);
00356
00357 dbg_err_if(io_name_get(p->in, file, U_FILENAME_MAX));
00358
00359 dbg_err_if(u_snprintf(ti->emsg, EMSG_BUFSZ, "[%s:%d] %s",
00360 file, p->line, msg));
00361
00362 return 0;
00363 err:
00364 return ~0;
00365 }
00366
00367 static int cb_html_block(parser_t *p, void *arg, const char *buf, size_t sz)
00368 {
00369 enum { CODESZ = 128, VARNSZ = 32 };
00370 lang_c_ctx_t *ctx;
00371 char code[CODESZ];
00372 char varname[VARNSZ];
00373
00374 dbg_err_if (p == NULL);
00375 dbg_err_if (arg == NULL);
00376
00377 ctx = (lang_c_ctx_t*)arg;
00378
00379 if(ctx->ti->comp)
00380 {
00381 dbg_err_if(u_snprintf(varname, VARNSZ, "klone_html_zblock_%lu",
00382 ctx->html_block_cnt));
00383
00384 dbg_err_if(print_var_definition(p, 1 , varname, buf, sz));
00385
00386 dbg_err_if(u_snprintf(code, CODESZ,
00387 "\ndbg_if(u_io_unzip_copy(out, klone_html_zblock_%lu, "
00388 " sizeof(klone_html_zblock_%lu)));\n",
00389 ctx->html_block_cnt, ctx->html_block_cnt));
00390
00391 } else {
00392
00393 dbg_err_if(u_snprintf(varname, VARNSZ, "klone_html_%lu",
00394 ctx->html_block_cnt));
00395
00396 dbg_err_if(print_var_definition(p, 0, varname, buf, sz));
00397
00398 dbg_err_if(u_snprintf(code, CODESZ,
00399 "\ndbg_if(io_write(out, klone_html_%lu, "
00400 " sizeof(klone_html_%lu)) < 0);\n",
00401 ctx->html_block_cnt, ctx->html_block_cnt));
00402 }
00403
00404 dbg_err_if(push_code_block(ctx, p, code, strlen(code)));
00405
00406 ctx->html_block_cnt++;
00407
00408 return 0;
00409 err:
00410 return ~0;
00411 }
00412
00413 static int cb_code_block(parser_t *p, int cmd, void *arg, const char *buf,
00414 size_t sz)
00415 {
00416 lang_c_ctx_t *ctx;
00417
00418 dbg_err_if (p == NULL);
00419 dbg_err_if (arg == NULL);
00420
00421 ctx = (lang_c_ctx_t *)arg;
00422
00423 switch(cmd)
00424 {
00425 case 0:
00426 process_code(p, arg, buf, sz);
00427 break;
00428 case '@':
00429 dbg_err_if("the file should have already been preprocessed");
00430 break;
00431 case '!':
00432 process_declaration(p, arg, buf, sz);
00433 break;
00434 case '=':
00435 process_expression(p, arg, buf, sz);
00436 break;
00437 default:
00438 translate_set_error(ctx->ti, p, "bad command char after <%");
00439 warn_err("unknown code type");
00440 }
00441 return 0;
00442 err:
00443 return ~0;
00444 }
00445
00446
00447 int translate_opaque_to_c(io_t *in, io_t *out, trans_info_t *ti)
00448 {
00449 lang_c_ctx_t ctx;
00450 int i = 0;
00451 ssize_t rc;
00452 unsigned char c;
00453
00454 dbg_err_if (in == NULL);
00455 dbg_err_if (out == NULL);
00456 dbg_err_if (ti == NULL);
00457
00458 memset(&ctx, 0, sizeof(lang_c_ctx_t));
00459 TAILQ_INIT(&ctx.code_blocks);
00460 ctx.ti = ti;
00461
00462 io_printf(out, "%s", copyright_hdr);
00463 io_printf(out, "#include <klone/emb.h>\n");
00464
00465 io_printf(out, "static unsigned char data[] = {\n");
00466
00467 for(i = 1; (rc = io_getc(in, (char*)&c)) > 0; ++i)
00468 {
00469 io_printf(out, "0x%02X, ", c);
00470 if(i % 12 == 0)
00471 io_printf(out, "\n");
00472 }
00473 dbg_err_if(rc < 0);
00474
00475 io_printf(out, "};\n");
00476
00477 print_static_page_block(out, &ctx);
00478 print_register_block(out, &ctx);
00479
00480 return 0;
00481 err:
00482 return ~0;
00483 }
00484
00485 int translate_script_to_c(io_t *in, io_t *out, trans_info_t *ti)
00486 {
00487 parser_t *p = NULL;
00488 lang_c_ctx_t ctx;
00489
00490 dbg_return_if (in == NULL, ~0);
00491 dbg_return_if (out == NULL, ~0);
00492 dbg_return_if (ti == NULL, ~0);
00493
00494
00495 memset(&ctx, 0, sizeof(lang_c_ctx_t));
00496 TAILQ_INIT(&ctx.code_blocks);
00497 ctx.ti = ti;
00498
00499
00500 dbg_err_if(parser_create(&p));
00501
00502 parser_set_io(p, in, out);
00503
00504 parser_set_cb_arg(p, &ctx);
00505 parser_set_cb_code(p, cb_code_block);
00506 parser_set_cb_html(p, cb_html_block);
00507
00508 print_header(p, &ctx);
00509
00510 dbg_err_if(parser_run(p));
00511
00512 print_code_blocks(p, &ctx);
00513
00514 print_dynamic_page_block(p->out, &ctx);
00515
00516 print_register_block(p->out, &ctx);
00517
00518 free_code_blocks(&ctx);
00519
00520 parser_free(p);
00521
00522 return 0;
00523 err:
00524 free_code_blocks(&ctx);
00525 if(p)
00526 parser_free(p);
00527 return ~0;
00528 }