trans_c.c

00001 /*
00002  * Copyright (c) 2005-2012 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.43 2010/05/31 13:41:12 tho 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/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; /* 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-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; /* shortcut */
00136 
00137     /* we need a prefix to avoid errors with pages whose filename starts with
00138        a number (404-handler.kl1) or any other char not allowed by C as the
00139        first char of function names */
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] = '_'; /* just a-zA-Z0-9 allowed */
00146 
00147     /* add a dummy function that the user can use to set a breakpoint when
00148        entering the page code. the "static volatile" variable is used to avoid
00149        the compiler to optimize-out (inlining) the function call */
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     /* create an io_t around the HTML block */
00177     dbg_err_if(io_mem_create((char*)buf, bufsz, 0, &ios));
00178 
00179 #ifdef HAVE_LIBZ
00180     /* if compression is enabled zip the data block */
00181     if(comp)
00182     {
00183         /* apply a gzip codec */
00184         dbg_err_if(codec_gzip_create(GZIP_COMPRESS, &zip));
00185         dbg_err_if(io_codec_add_tail(ios, zip));
00186         zip = NULL; /* io_free() will free the codec */
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); /* input stream error */
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          /* file_size will be == to size if the file is not compressed */
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" /* avoids a warning */
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" /* avoids a warning */
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     /* a newline is required after #includes or #defines */
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     {   /* zip embedded HTML blocks */
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 /* zip it */, 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         /* embedded HTML blocks will not be zipped */
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: /* plain code block <% ... %> */
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 /* translate a opaque file to a const char array */
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); /* input stream error */
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     /* init the context obj */
00527     memset(&ctx, 0, sizeof(lang_c_ctx_t));
00528     TAILQ_INIT(&ctx.code_blocks);
00529     ctx.ti = ti;
00530 
00531     /* create a parse that reads from in and writes to out */
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 }

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