Whitespace fixes
[amule.git] / src / webserver / src / php_core_lib.cpp
blobb68345dceb768442c6c569d8fe60701a87b69a87
1 //
2 // This file is part of the aMule Project.
4 // Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2005-2011 Froenchenko Leonid ( lfroen@gmail.com / http://www.amule.org )
6 //
7 // Any parts of this program derived from the xMule, lMule or eMule project,
8 // or contributed by third-party developers are copyrighted by their
9 // respective authors.
11 // This program is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation; either version 2 of the License, or
14 // (at your option) any later version.
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
21 // You should have received a copy of the GNU General Public License
22 // along with this program; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
30 #include <string> // Do_not_auto_remove (g++-4.0.1)
32 #ifdef HAVE_SYS_TYPES_H
33 # include <sys/types.h>
34 #endif
36 #ifdef PHP_STANDALONE_EN
37 # include <map>
38 # include <string>
39 # include <list>
40 # include <regex.h>
41 #else
42 # include "WebServer.h"
43 # include <ec/cpp/ECSpecialTags.h>
44 # include <wx/regex.h>
45 # include <wx/datetime.h>
46 #endif
48 #include "php_syntree.h"
49 #include "php_core_lib.h"
50 #include <stdarg.h>
52 #ifdef ENABLE_NLS
53 #include <libintl.h>
54 #endif
57 * Built-in php functions. Those are both library and core internals.
59 * I'm not going event to get near to what Zend provide, but
60 * at least base things must be here
64 * Print info about variable: php var_dump()
66 void php_var_dump(PHP_VALUE_NODE *node, int ident, int ref)
68 for(int i = 0; i < ident;i++) {
69 printf("\t");
71 if ( ref ) printf("&");
72 switch(node->type) {
73 case PHP_VAL_BOOL: printf("bool(%s)\n", node->int_val ? "true" : "false"); break;
74 case PHP_VAL_INT: printf("int(%"PRIu64")\n", node->int_val); break;
75 case PHP_VAL_FLOAT: printf("float(%f)\n", node->float_val); break;
76 case PHP_VAL_STRING: printf("string(%d) \"%s\"\n", (int)strlen(node->str_val), node->str_val); break;
77 case PHP_VAL_OBJECT: printf("Object(%s)\n", node->obj_val.class_name); break;
78 case PHP_VAL_ARRAY: {
79 int arr_size = array_get_size(node);
80 printf("array(%d) {\n", arr_size);
81 for(int i = 0; i < arr_size;i++) {
82 const std::string &curr_key = array_get_ith_key(node, i);
83 PHP_VAR_NODE *curr_val = array_get_by_str_key(node, curr_key);
84 printf("\t[%s]=>\n", curr_key.c_str());
85 php_var_dump(&curr_val->value, ident+1, curr_val->ref_count > 1);
87 for(int i = 0; i < ident;i++) {
88 printf("\t");
90 printf("}\n");
91 break;
93 case PHP_VAL_NONE: printf("NULL\n"); break;
94 case PHP_VAL_VAR_NODE:
95 case PHP_VAL_INT_DATA: assert(0); break;
99 void php_native_var_dump(PHP_VALUE_NODE *)
101 PHP_SCOPE_ITEM *si = get_scope_item(g_current_scope, "__param_0");
102 if ( si ) {
103 assert((si->type == PHP_SCOPE_VAR)||(si->type == PHP_SCOPE_PARAM));
104 php_var_dump(&si->var->value, 0, 0);
105 } else {
106 php_report_error(PHP_ERROR, "Invalid or missing argument");
112 * Sorting stl-way requires operator ">"
114 class SortElem {
115 public:
116 SortElem() {}
117 SortElem(PHP_VAR_NODE *p) { obj = p; }
119 PHP_VAR_NODE *obj;
120 static PHP_SYN_FUNC_DECL_NODE *callback;
122 friend bool operator<(const SortElem &o1, const SortElem &o2);
125 PHP_SYN_FUNC_DECL_NODE *SortElem::callback = 0;
127 bool operator<(const SortElem &o1, const SortElem &o2)
129 PHP_VALUE_NODE result;
131 value_value_assign(&SortElem::callback->params[0].si_var->var->value, &o1.obj->value);
132 value_value_assign(&SortElem::callback->params[1].si_var->var->value, &o2.obj->value);
134 switch_push_scope_table((PHP_SCOPE_TABLE_TYPE *)SortElem::callback->scope);
137 // params passed by-value, all & notations ignored
139 result.type = PHP_VAL_NONE;
140 php_execute(SortElem::callback->code, &result);
141 cast_value_dnum(&result);
143 // restore stack, free arg list
145 switch_pop_scope_table(0);
147 value_value_free(&SortElem::callback->params[0].si_var->var->value);
148 value_value_free(&SortElem::callback->params[1].si_var->var->value);
150 return result.int_val != 0;
153 void php_native_usort(PHP_VALUE_NODE *)
155 PHP_SCOPE_ITEM *si = get_scope_item(g_current_scope, "__param_0");
156 if ( !si || (si->var->value.type != PHP_VAL_ARRAY)) {
157 php_report_error(PHP_ERROR, "Invalid or missing argument (array)");
158 return;
160 PHP_VAR_NODE *array = si->var;
161 si = get_scope_item(g_current_scope, "__param_1");
162 if ( !si || (si->var->value.type != PHP_VAL_STRING)) {
163 php_report_error(PHP_ERROR, "Invalid or missing argument (func name)");
164 return;
166 char *cmp_func_name = si->var->value.str_val;
167 si = get_scope_item(g_global_scope, cmp_func_name);
168 if ( !si || (si->type != PHP_SCOPE_FUNC)) {
169 php_report_error(PHP_ERROR, "Compare function [%s] not found", cmp_func_name);
170 return;
172 PHP_SYN_FUNC_DECL_NODE *func_decl = si->func->func_decl;
175 // usort invalidates keys, and sorts values
177 PHP_ARRAY_TYPE *arr_obj = (PHP_ARRAY_TYPE *)array->value.ptr_val;
179 // create vector of values
181 if ( arr_obj->array.size() == 0 ) {
182 php_report_error(PHP_WARNING, "Sorting array of size 0");
183 return;
186 std::list<SortElem> sort_list;
187 for(PHP_ARRAY_ITER_TYPE i = arr_obj->array.begin(); i != arr_obj->array.end(); i++) {
188 sort_list.push_back(SortElem(i->second));
190 SortElem::callback = func_decl;
191 sort_list.sort();
193 arr_obj->array.clear();
194 arr_obj->sorted_keys.clear();
195 unsigned int key = 0;
196 for(std::list<SortElem>::iterator i = sort_list.begin(); i != sort_list.end(); i++) {
197 array_add_to_int_key(&array->value, key++, i->obj);
204 * String functions
206 void php_native_strlen(PHP_VALUE_NODE *result)
208 PHP_SCOPE_ITEM *si = get_scope_item(g_current_scope, "__param_0");
209 if ( si ) {
210 PHP_VALUE_NODE *param = &si->var->value;
211 cast_value_str(param);
212 if ( result ) {
213 cast_value_dnum(result);
214 result->int_val = strlen(param->str_val);
216 } else {
217 php_report_error(PHP_ERROR, "Invalid or missing argument");
221 void php_native_count(PHP_VALUE_NODE *result)
223 PHP_SCOPE_ITEM *si = get_scope_item(g_current_scope, "__param_0");
224 if ( si ) {
225 PHP_VALUE_NODE *param = &si->var->value;
226 if ( result ) {
227 cast_value_dnum(result);
228 if ( (si->var->value.type == PHP_VAL_NONE) || (si->var->value.type != PHP_VAL_ARRAY) ) {
229 result->int_val = 0;
230 } else {
231 result->int_val = array_get_size(param);
234 } else {
235 php_report_error(PHP_ERROR, "Invalid or missing argument");
239 void php_native_isset(PHP_VALUE_NODE *result)
241 PHP_SCOPE_ITEM *si = get_scope_item(g_current_scope, "__param_0");
242 if ( si ) {
243 PHP_VALUE_NODE *param = &si->var->value;
244 cast_value_str(param);
245 if ( result ) {
246 cast_value_bool(result);
247 result->int_val = (si->var->value.type == PHP_VAL_NONE) ? 0 : 1;
249 } else {
250 php_report_error(PHP_ERROR, "Invalid or missing argument");
254 void php_native_substr(PHP_VALUE_NODE * /*result*/)
256 PHP_SCOPE_ITEM *si_str = get_scope_item(g_current_scope, "__param_0");
257 PHP_VALUE_NODE *str = &si_str->var->value;
258 if ( si_str ) {
259 cast_value_str(str);
260 } else {
261 php_report_error(PHP_ERROR, "Invalid or missing argument 'str' for 'substr'");
262 return;
264 PHP_SCOPE_ITEM *si_start = get_scope_item(g_current_scope, "__param_1");
265 PHP_VALUE_NODE *start = &si_start->var->value;
266 if ( si_start ) {
267 cast_value_dnum(start);
268 } else {
269 php_report_error(PHP_ERROR, "Invalid or missing argument 'start' for 'substr'");
270 return;
272 // 3-rd is optional
273 PHP_SCOPE_ITEM *si_end = get_scope_item(g_current_scope, "__param_2");
274 PHP_VALUE_NODE end = { PHP_VAL_INT, { 0 } };
275 if ( si_end ) {
276 end = si_end->var->value;
278 cast_value_dnum(&end);
284 void php_native_split(PHP_VALUE_NODE *result)
286 if ( result ) {
287 cast_value_array(result);
288 } else {
289 return;
291 PHP_VALUE_NODE *pattern, *string_to_split, *split_limit;
292 PHP_SCOPE_ITEM *si = get_scope_item(g_current_scope, "__param_0");
293 if ( si ) {
294 pattern = &si->var->value;
295 cast_value_str(pattern);
296 } else {
297 php_report_error(PHP_ERROR, "Invalid or missing argument: pattern");
298 return;
300 si = get_scope_item(g_current_scope, "__param_1");
301 if ( si ) {
302 string_to_split = &si->var->value;
303 cast_value_str(string_to_split);
304 } else {
305 php_report_error(PHP_ERROR, "Invalid or missing argument: string");
306 return;
308 si = get_scope_item(g_current_scope, "__param_2");
309 if ( si ) {
310 split_limit = &si->var->value;
311 cast_value_dnum(split_limit);
312 } else {
313 php_report_error(PHP_ERROR, "Invalid or missing argument: string");
314 return;
316 #ifdef PHP_STANDALONE_EN
317 regex_t preg;
318 char error_buff[256];
319 int reg_result = regcomp(&preg, pattern->str_val, REG_EXTENDED);
320 if ( reg_result ) {
321 regerror(reg_result, &preg, error_buff, sizeof(error_buff));
322 php_report_error(PHP_ERROR, "Failed in regcomp: %s", error_buff);
323 #else
324 wxRegEx preg;
325 if (!preg.Compile(wxString(char2unicode(pattern->str_val)), wxRE_EXTENDED)) {
326 php_report_error(PHP_ERROR, "Failed in Compile of: %s", pattern->str_val);
327 #endif
328 return;
331 #ifdef PHP_STANDALONE_EN
332 size_t nmatch = strlen(string_to_split->str_val);
333 regmatch_t *pmatch = new regmatch_t[nmatch];
334 #endif
335 char *str_2_match = string_to_split->str_val;
336 char *tmp_buff = new char[strlen(string_to_split->str_val)+1];
338 while ( 1 ) {
339 // printf("matching: %s\n", str_2_match);
340 #ifdef PHP_STANDALONE_EN
341 reg_result = regexec(&preg, str_2_match, nmatch, pmatch, 0);
342 if ( reg_result ) {
343 #else
344 if (!preg.Matches(wxString(char2unicode(str_2_match)))) {
345 #endif
346 // no match
347 break;
349 #ifndef PHP_STANDALONE_EN
350 // get matching position
351 size_t start, len;
352 if (!preg.GetMatch(&start, &len)) {
353 break; // shouldn't happen
355 #endif
357 * I will use only first match, since I don't see any sense to have more
358 * then 1 match in split() call
360 #ifdef PHP_STANDALONE_EN
361 for(int i = 0; i < pmatch[0].rm_so; i++) {
362 #else
363 for(size_t i = 0; i < start; i++) {
364 #endif
365 tmp_buff[i] = str_2_match[i];
367 #ifdef PHP_STANDALONE_EN
368 tmp_buff[pmatch[0].rm_so] = 0;
369 #else
370 tmp_buff[start] = 0;
371 #endif
372 // printf("Match added [%s]\n", tmp_buff);
374 PHP_VAR_NODE *match_val = array_push_back(result);
375 match_val->value.type = PHP_VAL_STRING;
376 match_val->value.str_val = strdup(tmp_buff);
378 #ifdef PHP_STANDALONE_EN
379 str_2_match += pmatch[0].rm_eo;
380 #else
381 str_2_match += start + len;
382 #endif
385 PHP_VAR_NODE *match_val = array_push_back(result);
386 match_val->value.type = PHP_VAL_STRING;
387 match_val->value.str_val = strdup(str_2_match);
389 delete [] tmp_buff;
390 #ifdef PHP_STANDALONE_EN
391 delete [] pmatch;
392 regfree(&preg);
393 #endif
396 #ifdef ENABLE_NLS
398 void php_native_gettext(PHP_VALUE_NODE *result)
400 PHP_SCOPE_ITEM *si_str = get_scope_item(g_current_scope, "__param_0");
401 PHP_VALUE_NODE *str = &si_str->var->value;
402 if ( si_str ) {
403 cast_value_str(str);
404 } else {
405 php_report_error(PHP_ERROR, "Invalid or missing argument 'msgid' for 'gettext'");
406 return;
408 if ( result ) {
409 cast_value_dnum(result);
410 result->type = PHP_VAL_STRING;
411 result->str_val = strdup(gettext(str->str_val));
415 void php_native_gettext_noop(PHP_VALUE_NODE *result)
417 PHP_SCOPE_ITEM *si_str = get_scope_item(g_current_scope, "__param_0");
418 PHP_VALUE_NODE *str = &si_str->var->value;
419 if ( si_str ) {
420 cast_value_str(str);
421 } else {
422 php_report_error(PHP_ERROR, "Invalid or missing argument 'msgid' for 'gettext_noop'");
423 return;
425 if ( result ) {
426 cast_value_dnum(result);
427 result->type = PHP_VAL_STRING;
428 result->str_val = strdup(str->str_val);
432 void php_native_ngettext(PHP_VALUE_NODE *result)
434 PHP_SCOPE_ITEM *si_msgid = get_scope_item(g_current_scope, "__param_0");
435 PHP_VALUE_NODE *msgid = &si_msgid->var->value;
436 if ( si_msgid ) {
437 cast_value_str(msgid);
438 } else {
439 php_report_error(PHP_ERROR, "Invalid or missing argument 'msgid' for 'ngettext'");
440 return;
442 PHP_SCOPE_ITEM *si_msgid_plural = get_scope_item(g_current_scope, "__param_1");
443 PHP_VALUE_NODE *msgid_plural = &si_msgid_plural->var->value;
444 if ( si_msgid_plural ) {
445 cast_value_str(msgid_plural);
446 } else {
447 php_report_error(PHP_ERROR, "Invalid or missing argument 'msgid_plural' for 'ngettext'");
448 return;
450 PHP_SCOPE_ITEM *si_count = get_scope_item(g_current_scope, "__param_2");
451 PHP_VALUE_NODE *count = &si_count->var->value;
452 if ( si_count ) {
453 cast_value_dnum(count);
454 } else {
455 php_report_error(PHP_ERROR, "Invalid or missing argument 'count' for 'ngettext'");
456 return;
458 if ( result ) {
459 cast_value_dnum(result);
460 result->type = PHP_VAL_STRING;
461 result->str_val = strdup(ngettext(msgid->str_val, msgid_plural->str_val, count->int_val));
464 #endif
466 PHP_BLTIN_FUNC_DEF core_lib_funcs[] = {
468 "var_dump",
470 php_native_var_dump,
473 "strlen",
474 1, php_native_strlen,
477 "count",
478 1, php_native_count,
481 "isset",
482 1, php_native_isset,
485 "usort",
487 php_native_usort,
490 "split",
492 php_native_split,
494 #ifdef ENABLE_NLS
496 "_",
497 1, php_native_gettext,
500 "gettext",
501 1, php_native_gettext,
504 "gettext_noop",
505 1, php_native_gettext_noop,
508 "ngettext",
509 3, php_native_ngettext,
511 #endif
512 { 0, 0, 0, },
515 void php_init_core_lib()
517 // load function definitions
518 PHP_BLTIN_FUNC_DEF *curr_def = core_lib_funcs;
519 while ( curr_def->name ) {
520 php_add_native_func(curr_def);
521 curr_def++;
526 // lexer has no include file
528 extern "C"
529 void php_set_input_buffer(char *buf, int len);
531 CPhPLibContext::CPhPLibContext(CWebServerBase *server, const char *file)
533 g_curr_context = this;
535 m_server = server;
537 php_engine_init();
538 phpin = fopen(file, "r");
539 if ( !phpin ) {
540 return;
543 phpparse();
545 m_syn_tree_top = g_syn_tree_top;
546 m_global_scope = g_global_scope;
549 CPhPLibContext::CPhPLibContext(CWebServerBase *server, char *php_buf, int len)
551 g_curr_context = this;
553 m_server = server;
555 php_engine_init();
557 m_global_scope = g_global_scope;
559 php_set_input_buffer(php_buf, len);
560 phpparse();
562 m_syn_tree_top = g_syn_tree_top;
565 CPhPLibContext::~CPhPLibContext()
567 SetContext();
568 php_engine_free();
571 void CPhPLibContext::SetContext()
573 g_syn_tree_top = m_syn_tree_top;
574 g_global_scope = m_global_scope;
577 void CPhPLibContext::Execute(CWriteStrBuffer *buf)
579 m_curr_str_buffer = buf;
581 PHP_VALUE_NODE val;
582 php_execute(g_syn_tree_top, &val);
585 CPhPLibContext *CPhPLibContext::g_curr_context = 0;
588 * For simplicity and performance sake, this function can
589 * only handle limited-length printf's. In should be NOT be used
590 * for string concatenation like printf("xyz %s %s", s1, s2).
592 * Engine will call Print for "print" and "echo"
594 void CPhPLibContext::Printf(const char *str, ...)
596 va_list args;
598 va_start(args, str);
599 if ( !g_curr_context || !g_curr_context->m_curr_str_buffer ) {
600 vprintf(str, args);
601 } else {
602 char buf[4096];
603 vsnprintf(buf, sizeof(buf), str, args);
604 g_curr_context->m_curr_str_buffer->Write(buf);
606 va_end(args);
609 void CPhPLibContext::Print(const char *str)
611 if ( !g_curr_context || !g_curr_context->m_curr_str_buffer ) {
612 printf("%s", str);
613 } else {
614 g_curr_context->m_curr_str_buffer->Write(str);
619 CPhpFilter::CPhpFilter(CWebServerBase *server, CSession *sess,
620 const char *file, CWriteStrBuffer *buff)
622 FILE *f = fopen(file, "r");
623 if ( !f ) {
624 printf("ERROR: php can not open source file [%s]\n", file);
625 return;
627 if ( fseek(f, 0, SEEK_END) != 0 ) {
628 printf("ERROR: fseek failed on php source file [%s]\n", file);
629 return;
631 int size = ftell(f);
632 char *buf = new char [size+1];
633 rewind(f);
634 // fread may actually read less if it is a CR-LF-file in Windows
635 size = fread(buf, 1, size, f);
636 buf[size] = 0;
637 fclose(f);
638 char *scan_ptr = buf;
639 char *curr_code_end = buf;
640 while ( strlen(scan_ptr) ) {
641 scan_ptr = strstr(scan_ptr, "<?php");
642 if ( !scan_ptr ) {
643 buff->Write(curr_code_end);
644 break;
646 if ( scan_ptr != curr_code_end ) {
647 buff->Write(curr_code_end, scan_ptr - curr_code_end);
649 curr_code_end = strstr(scan_ptr, "?>");
650 if ( !curr_code_end ) {
651 break;
653 curr_code_end += 2; // include "?>" in buffer
655 int len = curr_code_end - scan_ptr;
657 CPhPLibContext *context = new CPhPLibContext(server, scan_ptr, len);
659 #ifndef PHP_STANDALONE_EN
660 load_session_vars("HTTP_GET_VARS", sess->m_get_vars);
661 load_session_vars("_SESSION", sess->m_vars);
662 #endif
664 context->Execute(buff);
666 #ifndef PHP_STANDALONE_EN
667 save_session_vars(sess->m_vars);
668 #endif
670 delete context;
672 scan_ptr = curr_code_end;
675 #ifndef PHP_STANDALONE_EN
676 sess->m_get_vars.clear();
677 #endif
679 delete [] buf;
684 * String buffer: almost same as regular 'string' class, but,
685 * without reallocation when full. Instead, new buffer is
686 * allocated, and added to list
688 CWriteStrBuffer::CWriteStrBuffer()
690 m_alloc_size = 1024;
691 m_total_length = 0;
693 AllocBuf();
696 CWriteStrBuffer::~CWriteStrBuffer()
698 for(std::list<char *>::iterator i = m_buf_list.begin(); i != m_buf_list.end(); i++) {
699 delete [] *i;
701 delete [] m_curr_buf;
704 void CWriteStrBuffer::AllocBuf()
706 m_curr_buf = new char [m_alloc_size];
707 m_buf_ptr = m_curr_buf;
708 m_curr_buf_left = m_alloc_size;
711 void CWriteStrBuffer::Write(const char *s, int len)
713 if ( len == -1 ) {
714 len = strlen(s);
716 m_total_length += len;
718 while ( len ) {
719 if ( (len + 1) <= m_curr_buf_left ) {
720 strncpy(m_buf_ptr, s, len);
721 m_buf_ptr += len;
722 m_curr_buf_left -= len;
723 len = 0;
724 } else {
725 memcpy(m_buf_ptr, s, m_curr_buf_left);
726 int rem_len = len - m_curr_buf_left;
727 s += m_curr_buf_left;
729 len = rem_len;
730 m_buf_list.push_back(m_curr_buf);
731 AllocBuf();
736 void CWriteStrBuffer::CopyAll(char *dst_buffer)
738 char *curr_ptr = dst_buffer;
739 int rem_size = m_total_length;
740 for(std::list<char *>::iterator i = m_buf_list.begin(); i != m_buf_list.end(); i++) {
741 memcpy(curr_ptr, *i, m_alloc_size);
742 rem_size -= m_alloc_size;
743 curr_ptr += m_alloc_size;
745 if ( rem_size ) {
746 memcpy(curr_ptr, m_curr_buf, rem_size);
748 *(curr_ptr + rem_size) = 0;
751 void load_session_vars(const char *target, std::map<std::string, std::string> &varmap)
753 PHP_EXP_NODE *sess_vars_exp_node = get_var_node(target);
754 PHP_VAR_NODE *sess_vars = sess_vars_exp_node->var_si_node->var;
755 // i'm not building exp tree, node not needed
756 delete sess_vars_exp_node;
757 cast_value_array(&sess_vars->value);
758 for(std::map<std::string, std::string>::iterator i = varmap.begin(); i != varmap.end(); i++) {
759 PHP_VAR_NODE *curr_var = array_get_by_str_key(&sess_vars->value, i->first);
760 PHP_VALUE_NODE val;
761 val.type = PHP_VAL_STRING;
762 val.str_val = const_cast<char *>(i->second.c_str());
763 value_value_assign(&curr_var->value, &val);
767 void save_session_vars(std::map<std::string, std::string> &varmap)
769 PHP_EXP_NODE *sess_vars_exp_node = get_var_node("_SESSION");
770 PHP_VAR_NODE *sess_vars = sess_vars_exp_node->var_si_node->var;
772 delete sess_vars_exp_node;
773 if ( sess_vars->value.type != PHP_VAL_ARRAY ) {
774 return;
777 for(int i = 0; i < array_get_size(&sess_vars->value); i++) {
778 std::string s = array_get_ith_key(&sess_vars->value, i);
779 PHP_VAR_NODE *var = array_get_by_str_key(&sess_vars->value, s);
780 cast_value_str(&var->value);
781 varmap[s] = var->value.str_val;
784 // File_checked_for_headers