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 <ctype.h>
00015 #include <fcntl.h>
00016 #include <unistd.h>
00017 #include <limits.h>
00018 #ifdef HAVE_LIBOPENSSL
00019 #include <openssl/evp.h>
00020 #endif
00021 #include <u/libu.h>
00022 #include <klone/os.h>
00023 #include <klone/translat.h>
00024 #include <klone/parser.h>
00025 #include <klone/utils.h>
00026 #include <klone/os.h>
00027 #include <klone/io.h>
00028 #include <klone/codec.h>
00029 #include <klone/codecs.h>
00030
00031 #define tr_err(...) \
00032 do { con_p_ctx(p); con_err(__VA_ARGS__); } while(0)
00033 #define tr_err_if(expr) \
00034 do { if( (expr) ) { con_p_ctx(p); con("%s", #expr); goto err; } } while(0)
00035 #define tr_err_ifm(expr, ...) \
00036 do { if( (expr) ) { con_p_ctx(p); con(__VA_ARGS__); goto err; } } while(0)
00037
00038 static int preprocess(io_t *in, io_t *out);
00039
00040
00041 static void con_p_ctx(parser_t *p)
00042 {
00043 char fn[U_FILENAME_MAX];
00044
00045 dbg_err_if(io_name_get(p->in, fn, U_FILENAME_MAX));
00046
00047
00048 fprintf(stderr, "[%s:%d]: error: ", fn, p->code_line);
00049 err:
00050 return;
00051 }
00052
00053 static int is_a_script(const char *filename)
00054 {
00055 static const char *script_ext[] = {
00056 ".klone", ".kl1", ".klc",
00057 ".klx",
00058 NULL
00059 };
00060 const char **ext;
00061
00062 dbg_return_if(filename == NULL, 0);
00063
00064
00065 for(ext = script_ext; *ext; ++ext)
00066 {
00067
00068 if(u_match_ext(filename, *ext))
00069 return 1;
00070 }
00071 return 0;
00072 }
00073
00074 static int process_directive_include(parser_t *p, char *inc_file)
00075 {
00076 enum { BUFSZ = 4096 };
00077 char buf[U_FILENAME_MAX], *pc;
00078 char file[U_FILENAME_MAX];
00079 io_t *io = NULL;
00080
00081 dbg_return_if (p == NULL, ~0);
00082 dbg_return_if (inc_file == NULL, ~0);
00083
00084 dbg_err_if(io_name_get(p->in, file, U_FILENAME_MAX));
00085 dbg_err_if(io_name_get(p->in, buf, U_FILENAME_MAX));
00086
00087
00088 dbg_err_if((pc = strrchr(buf, '/')) == NULL);
00089 ++pc; *pc = 0;
00090
00091 dbg_err_if(strlen(buf) + strlen(inc_file) >= BUFSZ);
00092
00093 strcat(buf, inc_file);
00094
00095
00096 tr_err_ifm(u_file_open(buf, O_RDONLY, &io),
00097 "unable to open included file %s", buf);
00098
00099 dbg_err_if(io_printf(p->out, "<%% #line 1 \"%s\" \n %%>", buf));
00100
00101 dbg_err_if(preprocess(io, p->out));
00102
00103 dbg_err_if(io_printf(p->out, "<%% #line %d \"%s\" \n %%>",
00104 p->code_line, file));
00105
00106 io_free(io);
00107
00108 return 0;
00109 err:
00110 if(io)
00111 io_free(io);
00112 return ~0;
00113 }
00114
00115 static int process_directive(parser_t *p, char *buf)
00116 {
00117 char *tok, *pp;
00118
00119 dbg_return_if (p == NULL, ~0);
00120 dbg_return_if (buf == NULL, ~0);
00121
00122
00123 tr_err_ifm((tok = strtok_r(buf, " \t", &pp)) == NULL,
00124 "bad or missing preprocessor command");
00125
00126 if(strcasecmp(tok, "include") == 0)
00127 {
00128
00129 tr_err_ifm((tok = strtok_r(NULL, " \t\"", &pp)) == NULL,
00130 "bad or missing include filename");
00131
00132 dbg_err_if(process_directive_include(p, tok));
00133 } else {
00134 tr_err("unknown preprocessor directive: %s", tok);
00135 }
00136
00137 return 0;
00138 err:
00139 return ~0;
00140 }
00141
00142 static int parse_directive(parser_t *p, void *arg, const char *buf, size_t sz)
00143 {
00144 enum { LINE_BUFSZ = 1024 };
00145 char line[LINE_BUFSZ];
00146 io_t *io = NULL;
00147
00148 u_unused_args(arg);
00149
00150 dbg_return_if (p == NULL, ~0);
00151 dbg_return_if (buf == NULL, ~0);
00152
00153 dbg_err_if(io_mem_create((char*)buf, sz, 0, &io));
00154
00155 while(io_gets(io, line, LINE_BUFSZ) > 0)
00156 dbg_err_if(process_directive(p, line));
00157
00158 io_free(io);
00159
00160 return 0;
00161 err:
00162 if(io)
00163 io_free(io);
00164 return ~0;
00165 }
00166
00167 static int cb_pre_html_block(parser_t *p, void *arg, const char *buf, size_t sz)
00168 {
00169 u_unused_args(arg);
00170
00171 dbg_err_if (p == NULL);
00172
00173 dbg_err_if(io_write(p->out, buf, sz) < 0);
00174
00175 return 0;
00176 err:
00177 return ~0;
00178 }
00179
00180 static int cb_pre_code_block(parser_t *p, int cmd, void *arg, const char *buf,
00181 size_t sz)
00182 {
00183 char file[U_FILENAME_MAX];
00184
00185 dbg_err_if (p == NULL);
00186
00187 if(cmd == '@')
00188 {
00189 dbg_err_if(parse_directive(p, arg, buf, sz));
00190 } else {
00191 dbg_err_if(io_name_get(p->in, file, U_FILENAME_MAX));
00192 if(cmd != '=')
00193 dbg_err_if(io_printf(p->out, "<%%%c #line %d \"%s\" \n%%>",
00194 (cmd == 0 ? ' ' : cmd), p->code_line, file));
00195 else
00196 dbg_err_if(io_printf(p->out, "<%% #line %d \"%s\" \n%%>",
00197 p->code_line, file));
00198
00199 dbg_err_if(io_printf(p->out, "<%%%c ", (cmd == 0 ? ' ' : cmd)) < 0);
00200 dbg_err_if(io_write(p->out, buf, sz) < 0);
00201 dbg_err_if(io_printf(p->out, "%%>") < 0);
00202 }
00203 return 0;
00204 err:
00205 return ~0;
00206 }
00207
00208 static int preprocess(io_t *in, io_t *out)
00209 {
00210 parser_t *p = NULL;
00211
00212
00213 dbg_err_if(parser_create(&p));
00214
00215 parser_set_io(p, in, out);
00216
00217 parser_set_cb_code(p, cb_pre_code_block);
00218 parser_set_cb_html(p, cb_pre_html_block);
00219
00220 dbg_err_if(parser_run(p));
00221
00222 parser_free(p);
00223
00224 return 0;
00225 err:
00226 if(p)
00227 parser_free(p);
00228 return ~0;
00229 }
00230
00231 int translate(trans_info_t *pti)
00232 {
00233 io_t *in = NULL, *out = NULL, *tmp = NULL;
00234 codec_t *gzip = NULL, *aes = NULL;
00235 char tname[U_FILENAME_MAX];
00236
00237 dbg_return_if (pti == NULL, ~0);
00238
00239
00240 con_err_ifm(u_file_open(pti->file_in, O_RDONLY, &in),
00241 "unable to open %s", pti->file_in);
00242
00243
00244 con_err_ifm(u_file_open(pti->file_out, O_CREAT | O_TRUNC | O_WRONLY, &out),
00245 "unable to open %s", pti->file_out);
00246
00247
00248 if(is_a_script(pti->file_in))
00249 {
00250
00251 con_err_if(u_tmpfile_open(&tmp));
00252
00253
00254 dbg_err_if(preprocess(in, tmp));
00255
00256
00257 io_seek(tmp, 0);
00258
00259
00260 dbg_err_if(translate_script_to_c(tmp, out, pti));
00261
00262
00263 dbg_err_if(io_name_get(tmp, tname, U_FILENAME_MAX));
00264
00265
00266 io_free(tmp);
00267
00268
00269 unlink(tname);
00270 } else {
00271
00272 #ifdef HAVE_LIBZ
00273 if(pti->comp)
00274 {
00275
00276 dbg_err_if(codec_gzip_create(GZIP_COMPRESS, &gzip));
00277 dbg_err_if(io_codec_add_tail(in, gzip));
00278 gzip = NULL;
00279 }
00280 #endif
00281 #ifdef HAVE_LIBOPENSSL
00282
00283 if(pti->encrypt)
00284 {
00285
00286 dbg_err_if(codec_cipher_create(CIPHER_ENCRYPT, EVP_aes_256_cbc(),
00287 pti->key, NULL, &aes));
00288 dbg_err_if(io_codec_add_tail(in, aes));
00289 aes = NULL;
00290 }
00291 #endif
00292 dbg_err_if(translate_opaque_to_c(in, out, pti));
00293 }
00294
00295 io_free(in);
00296 io_free(out);
00297
00298 return 0;
00299 err:
00300 if(pti && strlen(pti->emsg))
00301 con("%s", pti->emsg);
00302 if(gzip)
00303 codec_free(gzip);
00304 if(tmp)
00305 io_free(tmp);
00306 if(in)
00307 io_free(in);
00308 if(out)
00309 io_free(out);
00310 return ~0;
00311 }