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