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