1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "wxexpr.h"
16 // For compilers that support precompilation, includes "wx/wx.h".
17 #include "wx/wxprec.h"
39 #include "wx/wxexpr.h"
41 extern "C" void add_expr(char *);
42 extern "C" void LexFromFile(FILE *fd
);
43 extern "C" void LexFromString(char *buf
);
45 wxExprDatabase
*thewxExprDatabase
= NULL
;
46 wxExprErrorHandler currentwxExprErrorHandler
;
48 wxExpr::wxExpr(const wxString
& functor
)
55 wxExpr
*pfunctor
= new wxExpr(wxExprWord
, functor
);
60 wxExpr::wxExpr(wxExprType the_type
, const wxString
& word_or_string
)
67 value
.word
= copystring((const char *)word_or_string
);
70 value
.string
= copystring((const char *)word_or_string
);
85 wxExpr::wxExpr(wxExprType the_type
, char *word_or_string
, bool allocate
)
92 value
.word
= allocate
? copystring(word_or_string
) : word_or_string
;
95 value
.string
= allocate
? copystring(word_or_string
) : word_or_string
;
110 wxExpr::wxExpr(long the_integer
)
112 type
= wxExprInteger
;
113 value
.integer
= the_integer
;
118 wxExpr::wxExpr(double the_real
)
121 value
.real
= the_real
;
126 wxExpr::wxExpr(wxList
*the_list
)
133 wxExpr
*listExpr
= new wxExpr(wxExprList
);
135 wxNode
*node
= the_list
->First();
138 wxExpr
*expr
= (wxExpr
*)node
->Data();
139 listExpr
->Append(expr
);
147 wxExpr::~wxExpr(void)
158 delete[] value
.string
;
168 wxExpr
*expr
= value
.first
;
171 wxExpr
*expr1
= expr
->next
;
178 case wxExprNull
: break;
182 void wxExpr::Append(wxExpr
*expr
)
192 void wxExpr::Insert(wxExpr
*expr
)
194 expr
->next
= value
.first
;
201 wxExpr
*wxExpr::Copy(void) const
203 // This seems to get round an optimizer bug when
204 // using Watcom C++ 10a in WIN32 compilation mode.
205 // If these lines not present, the type seems to be
206 // interpreted wrongly as an integer.
207 // I don't want to turn optimization off since it's needed
208 // for reading in files quickly.
209 #if defined(__WATCOMC__)
217 return new wxExpr(value
.integer
);
219 return new wxExpr(value
.real
);
221 return new wxExpr(wxExprString
, wxString(value
.string
));
223 return new wxExpr(wxExprWord
, wxString(value
.word
));
226 wxExpr
*expr
= value
.first
;
227 wxExpr
*new_list
= new wxExpr(wxExprList
);
230 wxExpr
*expr2
= expr
->Copy();
231 new_list
->Append(expr2
);
243 // Get the wxExpr (containing (= wxExpr Value) form) for the given word
244 // or string, assuming that we have Attribute=Value, ...
245 wxExpr
*wxExpr::GetAttributeValueNode(const wxString
& word
) const // Use only for a clause or list
247 if (type
!= wxExprList
)
250 wxExpr
*expr
= value
.first
;
253 if (expr
->type
== wxExprList
)
255 wxExpr
*firstNode
= expr
->value
.first
;
256 if ((firstNode
->type
== wxExprWord
) && (firstNode
->value
.word
[0] == '='))
258 wxExpr
*secondNode
= firstNode
->next
;
259 if ((secondNode
->type
== wxExprWord
) &&
260 (strcmp((const char *)word
, secondNode
->value
.word
) == 0))
271 // Get the value (in wxExpr form) for the given word or string, assuming
272 // that we have Attribute=Value, ...
273 wxExpr
*wxExpr::AttributeValue(const wxString
& word
) const // Use only for a clause or list
275 if (type
!= wxExprList
)
278 wxExpr
*attExpr
= GetAttributeValueNode(word
);
279 if (attExpr
&& attExpr
->value
.first
&& attExpr
->value
.first
->next
)
280 return attExpr
->value
.first
->next
->next
;
284 wxString
wxExpr::Functor(void) const // Use only for a clause
286 if ((type
!= wxExprList
) || !value
.first
)
289 if (value
.first
->type
== wxExprWord
)
290 return wxString(value
.first
->value
.word
);
295 bool wxExpr::IsFunctor(const wxString
& f
) const // Use only for a clause
297 if ((type
!= wxExprList
) || !value
.first
)
300 return (value
.first
->type
== wxExprWord
&&
301 (strcmp((const char *)f
, value
.first
->value
.word
) == 0));
304 // Return nth argument of a clause (starting from 1)
305 wxExpr
*wxExpr::Arg(wxExprType theType
, int arg
) const
307 wxExpr
*expr
= value
.first
;
309 for (i
= 1; i
< arg
; i
++)
313 if (expr
&& (expr
->type
== theType
))
319 // Return nth argument of a list expression (starting from zero)
320 wxExpr
*wxExpr::Nth(int arg
) const
322 if (type
!= wxExprList
)
325 wxExpr
*expr
= value
.first
;
327 for (i
= 0; i
< arg
; i
++)
338 // Returns the number of elements in a list expression
339 int wxExpr::Number(void) const
341 if (type
!= wxExprList
)
345 wxExpr
*expr
= value
.first
;
354 void wxExpr::DeleteAttributeValue(const wxString
& attribute
)
356 if (type
!= wxExprList
)
359 wxExpr
*expr
= value
.first
;
360 wxExpr
*lastExpr
= this;
363 if (expr
->type
== wxExprList
)
365 wxExpr
*firstNode
= expr
->value
.first
;
366 if ((firstNode
->type
== wxExprWord
) && (firstNode
->value
.word
[0] == '='))
368 wxExpr
*secondNode
= firstNode
->next
;
369 if ((secondNode
->type
== wxExprWord
) &&
370 (strcmp((const char *)attribute
, secondNode
->value
.word
) == 0))
372 wxExpr
*nextExpr
= expr
->next
;
375 lastExpr
->next
= nextExpr
;
390 void wxExpr::AddAttributeValue(const wxString
& attribute
, wxExpr
*val
)
392 if (type
!= wxExprList
)
394 // cout << "Error! tried to add an attribute-value pair to a nonlist wxExpr expression\n";
397 // Warning - existing code may assume that any existing value
398 // is deleted first. For efficiency, we leave this to the application.
399 // DeleteAttributeValue(attribute);
401 wxExpr
*patt
= new wxExpr(wxExprWord
, attribute
);
402 wxExpr
*pequals
= new wxExpr(wxExprWord
, "=");
404 wxExpr
*listExpr
= new wxExpr(wxExprList
);
406 listExpr
->Append(pequals
);
407 listExpr
->Append(patt
);
408 listExpr
->Append(val
);
413 void wxExpr::AddAttributeValue(const wxString
& attribute
, long val
)
415 if (type
!= wxExprList
)
417 // cout << "Error! tried to add an attribute-value pair to a nonlist wxExpr expression\n";
420 // Warning - existing code may assume that any existing value
421 // is deleted first. For efficiency, we leave this to the application.
422 // DeleteAttributeValue(attribute);
424 wxExpr
*patt
= new wxExpr(wxExprWord
, attribute
);
425 wxExpr
*pval
= new wxExpr(val
);
426 wxExpr
*pequals
= new wxExpr(wxExprWord
, "=");
428 wxExpr
*listExpr
= new wxExpr(wxExprList
);
430 listExpr
->Append(pequals
);
431 listExpr
->Append(patt
);
432 listExpr
->Append(pval
);
437 void wxExpr::AddAttributeValue(const wxString
& attribute
, double val
)
439 if (type
!= wxExprList
)
441 // cout << "Error! tried to add an attribute-value pair to a nonlist wxExpr expression\n";
445 // DeleteAttributeValue(attribute);
446 wxExpr
*patt
= new wxExpr(wxExprWord
, attribute
);
447 wxExpr
*pval
= new wxExpr(val
);
448 wxExpr
*pequals
= new wxExpr(wxExprWord
, "=");
450 wxExpr
*listExpr
= new wxExpr(wxExprList
);
452 listExpr
->Append(pequals
);
453 listExpr
->Append(patt
);
454 listExpr
->Append(pval
);
459 void wxExpr::AddAttributeValueString(const wxString
& attribute
, const wxString
& val
)
461 if (type
!= wxExprList
)
463 // cout << "Error! tried to add an attribute-value pair to a nonlist wxExpr expression\n";
467 // DeleteAttributeValue(attribute);
469 wxExpr
*patt
= new wxExpr(wxExprWord
, attribute
);
470 wxExpr
*pval
= new wxExpr(wxExprString
, val
);
471 wxExpr
*pequals
= new wxExpr(wxExprWord
, "=");
473 wxExpr
*listExpr
= new wxExpr(wxExprList
);
475 listExpr
->Append(pequals
);
476 listExpr
->Append(patt
);
477 listExpr
->Append(pval
);
482 void wxExpr::AddAttributeValueWord(const wxString
& attribute
, const wxString
& val
)
484 if (type
!= wxExprList
)
486 // cout << "Error! tried to add an attribute-value pair to a nonlist wxExpr expression\n";
490 // DeleteAttributeValue(attribute);
492 wxExpr
*patt
= new wxExpr(wxExprWord
, attribute
);
493 wxExpr
*pval
= new wxExpr(wxExprWord
, val
);
494 wxExpr
*pequals
= new wxExpr(wxExprWord
, "=");
496 wxExpr
*listExpr
= new wxExpr(wxExprList
);
498 listExpr
->Append(pequals
);
499 listExpr
->Append(patt
);
500 listExpr
->Append(pval
);
505 void wxExpr::AddAttributeValue(const wxString
& attribute
, wxList
*val
)
507 if (type
!= wxExprList
)
509 // cout << "Error! tried to add an attribute-value pair to a nonlist wxExpr expression\n";
515 // DeleteAttributeValue(attribute);
517 wxExpr
*patt
= new wxExpr(wxExprWord
, attribute
);
518 wxExpr
*pval
= new wxExpr(val
);
519 wxExpr
*pequals
= new wxExpr(wxExprWord
, "=");
521 wxExpr
*listExpr
= new wxExpr(wxExprList
);
523 listExpr
->Append(pequals
);
524 listExpr
->Append(patt
);
525 listExpr
->Append(pval
);
530 void wxExpr::AddAttributeValueStringList(const wxString
& attribute
, wxList
*string_list
)
532 if (type
!= wxExprList
)
534 // cout << "Error! tried to add an attribute-value pair to a nonlist wxExpr expression\n";
540 // DeleteAttributeValue(attribute);
542 // First make a list of wxExpr strings
543 wxExpr
*listExpr
= new wxExpr(wxExprList
);
544 wxNode
*node
= string_list
->First();
547 char *string
= (char *)node
->Data();
548 wxExpr
*expr
= new wxExpr(wxExprString
, wxString(string
));
549 listExpr
->Append(expr
);
553 // Now make an (=, Att, Value) triple
554 wxExpr
*patt
= new wxExpr(wxExprWord
, attribute
);
555 wxExpr
*pequals
= new wxExpr(wxExprWord
, "=");
557 wxExpr
*listExpr2
= new wxExpr(wxExprList
);
559 listExpr2
->Append(pequals
);
560 listExpr2
->Append(patt
);
561 listExpr2
->Append(listExpr
);
566 bool wxExpr::GetAttributeValue(const wxString
& att
, int& var
) const
568 wxExpr
*expr
= AttributeValue(att
);
570 if (expr
&& (expr
->Type() == wxExprInteger
|| expr
->Type() == wxExprReal
))
572 var
= (int)(expr
->IntegerValue());
579 bool wxExpr::GetAttributeValue(const wxString
& att
, long& var
) const
581 wxExpr
*expr
= AttributeValue(att
);
583 if (expr
&& (expr
->Type() == wxExprInteger
|| expr
->Type() == wxExprReal
))
585 var
= expr
->IntegerValue();
592 bool wxExpr::GetAttributeValue(const wxString
& att
, float& var
) const
594 wxExpr
*expr
= AttributeValue(att
);
595 if (expr
&& (expr
->Type() == wxExprInteger
|| expr
->Type() == wxExprReal
))
597 var
= (float) expr
->RealValue();
604 bool wxExpr::GetAttributeValue(const wxString
& att
, double& var
) const
606 wxExpr
*expr
= AttributeValue(att
);
607 if (expr
&& (expr
->Type() == wxExprInteger
|| expr
->Type() == wxExprReal
))
609 var
= expr
->RealValue();
616 bool wxExpr::GetAttributeValue(const wxString
& att
, wxString
& var
) const // Word OR string -> string
618 wxExpr
*expr
= AttributeValue(att
);
619 if (expr
&& expr
->Type() == wxExprWord
)
621 var
= expr
->WordValue();
624 else if (expr
&& expr
->Type() == wxExprString
)
626 var
= expr
->StringValue();
633 bool wxExpr::GetAttributeValue(const wxString
& att
, wxExpr
**var
) const
635 wxExpr
*expr
= AttributeValue(att
);
645 bool wxExpr::GetAttributeValueStringList(const wxString
& att
, wxList
*var
) const
647 wxExpr
*expr
= AttributeValue(att
);
648 if (expr
&& expr
->Type() == wxExprList
)
650 wxExpr
*string_expr
= expr
->value
.first
;
653 if (string_expr
->Type() == wxExprString
)
654 var
->Append((wxObject
*)copystring(string_expr
->StringValue()));
656 string_expr
= string_expr
->next
;
665 void wxExpr::AssignAttributeValue(char *att
, char **var
) const
668 if (GetAttributeValue(att
, str
))
672 *var
= copystring((const char *) str
);
676 void wxExpr::WriteClause(ostream
& stream
) // Write this expression as a top-level clause
678 if (type
!= wxExprList
)
681 wxExpr
*node
= value
.first
;
684 node
->WriteExpr(stream
);
692 node
->WriteExpr(stream
);
694 if (node
) stream
<< ",\n";
701 void wxExpr::WriteExpr(ostream
& stream
) // Write as any other subexpression
703 // This seems to get round an optimizer bug when
704 // using Watcom C++ 10a in WIN32 compilation mode.
705 // If these lines not present, the type seems to be
706 // interpreted wrongly as an integer.
707 // I don't want to turn optimization off since it's needed
708 // for reading in files quickly.
709 #if defined(__WATCOMC__)
718 stream
<< value
.integer
;
723 double f
= value
.real
;
724 /* Now the parser can cope with this.
725 // Prevent printing in 'e' notation. Any better way?
726 if (fabs(f) < 0.00001)
730 sprintf(buf
, "%.6g", f
);
738 int len
= strlen(value
.string
);
739 for (i
= 0; i
< len
; i
++)
741 char ch
= value
.string
[i
];
742 if (ch
== '"' || ch
== '\\')
752 bool quote_it
= FALSE
;
753 int len
= strlen(value
.word
);
754 if ((len
== 0) || (len
> 0 && (value
.word
[0] > 64 && value
.word
[0] < 91)))
759 for (i
= 0; i
< len
; i
++)
760 if ((!isalpha(value
.word
[i
])) && (!isdigit(value
.word
[i
])) &&
761 (value
.word
[i
] != '_'))
762 { quote_it
= TRUE
; i
= len
; }
768 stream
<< value
.word
;
781 wxExpr
*expr
= value
.first
;
783 if ((expr
->Type() == wxExprWord
) && (strcmp(expr
->WordValue(), "=") == 0))
785 wxExpr
*arg1
= expr
->next
;
786 wxExpr
*arg2
= arg1
->next
;
787 arg1
->WriteExpr(stream
);
789 arg2
->WriteExpr(stream
);
796 expr
->WriteExpr(stream
);
798 if (expr
) stream
<< ", ";
805 case wxExprNull
: break;
809 void wxExpr::WriteLispExpr(ostream
& stream
)
815 stream
<< value
.integer
;
820 stream
<< value
.real
;
825 stream
<< "\"" << value
.string
<< "\"";
830 stream
<< value
.word
;
835 wxExpr
*expr
= value
.first
;
840 expr
->WriteLispExpr(stream
);
842 if (expr
) stream
<< " ";
848 case wxExprNull
: break;
852 // wxExpr 'database' (list of expressions)
853 wxExprDatabase::wxExprDatabase(wxExprErrorHandler handler
)
857 currentwxExprErrorHandler
= handler
;
861 wxExprDatabase::wxExprDatabase(wxExprType type
, const wxString
& attribute
, int size
,
862 wxExprErrorHandler handler
)
865 attribute_to_hash
= attribute
;
866 if (type
== wxExprString
)
867 hash_table
= new wxHashTable(wxKEY_STRING
, size
);
868 else if (type
== wxExprInteger
)
869 hash_table
= new wxHashTable(wxKEY_INTEGER
, size
);
870 else hash_table
= NULL
;
872 currentwxExprErrorHandler
= handler
;
876 wxExprDatabase::~wxExprDatabase(void)
883 void wxExprDatabase::BeginFind(void) // Initialise a search
888 wxExpr
*wxExprDatabase::FindClause(long id
) // Find a term based on an integer id attribute
889 // e.g. node(id=23, type=rectangle, ....).
891 wxExpr
*found
= NULL
;
892 while (position
&& !found
)
894 wxExpr
*term
= (wxExpr
*)position
->Data();
896 if (term
->Type() == wxExprList
)
898 wxExpr
*value
= term
->AttributeValue("id");
899 if (value
->Type() == wxExprInteger
&& value
->IntegerValue() == id
)
902 position
= position
->Next();
907 // Find on basis of attribute/value pairs, e.g. type=rectangle
908 wxExpr
*wxExprDatabase::FindClause(const wxString
& word
, const wxString
& val
)
910 wxExpr
*found
= NULL
;
911 while (position
&& !found
)
913 wxExpr
*term
= (wxExpr
*)position
->Data();
915 if (term
->Type() == wxExprList
)
917 wxExpr
*value
= term
->AttributeValue(word
);
918 if ((value
->Type() == wxExprWord
&& value
->WordValue() == val
) ||
919 (value
->Type() == wxExprString
&& value
->StringValue() == val
))
922 position
= position
->Next();
927 wxExpr
*wxExprDatabase::FindClause(const wxString
& word
, long val
)
929 wxExpr
*found
= NULL
;
930 while (position
&& !found
)
932 wxExpr
*term
= (wxExpr
*)position
->Data();
934 if (term
->Type() == wxExprList
)
936 wxExpr
*value
= term
->AttributeValue(word
);
937 if ((value
->Type() == wxExprInteger
) && (value
->IntegerValue() == val
))
940 position
= position
->Next();
945 wxExpr
*wxExprDatabase::FindClause(const wxString
& word
, double val
)
947 wxExpr
*found
= NULL
;
948 while (position
&& !found
)
950 wxExpr
*term
= (wxExpr
*)position
->Data();
952 if (term
->Type() == wxExprList
)
954 wxExpr
*value
= term
->AttributeValue(word
);
955 if ((value
->Type() == wxExprReal
) && (value
->RealValue() == val
))
958 position
= position
->Next();
963 wxExpr
*wxExprDatabase::FindClauseByFunctor(const wxString
& functor
)
965 wxExpr
*found
= NULL
;
966 while (position
&& !found
)
968 wxExpr
*term
= (wxExpr
*)position
->Data();
970 if (term
->Type() == wxExprList
)
972 if (term
->Functor() == functor
)
975 position
= position
->Next();
980 // If hashing is on, must store in hash table too
981 void wxExprDatabase::Append(wxExpr
*clause
)
983 wxList::Append((wxObject
*)clause
);
986 wxString
functor(clause
->Functor());
987 wxExpr
*expr
= clause
->AttributeValue(attribute_to_hash
);
990 long functor_key
= hash_table
->MakeKey((char *)(const char *)functor
);
992 if (expr
&& expr
->Type() == wxExprString
)
994 value_key
= hash_table
->MakeKey((char *)(const char *)expr
->StringValue());
995 hash_table
->Put(functor_key
+ value_key
, (char *)(const char *)expr
->StringValue(), (wxObject
*)clause
);
997 else if (expr
&& expr
->Type() == wxExprInteger
)
999 value_key
= expr
->IntegerValue();
1000 hash_table
->Put(functor_key
+ value_key
, expr
->IntegerValue(), (wxObject
*)clause
);
1007 wxExpr
*wxExprDatabase::HashFind(const wxString
& functor
, long value
) const
1009 long key
= hash_table
->MakeKey((char *)(const char *)functor
) + value
;
1011 // The key alone isn't guaranteed to be unique:
1012 // must supply value too. Let's assume the value of the
1013 // id is going to be reasonably unique.
1014 return (wxExpr
*)hash_table
->Get(key
, value
);
1017 wxExpr
*wxExprDatabase::HashFind(const wxString
& functor
, const wxString
& value
) const
1019 long key
= hash_table
->MakeKey((char *)(const char *)functor
) + hash_table
->MakeKey((char *)(const char *)value
);
1020 return (wxExpr
*)hash_table
->Get(key
, (char *)(const char *)value
);
1023 void wxExprDatabase::ClearDatabase(void)
1026 wxNode
*node
= First();
1029 wxExpr
*expr
= (wxExpr
*)node
->Data();
1036 hash_table
->Clear();
1039 bool wxExprDatabase::Read(const wxString
& filename
)
1043 FILE *f
= fopen((const char *)filename
, "r");
1046 thewxExprDatabase
= this;
1053 return (noErrors
== 0);
1061 bool wxExprDatabase::ReadFromString(const wxString
& buffer
)
1064 thewxExprDatabase
= this;
1066 LexFromString((char *)(const char *)buffer
);
1069 return (noErrors
== 0);
1072 bool wxExprDatabase::Write(const wxString
& fileName
)
1074 ofstream
str((char *)(const char *)fileName
);
1080 bool wxExprDatabase::Write(ostream
& stream
)
1083 wxNode
*node
= First();
1086 wxExpr
*expr
= (wxExpr
*)node
->Data();
1087 expr
->WriteClause(stream
);
1088 node
= node
->Next();
1090 return (noErrors
== 0);
1093 void wxExprDatabase::WriteLisp(ostream
& stream
)
1096 wxNode
*node
= First();
1099 wxExpr
*expr
= (wxExpr
*)node
->Data();
1100 expr
->WriteLispExpr(stream
);
1102 node
= node
->Next();
1106 void add_expr(wxExpr
* expr
)
1108 thewxExprDatabase
->Append(expr
);
1112 bool wxExprIsFunctor(wxExpr
*expr
, const wxString
& functor
)
1114 if (expr
&& (expr
->Type() == wxExprList
))
1116 wxExpr
*first_expr
= expr
->value
.first
;
1118 if (first_expr
&& (first_expr
->Type() == wxExprWord
) &&
1119 (first_expr
->WordValue() == functor
))
1129 * Called from parser
1133 char *make_integer(char *str
)
1135 wxExpr
*x
= new wxExpr(atol(str
));
1140 char *make_real(char *str1
, char *str2
)
1144 sprintf(buf
, "%s.%s", str1
, str2
);
1145 double f
= (double)atof(buf
);
1146 wxExpr
*x
= new wxExpr(f
);
1151 // extern "C" double exp10(double);
1153 char *make_exp(char *str1
, char *str2
)
1155 double mantissa
= (double)atoi(str1
);
1156 double exponent
= (double)atoi(str2
);
1158 double d
= mantissa
* pow(10.0, exponent
);
1160 wxExpr
*x
= new wxExpr(d
);
1165 char *make_exp2(char *str1
, char *str2
, char *str3
)
1169 sprintf(buf
, "%s.%s", str1
, str2
);
1170 double mantissa
= (double)atof(buf
);
1171 double exponent
= (double)atoi(str3
);
1173 double d
= mantissa
* pow(10.0, exponent
);
1175 wxExpr
*x
= new wxExpr(d
);
1180 char *make_word(char *str
)
1182 wxExpr
*x
= new wxExpr(wxExprWord
, str
);
1186 char *make_string(char *str
)
1191 str
++; /* skip leading quote */
1192 len
= strlen(str
) - 1; /* ignore trailing quote */
1194 s
= new char[len
+ 1];
1197 for(i
=0; i
<len
; i
++)
1199 if (str
[i
] == '\\' && str
[i
+1] == '"')
1204 else if (str
[i
] == '\\' && str
[i
+1] == '\\')
1215 wxExpr
*x
= new wxExpr(wxExprString
, s
, FALSE
);
1219 char *proio_cons(char * ccar
, char * ccdr
)
1221 wxExpr
*car
= (wxExpr
*)ccar
;
1222 wxExpr
*cdr
= (wxExpr
*)ccdr
;
1226 cdr
= new wxExpr(wxExprList
);
1233 void process_command(char * cexpr
)
1235 wxExpr
*expr
= (wxExpr
*)cexpr
;
1239 void syntax_error(char *WXUNUSED(s
))
1241 if (currentwxExprErrorHandler
)
1242 (void)(*(currentwxExprErrorHandler
))(WXEXPR_ERROR_SYNTAX
, "syntax error");
1243 if (thewxExprDatabase
) thewxExprDatabase
->noErrors
+= 1;
1248 // char *__cdecl strdup(const char *s)
1249 WXDLLEXPORT
char *strdup(const char *s
)
1251 int len
= strlen(s
);
1252 char *new_s
= (char *)malloc(sizeof(char)*(len
+1));