translat.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: translat.c,v 1.32 2009/05/29 10:26:01 tho Exp $
00009  */
00010 
00011 #include "klone_conf.h"
00012 #include <stdio.h>
00013 #include <stdlib.h>
00014 #include <ctype.h>
00015 #include <fcntl.h>
00016 #include <unistd.h>
00017 #include <limits.h>
00018 #include <u/libu.h>
00019 #include <klone/os.h>
00020 #include <klone/translat.h>
00021 #include <klone/parser.h>
00022 #include <klone/utils.h>
00023 #include <klone/os.h>
00024 #include <klone/io.h>
00025 #include <klone/codec.h>
00026 #include <klone/codecs.h>
00027 
00028 #define tr_err(...)             \
00029     do  { con_p_ctx(p); con_err(__VA_ARGS__); } while(0)
00030 #define tr_err_if(expr)          \
00031     do { if( (expr) ) { con_p_ctx(p); u_con("%s", #expr); goto err; } } while(0)
00032 #define tr_err_ifm(expr, ...)    \
00033     do { if( (expr) ) { con_p_ctx(p); u_con(__VA_ARGS__); goto err; } } while(0)
00034 
00035 
00036 typedef struct kblock_s
00037 {
00038     char *name;                 /* block name (is NULL for unnamed blocks) */
00039     u_buf_t *ubuf;              /* block content */
00040     struct kblock_s *parent;     /* the parent block in the block tree */
00041     struct kblock_s *ancestor;   /* the ancestor block this block overrides */
00042     u_list_t *children;         /* list of children blocks */
00043 } kblock_t;
00044 
00045 typedef struct ppctx_s
00046 {
00047     kblock_t *cur;       /* currently selected block */
00048     kblock_t *top;       /* top block in the tree */
00049     kblock_t *dead;      /* tree for dead blocks */
00050     int lev;            /* blocks nesting level */
00051     int extending;      /* nesting level from the extended block */
00052     u_list_t *depend;   /* list of depends (path+filename) */
00053 } ppctx_t;
00054 
00055 static int preprocess(io_t *in, io_t *out, ppctx_t*);
00056 
00057 static int kblock_free(kblock_t *block)
00058 {
00059     kblock_t *child;
00060     int i;
00061 
00062     dbg_err_if(block == NULL);
00063 
00064     /* free children first */
00065     for(i = 0; (child = u_list_get_n(block->children, i)) != NULL; ++i)
00066         kblock_free(child);
00067 
00068     if(block->ancestor)
00069         kblock_free(block->ancestor);
00070 
00071     if(block->name)
00072         u_free(block->name);
00073 
00074     if(block->ubuf)
00075         u_buf_free(block->ubuf);
00076 
00077     u_free(block);
00078 
00079     return 0;
00080 err:
00081     return ~0;
00082 }
00083 
00084 static int kblock_push_child(kblock_t *parent, kblock_t *child)
00085 {
00086     dbg_err_if(u_list_add(parent->children, child));
00087 
00088     child->parent = parent;
00089 
00090     return 0;
00091 err:
00092     return ~0;
00093 }
00094 
00095 static int kblock_create(const char *name, const char *buf, size_t size, 
00096             kblock_t **pblock)
00097 {
00098     kblock_t *b = NULL;
00099 
00100     b = u_zalloc(sizeof(kblock_t));
00101     dbg_err_if(b == NULL);
00102 
00103     dbg_err_if(u_buf_create(&b->ubuf));
00104 
00105     dbg_err_if(u_list_create(&b->children));
00106 
00107     if(name)
00108     {
00109         b->name = u_strdup(name);
00110         dbg_err_if(b->name == NULL);
00111     }
00112 
00113     if(buf && size)
00114         dbg_err_if(u_buf_append(b->ubuf, buf, size));
00115 
00116     *pblock = b;
00117 
00118     return 0;
00119 err:
00120     if(b)
00121         kblock_free(b);
00122     return ~0;
00123 }
00124 
00125 static int ppctx_print_kblock(kblock_t *block, io_t *out)
00126 {
00127     kblock_t *b;
00128     size_t i;
00129 
00130     if(block->name == NULL)
00131     {
00132         if(u_buf_len(block->ubuf))
00133             dbg_err_if(io_write(out, u_buf_ptr(block->ubuf), 
00134                         u_buf_len(block->ubuf)) < 0);
00135     } else {
00136         /* named block */
00137         for(i = 0; (b = u_list_get_n(block->children, i)) != NULL; ++i)
00138             dbg_err_if(ppctx_print_kblock(b, out));
00139     }
00140 
00141     return 0;
00142 err:
00143     return ~0;
00144 }
00145 
00146 
00147 static int ppctx_depend_push(ppctx_t *ppc, const char *filepath)
00148 {
00149     const char *s;
00150 
00151     dbg_err_if((s = u_strdup(filepath)) == NULL);
00152 
00153     dbg_err_if(u_list_add(ppc->depend, (void*)s));
00154 
00155     return 0;
00156 err:
00157     return ~0;
00158 }
00159 
00160 static int ppctx_print_depend(ppctx_t *ppc, io_t *in, io_t *out, io_t *depend)
00161 {
00162     char infile[U_FILENAME_MAX], outfile[U_FILENAME_MAX];
00163     char fullpath[U_FILENAME_MAX];
00164     const char *dfile;
00165     size_t i;
00166 
00167     dbg_err_if(ppc == NULL);
00168     dbg_err_if(in == NULL);
00169     dbg_err_if(out == NULL);
00170     dbg_err_if(depend == NULL);
00171 
00172     /* print make-style depends list:
00173        srcfile: depfile0 depfile1 ... depfileN */
00174 
00175     dbg_err_if(io_name_get(in, infile, U_FILENAME_MAX));
00176     dbg_err_if(io_name_get(out, outfile, U_FILENAME_MAX));
00177 
00178     /* input filename (makefile-style) */
00179     dbg_err_if(translate_makefile_filepath(infile, "$(srcdir)", fullpath, 
00180         sizeof(fullpath)));
00181 
00182     io_printf(depend, "%s %s.kld: %s ", outfile, outfile, fullpath);
00183 
00184     for(i = 0; (dfile = u_list_get_n(ppc->depend, i)) != NULL; ++i)
00185     {
00186         dbg_err_if(translate_makefile_filepath(dfile, "$(srcdir)", fullpath, 
00187             sizeof(fullpath)));
00188         io_printf(depend, "%s ", fullpath);
00189     }
00190     io_printf(depend, "\n");
00191 
00192     return 0;
00193 err:
00194     return ~0;
00195 
00196 }
00197 
00198 static int ppctx_print(ppctx_t *ppc, io_t *out)
00199 {
00200     kblock_t *b;
00201     size_t i;
00202 
00203     dbg_err_if(ppc == NULL);
00204     dbg_err_if(out == NULL);
00205 
00206     for(i = 0; (b = u_list_get_n(ppc->top->children, i)) != NULL; ++i)
00207         dbg_err_if(ppctx_print_kblock(b, out));
00208 
00209     return 0;
00210 err:
00211     return ~0;
00212 
00213 }
00214 
00215 static int ppctx_free(ppctx_t *ppc)
00216 {
00217     char *str;
00218     size_t i;
00219 
00220     if(ppc->top)
00221         kblock_free(ppc->top);
00222 
00223     if(ppc->dead)
00224         kblock_free(ppc->dead);
00225 
00226     if(ppc->depend)
00227     {
00228         for(i = 0; (str = u_list_get_n(ppc->depend, i)) != NULL; ++i)
00229             u_free(str);
00230 
00231         u_list_free(ppc->depend);
00232     }
00233 
00234     u_free(ppc);
00235 
00236     return 0;
00237 }
00238 
00239 static int ppctx_create(ppctx_t **pppc)
00240 {
00241     ppctx_t *ppc = NULL;
00242 
00243     ppc = u_zalloc(sizeof(ppctx_t));
00244     dbg_err_if(ppc == NULL);
00245 
00246     dbg_err_if(kblock_create(NULL, NULL, 0, &ppc->top));
00247     dbg_err_if(kblock_create(NULL, NULL, 0, &ppc->dead));
00248 
00249     dbg_err_if(u_list_create(&ppc->depend));
00250 
00251     ppc->cur = ppc->top;
00252     ppc->dead->parent = ppc->top;
00253 
00254     *pppc = ppc;
00255 
00256     return 0;
00257 err:
00258     if(ppc)
00259         ppctx_free(ppc);
00260     return ~0;
00261 }
00262 
00263 /* print parser context to the console */
00264 static void con_p_ctx(parser_t *p)
00265 {
00266     char fn[U_FILENAME_MAX];
00267 
00268     dbg_err_if(io_name_get(p->in, fn, U_FILENAME_MAX));
00269 
00270     /* con_ macro should be used here; we'd need a con_no_newline(...) */
00271     fprintf(stderr, "[%s:%d]: error: ", fn, p->code_line);
00272 
00273 err:
00274     return;
00275 }
00276 
00277 int translate_makefile_filepath(const char *filepath, const char *prefix, 
00278     char *buf, size_t size)
00279 {
00280     char file_in[U_FILENAME_MAX];
00281 
00282     /* input file */
00283     if(filepath[0] == '/' || filepath[0] == '\\')
00284     {   /* absolute path */
00285         dbg_err_if(u_snprintf(file_in, U_FILENAME_MAX, "%s", filepath));
00286     } else if(isalpha(filepath[0]) && filepath[1] == ':') {
00287         /* absolute path Windows (X:/....) */
00288         dbg_err_if(u_snprintf(file_in, U_FILENAME_MAX, "%s", filepath));
00289     } else {
00290         /* relative path, use $(srcdir) */
00291         dbg_err_if(u_snprintf(file_in, U_FILENAME_MAX, "%s/%s", prefix, 
00292             filepath ));
00293     }
00294 
00295     dbg_err_if(u_strlcpy(buf, file_in, size));
00296 
00297     return 0;
00298 err:
00299     return ~0;
00300 }
00301 
00302 int translate_is_a_script(const char *filename)
00303 {
00304     static const char *script_ext[] = { 
00305         ".klone", ".kl1", ".klc", 
00306         ".klx",  /* C++ page */
00307         NULL 
00308     };
00309     const char **ext;
00310 
00311     dbg_return_if(filename == NULL, 0);
00312 
00313     /* try to find an index page between default index uris */
00314     for(ext = script_ext; *ext; ++ext)
00315     {
00316         /* case insensitive matching */
00317         if(u_match_ext(filename, *ext))
00318             return 1;
00319     }
00320     return 0;
00321 }
00322 
00323 static int include_file_full_path(parser_t *p, char *inc_file, char *obuf, 
00324     size_t size)
00325 {
00326     char buf[U_FILENAME_MAX], *pc;
00327 
00328     /* get the name of the input file (that include filename path is relative
00329      * to the one of the input file) */
00330     dbg_err_if(io_name_get(p->in, buf, U_FILENAME_MAX));
00331 
00332     /* remove file name, just path is needed */
00333     dbg_err_if((pc = strrchr(buf, '/')) == NULL);
00334     ++pc; *pc = 0;
00335 
00336     dbg_err_if(u_strlcat(buf, inc_file, U_FILENAME_MAX));
00337 
00338     dbg_err_if(u_strlcpy(obuf, buf, size));
00339 
00340     return 0;
00341 err:
00342     return ~0;
00343 }
00344 
00345 static int process_directive_include(parser_t *p, char *inc_file)
00346 {
00347     ppctx_t *ppc;
00348     char fullpath[U_FILENAME_MAX], file[U_FILENAME_MAX];
00349     io_t *io = NULL;
00350 
00351     dbg_return_if (p == NULL, ~0);
00352     dbg_return_if (inc_file == NULL, ~0);
00353 
00354     dbg_err_if(io_name_get(p->in, file, U_FILENAME_MAX));
00355 
00356     dbg_err_if(include_file_full_path(p, inc_file, fullpath, U_FILENAME_MAX));
00357 
00358     /* copy include file to p->out */
00359     tr_err_ifm(u_file_open(fullpath, O_RDONLY, &io), 
00360         "unable to open included file %s", fullpath);
00361 
00362     dbg_err_if(io_printf(p->out, "<%% #line 1 \"%s\" \n %%>", fullpath));
00363 
00364     /* get the current preprocessor context */
00365     ppc = parser_get_cb_arg(p);
00366     dbg_err_if(preprocess(io, p->out, ppc));
00367 
00368     dbg_err_if(io_printf(p->out, "<%% #line %d \"%s\" \n %%>", 
00369         p->code_line, file));
00370 
00371     io_free(io);
00372 
00373     return 0;
00374 err:
00375     if(io)
00376         io_free(io);
00377     return ~0;
00378 }
00379 
00380 static int kblock_get_by_name(kblock_t *parent, const char *name, 
00381     kblock_t **pfound, size_t *pidx)
00382 {
00383     kblock_t *b;
00384     size_t i;
00385 
00386     dbg_err_if(parent == NULL);
00387 
00388     for(i = 0; (b = u_list_get_n(parent->children, i)) != NULL; ++i)
00389     {
00390         if(b->name && strcasecmp(b->name, name) == 0)
00391         {
00392             *pfound = b;
00393             *pidx = i;
00394             return 0;
00395         }
00396         if(kblock_get_by_name(b, name, pfound, pidx) == 0)
00397             return 0;
00398     }
00399         
00400 err:
00401     return ~0;
00402 }
00403 
00404 static int process_directive_block(parser_t *p, const char *name)
00405 {
00406     kblock_t *block = NULL, *old;
00407     ppctx_t *ppc;
00408     char file[U_FILENAME_MAX];
00409     size_t idx;
00410 
00411     dbg_err_if((ppc = parser_get_cb_arg(p)) == NULL);
00412 
00413     /* create a named block */
00414     dbg_err_if(kblock_create(name, NULL, 0, &block));
00415 
00416     dbg_err_if(io_name_get(p->in, file, U_FILENAME_MAX));
00417 
00418     ppc->lev++;
00419 
00420     if(!ppc->extending)
00421     {
00422         con_err_ifm(!kblock_get_by_name(ppc->top, name, &old, &idx),
00423             "[%s:%d] error: block named %s already exists", file, p->code_line,
00424             name);
00425 
00426         /* new block -> append to the block list */
00427         dbg_err_if(kblock_push_child(ppc->cur, block));
00428 
00429         ppc->cur = block;
00430 
00431         return 0;
00432     }
00433 
00434     ppc->extending++; /* increase the nesting level */
00435 
00436     /* we're extending a base template... */
00437      
00438     if(kblock_get_by_name(ppc->top, name, &old, &idx))
00439     {
00440         if(ppc->cur == ppc->top)
00441         {
00442             /* top-level block */
00443             u_con("[%s:%d] warning: extending a block (%s) that does not exist "
00444                 "in the base templates, ignoring", file, p->code_line, name);
00445 
00446             /* attach it to a dead tree (i.e. a tree that doesn't get printed)*/
00447             dbg_err_if(kblock_push_child(ppc->dead, block));
00448 
00449         } else {
00450 
00451             if(ppc->lev)
00452             {
00453                 /* nested block */
00454                 dbg_err_if(kblock_push_child(ppc->cur, block));
00455             }
00456         }
00457 
00458     } else {
00459         /* overriding block */
00460 
00461         /* block with the same name as been found at position 'idx' of
00462            its parent's list; replace the old block with the new one
00463            and save the old in new->ancestor (we may need it for
00464            <% block inherit %>) */
00465 
00466         /* save the old block ptr */
00467         block->ancestor = old;
00468         block->parent = old->parent;
00469 
00470         /* insert the new block in the position of the old block */
00471         dbg_err_if(u_list_insert(old->parent->children, block, idx));
00472 
00473         /* remove the old block from the list */
00474         dbg_err_if(u_list_del(old->parent->children, old));
00475     }
00476 
00477     ppc->cur = block;
00478 
00479     return 0;
00480 err:
00481     if(block)
00482         kblock_free(block);
00483     return ~0;
00484 }
00485 
00486 static int process_directive_endblock(parser_t *p, const char *name)
00487 {
00488     ppctx_t *ppc;
00489 
00490     dbg_err_if((ppc = parser_get_cb_arg(p)) == NULL);
00491 
00492     dbg_err_if(ppc->cur == NULL);
00493 
00494     tr_err_ifm(--ppc->lev < 0, "unbalanced endblock directive");
00495 
00496     /* if name is provided check that it's correct */
00497     if(name)
00498         tr_err_ifm(ppc->cur->name == NULL || strcasecmp(name, ppc->cur->name),
00499             "endblock name is not correct (\"%s\" used when closing to "
00500             "\"%s\" block)", name, ppc->cur->name);
00501 
00502     ppc->cur = ppc->cur->parent; /* may be NULL */
00503 
00504     if(ppc->extending)
00505     {
00506         /* decrease the nesting level */
00507         if(--ppc->extending == 1)
00508             ppc->cur = ppc->top;
00509     }
00510 
00511     return 0;
00512 err:
00513     return ~0;
00514 }
00515 
00516 static int process_directive_inherit(parser_t *p)
00517 {
00518     ppctx_t *ppc;
00519     kblock_t *anc, *b;
00520     int i;
00521 
00522     dbg_err_if((ppc = parser_get_cb_arg(p)) == NULL);
00523 
00524     dbg_err_if(ppc->cur == NULL);
00525 
00526     anc = ppc->cur->ancestor;
00527     tr_err_ifm(anc == NULL, "inherit directive used in a block "
00528         "(\"%s\") that is not extending another block", ppc->cur->name);
00529 
00530     /* move all ancestor children to the current block (that's the block whom
00531      * is extending the ancestor */
00532     for(i = 0; (b = u_list_get_n(anc->children, i)) != NULL; ++i)
00533         dbg_err_if(kblock_push_child(ppc->cur, b));
00534 
00535     /* remove all elems */
00536     while(u_list_count(anc->children))
00537         dbg_err_if(u_list_del_n(anc->children, 0, NULL));
00538 
00539     return 0;
00540 err:
00541     return ~0;
00542 }
00543 
00544 static int process_directive(parser_t *p, char *buf)
00545 {
00546     ppctx_t *ppc;
00547     char *tok, *pp;
00548     char fullpath[U_FILENAME_MAX];
00549 
00550     dbg_return_if (p == NULL, ~0);
00551     dbg_return_if (buf == NULL, ~0);
00552 
00553     /* preprocessor context */
00554     dbg_err_if((ppc = parser_get_cb_arg(p)) == NULL);
00555 
00556     /* get preprocessor command */
00557     tr_err_ifm((tok = strtok_r(buf, " \t", &pp)) == NULL,
00558         "bad or missing preprocessor command");
00559 
00560     if(strcasecmp(tok, "include") == 0)
00561     {
00562         /* get include file name */
00563         tr_err_ifm((tok = strtok_r(NULL, " \t\"", &pp)) == NULL,
00564             "bad or missing include filename");
00565 
00566         /* calc the full path of the included file and add it to the deps list*/
00567         dbg_err_if(include_file_full_path(p, tok, fullpath, U_FILENAME_MAX));
00568 
00569         dbg_err_if(ppctx_depend_push(ppc, fullpath));
00570 
00571         dbg_err_if(process_directive_include(p, tok));
00572 
00573     } else if(strcasecmp(tok, "extends") == 0) { 
00574 
00575         /* get base file name */
00576         tr_err_ifm((tok = strtok_r(NULL, " \t\"", &pp)) == NULL,
00577             "bad or missing 'extends' filename");
00578 
00579         tr_err_ifm(p->code_line > 1, "child templates must start with the "
00580             "'<%@ extends \"FILE\" %>' directive (first line) %d");
00581 
00582         /* calc the full path of the included file and add it to the deps list*/
00583         dbg_err_if(include_file_full_path(p, tok, fullpath, U_FILENAME_MAX));
00584 
00585         dbg_err_if(ppctx_depend_push(ppc, fullpath));
00586 
00587         /* no difference with include? */
00588         dbg_err_if(process_directive_include(p, tok));
00589 
00590         con_err_ifm(ppc->lev, "[%s] error: unclosed block \"%s\"", tok, 
00591             ppc->cur->name);
00592 
00593         ppc->extending++;
00594 
00595     } else if(strcasecmp(tok, "block") == 0) { 
00596 
00597         /* get block name */
00598         tr_err_ifm((tok = strtok_r(NULL, " \t\"", &pp)) == NULL,
00599             "bad or missing 'block' name");
00600 
00601         dbg_err_if(process_directive_block(p, tok));
00602 
00603     } else if(strcasecmp(tok, "endblock") == 0) { 
00604 
00605         /* try get the block name (it's not mandatory) */
00606         tok = strtok_r(NULL, " \t\"", &pp);
00607 
00608         dbg_err_if(process_directive_endblock(p, tok));
00609 
00610     } else if(strcasecmp(tok, "inherit") == 0) { 
00611 
00612         dbg_err_if(process_directive_inherit(p));
00613 
00614     } else {
00615         tr_err("unknown preprocessor directive: %s", tok);
00616     }
00617 
00618     return 0;
00619 err:
00620     return ~0;
00621 }
00622 
00623 static int parse_directive(parser_t *p, void *arg, const char *buf, size_t sz)
00624 {
00625     enum { LINE_BUFSZ = 1024 };
00626     char line[LINE_BUFSZ];
00627     io_t *io = NULL;
00628 
00629     u_unused_args(arg);
00630 
00631     dbg_return_if (p == NULL, ~0);
00632     dbg_return_if (buf == NULL, ~0);
00633     
00634     dbg_err_if(io_mem_create((char*)buf, sz, 0, &io));
00635 
00636     while(io_gets(io, line, LINE_BUFSZ) > 0)
00637         dbg_err_if(process_directive(p, line));
00638 
00639     io_free(io);
00640 
00641     return 0;
00642 err:
00643     if(io)
00644         io_free(io);
00645     return ~0;
00646 }
00647 
00648 static int cb_pre_html_block(parser_t *p, void *arg, const char *buf, size_t sz)
00649 {
00650     ppctx_t *ppc = (ppctx_t*)arg;
00651     kblock_t *block = NULL;
00652     char file[U_FILENAME_MAX];
00653     int ln;
00654     size_t i;
00655 
00656     u_unused_args(arg);
00657 
00658     dbg_err_if (p == NULL);
00659     dbg_err_if (ppc == NULL);
00660 
00661     /* create and append un unnamed */
00662     dbg_err_if(kblock_create(NULL, buf, sz, &block));
00663 
00664     if(ppc->cur == ppc->top && ppc->extending)
00665     {
00666         for(ln = p->code_line, i = 0; i < sz; ++i)
00667         {
00668             if(buf[i] == '\n')
00669                 ln++; /* find out the line of the first not-blank char */
00670             if(!isspace(buf[i]))
00671             {
00672                 dbg_err_if(io_name_get(p->in, file, U_FILENAME_MAX));
00673                 u_con("[%s:%d] warning: text out of blocks is not allowed in "
00674                     "child templates, ignoring", file, ln);
00675                 break;
00676             }
00677         }
00678 
00679         /* attach it to a dead tree (i.e. a tree that doesn't get printed)*/
00680         dbg_err_if(kblock_push_child(ppc->dead, block));
00681     } else {
00682 
00683         /* append the text block to the block list */
00684         dbg_err_if(kblock_push_child(ppc->cur, block));
00685     }
00686 
00687     return 0;
00688 err:
00689     return ~0;
00690 }
00691 
00692 static int cb_pre_code_block(parser_t *p, int cmd, void *arg, const char *buf, 
00693         size_t sz)
00694 {
00695     u_string_t *ustr = NULL;
00696     kblock_t *block = NULL;
00697     ppctx_t *ppc;
00698     char file[U_FILENAME_MAX];
00699 
00700     dbg_err_if (p == NULL);
00701     dbg_err_if((ppc = parser_get_cb_arg(p)) == NULL);
00702 
00703     if(cmd == '@')
00704     {   /* do preprocess */
00705         dbg_err_if(parse_directive(p, arg, buf, sz));
00706     } else {
00707         /* append the code to the current block */
00708         dbg_err_if(u_string_create(NULL, 0, &ustr));
00709 
00710         dbg_err_if(io_name_get(p->in, file, U_FILENAME_MAX));
00711 
00712         /* we must know the file:line where this code is coming from */
00713         if(cmd == 0 || cmd == '=')
00714         {
00715             dbg_err_if(u_string_aprintf(ustr, "<%% #line %d \"%s\" \n%%><%%", 
00716                  p->code_line, file)); 
00717             if(cmd == '=')
00718                 dbg_err_if(u_string_aprintf(ustr, "="));
00719         } else {
00720             dbg_err_if(u_string_aprintf(ustr, 
00721                 "<%%%c #line %d \"%s\" \n%%><%%%c", 
00722                  cmd, p->code_line, file, cmd)); 
00723         }
00724         dbg_err_if(u_string_aprintf(ustr, "%.*s", sz, buf));
00725         dbg_err_if(u_string_aprintf(ustr, "%%>"));
00726 
00727         /* placeholder to be subst'd in the last translation phase */
00728         dbg_err_if(u_string_aprintf(ustr, "<%%%c #line 0 __PG_FILE_C__ \n%%>", 
00729                     (cmd == '!' && cmd != 0 ? cmd : ' ')));
00730 
00731         dbg_err_if(kblock_create(NULL, u_string_c(ustr), u_string_len(ustr), 
00732                     &block));
00733 
00734         if(ppc->cur == ppc->top && ppc->extending)
00735         {
00736             dbg_err_if(io_name_get(p->in, file, U_FILENAME_MAX));
00737             u_con("[%s:%d] warning: code out of blocks is not allowed in child "
00738                 "templates, ignoring", file, p->code_line);
00739 
00740             /* attach it to a dead tree (i.e. a tree that doesn't get printed)*/
00741             dbg_err_if(kblock_push_child(ppc->dead, block));
00742         } else {
00743 
00744             dbg_err_if(kblock_push_child(ppc->cur, block));
00745         }
00746 
00747         dbg_err_if(u_string_free(ustr));
00748         ustr = NULL;
00749     }
00750 
00751     return 0;
00752 err:
00753     if(ustr)
00754         u_string_free(ustr);
00755     if(block)
00756         kblock_free(block);
00757     return ~0;
00758 }
00759 
00760 static int preprocess(io_t *in, io_t *out, ppctx_t *ppc)
00761 {
00762     parser_t *p = NULL;
00763     char file[U_FILENAME_MAX];
00764 
00765     dbg_err_if(in == NULL);
00766     dbg_err_if(out == NULL);
00767     dbg_err_if(ppc == NULL);
00768 
00769     /* create a parse that reads from in and writes to out */
00770     dbg_err_if(parser_create(&p));
00771 
00772     parser_set_cb_arg(p, ppc);
00773 
00774     /* input filename */
00775     dbg_err_if(io_name_get(in, file, U_FILENAME_MAX));
00776 
00777     parser_set_io(p, in, out);
00778 
00779     parser_set_cb_code(p, cb_pre_code_block);
00780     parser_set_cb_html(p, cb_pre_html_block);
00781 
00782     dbg_err_if(parser_run(p));
00783 
00784     con_err_ifm(ppc->lev, "[%s] error: unclosed block \"%s\"", file, 
00785         ppc->cur->name);
00786 
00787     parser_free(p);
00788 
00789     return 0;
00790 err:
00791     if(p)
00792         parser_free(p);
00793     return ~0;
00794 }
00795 
00796 static int fix_line_decl(trans_info_t *pti)
00797 {
00798     io_t *in = NULL, *tmp = NULL;
00799     char tname[U_FILENAME_MAX], buf[1024];
00800     int ln = 0;
00801 
00802     /* open the input file */
00803     con_err_ifm(u_file_open(pti->file_out, O_RDONLY, &in),
00804         "unable to open %s", pti->file_out);
00805 
00806     /* get a temporary io_t */
00807     con_err_if(u_tmpfile_open(NULL, &tmp));
00808 
00809     while(io_gets(in, buf, sizeof(buf)) > 0)
00810     {
00811         if(strstr(buf, "#line 0 __PG_FILE_C__") == NULL)
00812         {
00813             io_printf(tmp, "%s", buf);
00814             ln++; /* line number */
00815         } else
00816             io_printf(tmp, "#line %d \"%s\"\n", ln + 2, pti->file_out);
00817     }
00818 
00819     /* get the filename of the temporary io_t */
00820     dbg_err_if(io_name_get(tmp, tname, U_FILENAME_MAX));
00821 
00822     io_free(in), in = NULL;
00823     io_free(tmp), tmp = NULL;
00824 
00825     /* move tmp to file_out */
00826     u_remove(pti->file_out);
00827 
00828     u_move(tname, pti->file_out);
00829 
00830     return 0;
00831 err:
00832     if(in)
00833         io_free(in);
00834     if(tmp)
00835         io_free(tmp);
00836     return ~0;
00837 }
00838 
00839 int translate(trans_info_t *pti)
00840 {
00841     io_t *in = NULL, *out = NULL, *tmp = NULL, *depend = NULL;
00842     ppctx_t *ppc = NULL;
00843     codec_t *gzip = NULL, *aes = NULL;
00844     char tname[U_FILENAME_MAX];
00845 
00846     dbg_return_if (pti == NULL, ~0);
00847     
00848     /* open the input file */
00849     con_err_ifm(u_file_open(pti->file_in, O_RDONLY, &in),
00850         "unable to open %s", pti->file_in);
00851 
00852     /* open the output file */
00853     con_err_ifm(u_file_open(pti->file_out, O_CREAT | O_TRUNC | O_WRONLY, &out),
00854         "unable to open %s", pti->file_out);
00855 
00856     /* open the depend output file */
00857     if(pti->depend_out[0])
00858         con_err_ifm(u_file_open(pti->depend_out, O_CREAT | O_TRUNC | O_WRONLY, 
00859             &depend), "unable to open %s", pti->depend_out);
00860 
00861     /* should choose the right translator based on file extensions or config */
00862     if(translate_is_a_script(pti->file_in))
00863     {
00864         /* get a temporary io_t */
00865         con_err_if(u_tmpfile_open(NULL, &tmp));
00866 
00867         /* create a preprocessor context */
00868         dbg_err_if(ppctx_create(&ppc));
00869 
00870         /* save the preprocessed in file to tmp */
00871         dbg_err_if(preprocess(in, tmp, ppc));
00872 
00873         /* print out the preprocessed file */
00874         dbg_err_if(ppctx_print(ppc, tmp));
00875 
00876         /* reset the tmp io */
00877         io_seek(tmp, 0);
00878 
00879         /* translate it */
00880         dbg_err_if(translate_script_to_c(tmp, out, pti));
00881 
00882         /* get the filename of the temporary io_t */
00883         dbg_err_if(io_name_get(tmp, tname, U_FILENAME_MAX));
00884 
00885         /* free the tmp io */
00886         io_free(tmp); tmp = NULL;
00887 
00888         /* remove the tmp file */
00889         u_remove(tname);
00890 
00891         /* print out the depend .kld file */
00892         if(depend)
00893             dbg_err_if(ppctx_print_depend(ppc, in, out, depend));
00894 
00895         dbg_err_if(ppctx_free(ppc)); ppc = NULL;
00896     } else {
00897         /* check if compression is requested */
00898 #ifdef HAVE_LIBZ
00899         if(pti->comp)
00900         {
00901             /* set a compression filter to the input stream */
00902             dbg_err_if(codec_gzip_create(GZIP_COMPRESS, &gzip));
00903             dbg_err_if(io_codec_add_tail(in, gzip));
00904             gzip = NULL;
00905         }
00906 #endif
00907 #ifdef SSL_ON
00908         /* check if encryption is requested */
00909         if(pti->encrypt)
00910         {
00911             /* set a cipher filter */
00912             dbg_err_if(codec_cipher_create(CIPHER_ENCRYPT, EVP_aes_256_cbc(),
00913                 pti->key, NULL, &aes));
00914             dbg_err_if(io_codec_add_tail(in, aes));
00915             aes = NULL;
00916         }
00917 #endif
00918         dbg_err_if(translate_opaque_to_c(in, out, pti));
00919     }
00920 
00921     if(pti->depend_out[0])
00922         io_free(depend), depend = NULL;
00923 
00924     io_free(out), out = NULL;
00925     io_free(in), in = NULL;
00926 
00927     /* replace '#line 0 __PG_FILE_C__' lines with '#line N "real_filename.c"' */
00928     if(translate_is_a_script(pti->file_in))
00929         dbg_err_if(fix_line_decl(pti));
00930 
00931     return 0;
00932 err:
00933     if(pti && strlen(pti->emsg))
00934         u_con("%s", pti->emsg);
00935     if(gzip)
00936         codec_free(gzip);
00937     if(tmp)
00938         io_free(tmp);
00939     if(depend)
00940         io_free(depend);
00941     if(in)
00942         io_free(in);
00943     if(out)
00944         io_free(out);
00945     return ~0;
00946 }

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