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/os.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 io_printf(p->out,
00132 "static request_t *request = NULL;\n"
00133 "static response_t *response = NULL;\n"
00134 "static session_t *session = NULL;\n"
00135 "static io_t *in = NULL;\n"
00136 "static io_t *out = NULL;\n");
00137
00138 }
00139
00140 static int print_var_definition(parser_t *p, int comp, const char *varname,
00141 const char *buf, size_t bufsz)
00142 {
00143 codec_t *zip = NULL;
00144 io_t *ios = NULL;
00145 int rc, i;
00146 unsigned char c;
00147
00148 dbg_err_if(p == NULL);
00149 dbg_err_if(varname == NULL);
00150 dbg_err_if(buf == NULL);
00151
00152
00153 dbg_err_if(io_mem_create((char*)buf, bufsz, 0, &ios));
00154
00155 #ifdef HAVE_LIBZ
00156
00157 if(comp)
00158 {
00159
00160 dbg_err_if(codec_gzip_create(GZIP_COMPRESS, &zip));
00161 dbg_err_if(io_codec_add_tail(ios, zip));
00162 zip = NULL;
00163 }
00164 #endif
00165
00166 io_printf(p->out, "static const char %s[] = {\n", varname);
00167
00168 for(i = 1; (rc = io_getc(ios, (char*)&c)) > 0; ++i)
00169 {
00170 io_printf(p->out, "0x%02X, ", c);
00171 if(i % 12 == 0)
00172 io_printf(p->out, "\n");
00173 }
00174 dbg_err_if(rc < 0);
00175
00176 io_printf(p->out, "};\n");
00177
00178 io_free(ios);
00179
00180 return 0;
00181 err:
00182 if(zip)
00183 codec_free(zip);
00184 if(ios)
00185 io_free(ios);
00186 return ~0;
00187 }
00188
00189 static void print_code_blocks(parser_t *p, lang_c_ctx_t *ctx)
00190 {
00191 code_block_t *node;
00192 code_block_list_t *head;
00193
00194 dbg_ifb (p == NULL) return;
00195 dbg_ifb (ctx == NULL) return;
00196
00197 io_printf(p->out,
00198 "\n\n"
00199 "static void exec_page(request_t *rq, response_t *rs, session_t *ses)\n"
00200 "{\n"
00201 " request = rq; \n"
00202 " response = rs; \n"
00203 " session = ses; \n"
00204 " in = request_io(request); \n"
00205 " out = response_io(response); \n"
00206 " u_unused_args(SCRIPT_NAME, request, response, session, in, out); \n"
00207 );
00208
00209 head = &ctx->code_blocks;
00210 for(node = head->tqh_first; node != NULL; node = node->np.tqe_next)
00211 io_write(p->out, node->buf, node->sz);
00212
00213 io_printf(p->out,
00214 "goto klone_script_exit;\n" /* just to avoid a warning */
00215 "klone_script_exit: \n"
00216 " return; \n"
00217 "} \n"
00218 );
00219 }
00220
00221 static void print_static_page_block(io_t *out, lang_c_ctx_t *ctx)
00222 {
00223 dbg_ifb (out == NULL) return;
00224 dbg_ifb (ctx == NULL) return;
00225 dbg_ifb (ctx->ti == NULL) return;
00226
00227 io_printf(out,
00228 "static embfile_t e; \n"
00229 "static void res_ctor(void) \n"
00230 "{ \n"
00231 " e.res.type = ET_FILE; \n"
00232 " e.res.filename = \"%s\"; \n"
00233 " e.data = (unsigned char*)data; \n"
00234 " e.size = sizeof(data); \n"
00235 " e.file_size = %u; \n"
00236 " e.mime_type = \"%s\"; \n"
00237 " e.mtime = %lu; \n"
00238 " e.comp = %d; \n"
00239 " e.encrypted = %d; \n"
00240 "} \n",
00241 ctx->ti->uri,
00242
00243 ctx->ti->file_size,
00244 u_guess_mime_type(ctx->ti->uri),
00245 ctx->ti->mtime,
00246 ctx->ti->comp,
00247 ctx->ti->encrypt);
00248 }
00249
00250 static void print_dynamic_page_block(io_t *out, lang_c_ctx_t *ctx)
00251 {
00252 dbg_ifb (out == NULL) return;
00253 dbg_ifb (ctx == NULL) return;
00254 dbg_ifb (ctx->ti == NULL) return;
00255
00256 io_printf(out,
00257 "static embpage_t e; \n"
00258 "static void res_ctor(void) \n"
00259 "{ \n"
00260 " e.res.type = ET_PAGE; \n"
00261 " e.res.filename = \"%s\"; \n"
00262 " e.run = exec_page; \n"
00263 "} \n",
00264 ctx->ti->uri);
00265 }
00266
00267 static void print_register_block(io_t *out, lang_c_ctx_t *ctx)
00268 {
00269 char md5[MD5_DIGEST_BUFSZ];
00270
00271 dbg_ifb (out == NULL) return;
00272 dbg_ifb (ctx == NULL) return;
00273 dbg_ifb (ctx->ti == NULL) return;
00274
00275 u_md5(ctx->ti->uri, strlen(ctx->ti->uri), md5);
00276
00277 io_printf(out,
00278 "#ifdef __cplusplus \n"
00279 "extern \"C\" { \n"
00280 "#endif \n"
00281 "void module_init_%s(void); \n" /* avoids a warning */
00282 "void module_init_%s(void) \n"
00283 "{ \n"
00284 " res_ctor(); \n"
00285 " emb_register((embres_t*)&e); \n"
00286 "} \n"
00287 "void module_term_%s(void); \n" /* avoids a warning */
00288 "void module_term_%s(void) \n"
00289 "{ \n"
00290 " emb_unregister((embres_t*)&e); \n"
00291 "} \n"
00292 "#ifdef __cplusplus \n"
00293 "} \n"
00294 "#endif \n",
00295 md5, md5, md5, md5);
00296 }
00297
00298 static int print_c_line(parser_t *p, lang_c_ctx_t *ctx)
00299 {
00300 dbg_err_if (p == NULL);
00301 dbg_err_if (ctx == NULL);
00302 dbg_err_if (ctx->ti == NULL);
00303
00304 dbg_err_if(io_printf(p->out, "#line %d \"%s\"\n", p->code_line,
00305 ctx->ti->file_in) < 0);
00306
00307 return 0;
00308 err:
00309 return ~0;
00310 }
00311
00312 static int process_declaration(parser_t *p, void *arg, const char *buf,
00313 size_t sz)
00314 {
00315 u_unused_args(arg);
00316
00317 dbg_err_if (p == NULL);
00318
00319 dbg_err_if(io_write(p->out, buf, sz) < 0);
00320
00321
00322 dbg_err_if(io_printf(p->out, "\n") < 0);
00323
00324 return 0;
00325 err:
00326 return ~0;
00327 }
00328
00329 static int process_expression(parser_t *p, void *arg, const char *buf,
00330 size_t sz)
00331 {
00332 lang_c_ctx_t *ctx;
00333 const char before[] = "io_printf(out, \"%s\",";
00334 const char after[] = ");";
00335
00336 dbg_err_if (p == NULL);
00337 dbg_err_if (arg == NULL);
00338
00339 ctx = (lang_c_ctx_t*)arg;
00340
00341 dbg_err_if(push_code_block(ctx, p, before, strlen(before)));
00342 dbg_err_if(push_code_block(ctx, p, buf, sz));
00343 dbg_err_if(push_code_block(ctx, p, after, strlen(after)));
00344
00345 return 0;
00346 err:
00347 return ~0;
00348 }
00349
00350 static int process_code(parser_t *p, void *arg, const char *buf, size_t sz)
00351 {
00352 lang_c_ctx_t *ctx;
00353
00354 dbg_err_if (p == NULL);
00355 dbg_err_if (arg == NULL);
00356
00357 ctx = (lang_c_ctx_t*)arg;
00358
00359 dbg_err_if(push_code_block(ctx, p, buf, sz));
00360
00361 return 0;
00362 err:
00363 return ~0;
00364 }
00365
00366 static int translate_set_error(trans_info_t *ti, parser_t *p, const char *msg)
00367 {
00368 char file[U_FILENAME_MAX];
00369
00370 dbg_err_if (ti == NULL);
00371 dbg_err_if (p == NULL || p->in == NULL);
00372
00373 dbg_err_if(io_name_get(p->in, file, U_FILENAME_MAX));
00374
00375 dbg_err_if(u_snprintf(ti->emsg, EMSG_BUFSZ, "[%s:%d] %s",
00376 file, p->line, msg));
00377
00378 return 0;
00379 err:
00380 return ~0;
00381 }
00382
00383 static int cb_html_block(parser_t *p, void *arg, const char *buf, size_t sz)
00384 {
00385 enum { CODESZ = 128, VARNSZ = 32 };
00386 lang_c_ctx_t *ctx;
00387 char code[CODESZ];
00388 char varname[VARNSZ];
00389
00390 dbg_err_if (p == NULL);
00391 dbg_err_if (arg == NULL);
00392
00393 ctx = (lang_c_ctx_t*)arg;
00394
00395 if(ctx->ti->comp)
00396 {
00397 dbg_err_if(u_snprintf(varname, VARNSZ, "klone_html_zblock_%lu",
00398 ctx->html_block_cnt));
00399
00400 dbg_err_if(print_var_definition(p, 1 , varname, buf, sz));
00401
00402 dbg_err_if(u_snprintf(code, CODESZ,
00403 "\ndbg_if(u_io_unzip_copy(out, klone_html_zblock_%lu, "
00404 " sizeof(klone_html_zblock_%lu)));\n",
00405 ctx->html_block_cnt, ctx->html_block_cnt));
00406
00407 } else {
00408
00409 dbg_err_if(u_snprintf(varname, VARNSZ, "klone_html_%lu",
00410 ctx->html_block_cnt));
00411
00412 dbg_err_if(print_var_definition(p, 0, varname, buf, sz));
00413
00414 dbg_err_if(u_snprintf(code, CODESZ,
00415 "\ndbg_if(io_write(out, klone_html_%lu, "
00416 " sizeof(klone_html_%lu)) < 0);\n",
00417 ctx->html_block_cnt, ctx->html_block_cnt));
00418 }
00419
00420 dbg_err_if(push_code_block(ctx, p, code, strlen(code)));
00421
00422 ctx->html_block_cnt++;
00423
00424 return 0;
00425 err:
00426 return ~0;
00427 }
00428
00429 static int cb_code_block(parser_t *p, int cmd, void *arg, const char *buf,
00430 size_t sz)
00431 {
00432 lang_c_ctx_t *ctx;
00433
00434 dbg_err_if (p == NULL);
00435 dbg_err_if (arg == NULL);
00436
00437 ctx = (lang_c_ctx_t *)arg;
00438
00439 switch(cmd)
00440 {
00441 case 0:
00442 process_code(p, arg, buf, sz);
00443 break;
00444 case '@':
00445 dbg_err_if("the file should have already been preprocessed");
00446 break;
00447 case '!':
00448 process_declaration(p, arg, buf, sz);
00449 break;
00450 case '=':
00451 process_expression(p, arg, buf, sz);
00452 break;
00453 default:
00454 translate_set_error(ctx->ti, p, "bad command char after <%");
00455 warn_err("unknown code type");
00456 }
00457 return 0;
00458 err:
00459 return ~0;
00460 }
00461
00462
00463 int translate_opaque_to_c(io_t *in, io_t *out, trans_info_t *ti)
00464 {
00465 lang_c_ctx_t ctx;
00466 int i = 0;
00467 ssize_t rc;
00468 unsigned char c;
00469
00470 dbg_err_if (in == NULL);
00471 dbg_err_if (out == NULL);
00472 dbg_err_if (ti == NULL);
00473
00474 memset(&ctx, 0, sizeof(lang_c_ctx_t));
00475 TAILQ_INIT(&ctx.code_blocks);
00476 ctx.ti = ti;
00477
00478 io_printf(out, "%s", copyright_hdr);
00479 io_printf(out, "#include <klone/emb.h>\n");
00480
00481 io_printf(out, "static const char data[] = {\n");
00482
00483 for(i = 1; (rc = io_getc(in, (char*)&c)) > 0; ++i)
00484 {
00485 io_printf(out, "0x%02X, ", c);
00486 if(i % 12 == 0)
00487 io_printf(out, "\n");
00488 }
00489 dbg_err_if(rc < 0);
00490
00491 io_printf(out, "};\n");
00492
00493 print_static_page_block(out, &ctx);
00494 print_register_block(out, &ctx);
00495
00496 return 0;
00497 err:
00498 return ~0;
00499 }
00500
00501 int translate_script_to_c(io_t *in, io_t *out, trans_info_t *ti)
00502 {
00503 parser_t *p = NULL;
00504 lang_c_ctx_t ctx;
00505
00506 dbg_return_if (in == NULL, ~0);
00507 dbg_return_if (out == NULL, ~0);
00508 dbg_return_if (ti == NULL, ~0);
00509
00510
00511 memset(&ctx, 0, sizeof(lang_c_ctx_t));
00512 TAILQ_INIT(&ctx.code_blocks);
00513 ctx.ti = ti;
00514
00515
00516 dbg_err_if(parser_create(&p));
00517
00518 parser_set_io(p, in, out);
00519
00520 parser_set_cb_arg(p, &ctx);
00521 parser_set_cb_code(p, cb_code_block);
00522 parser_set_cb_html(p, cb_html_block);
00523
00524 print_header(p, &ctx);
00525
00526 dbg_err_if(parser_run(p));
00527
00528 print_code_blocks(p, &ctx);
00529
00530 print_dynamic_page_block(p->out, &ctx);
00531
00532 print_register_block(p->out, &ctx);
00533
00534 free_code_blocks(&ctx);
00535
00536 parser_free(p);
00537
00538 return 0;
00539 err:
00540 free_code_blocks(&ctx);
00541 if(p)
00542 parser_free(p);
00543 return ~0;
00544 }