Main Page | Modules | Data Structures | Directories | File List | Data Fields | Globals

trans_c.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2005, 2006, 2006 by KoanLogic s.r.l. <http://www.koanlogic.com>
00003  * All rights reserved.
00004  *
00005  * This file is part of KLone, and as such it is subject to the license stated
00006  * in the LICENSE file which you have received as part of this distribution.
00007  *
00008  * $Id: trans_c.c,v 1.30 2006/09/24 13:22:49 tat Exp $
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; /* next & prev pointers                   */
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     /* create an io_t around the HTML block */
00145     dbg_err_if(io_mem_create((char*)buf, bufsz, 0, &ios));
00146 
00147 #ifdef HAVE_LIBZ
00148     /* if compression is enabled zip the data block */
00149     if(comp)
00150     {
00151         /* apply a gzip codec */
00152         dbg_err_if(codec_gzip_create(GZIP_COMPRESS, &zip));
00153         dbg_err_if(io_codec_add_tail(ios, zip));
00154         zip = NULL; /* io_free() will free the codec */
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); /* input stream error */
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          /* file_size will be == to size if the file is not compressed */
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     /* a newline is required after #includes or #defines */
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     {   /* zip embedded HTML blocks */
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 /* zip it */, 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         /* embedded HTML blocks will not be zipped */
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: /* plain code block <% ... %> */
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 /* translate a opaque file to a C unsigned char array */
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); /* input stream error */
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     /* init the context obj */
00495     memset(&ctx, 0, sizeof(lang_c_ctx_t));
00496     TAILQ_INIT(&ctx.code_blocks);
00497     ctx.ti = ti;
00498 
00499     /* create a parse that reads from in and writes to out */
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 }

←Products
© 2005-2006 - KoanLogic S.r.l. - All rights reserved