728376bf3c380fa8b27707dcc28ad15014836eaa
[supertux.git] / src / squirrel / sqstdlib / sqstdstring.cpp
1 /* see copyright notice in squirrel.h */\r
2 #include <squirrel.h>\r
3 #include <sqstdstring.h>\r
4 #include <string.h>\r
5 #include <stdlib.h>\r
6 #include <stdio.h>\r
7 #include <ctype.h>\r
8 \r
9 #ifdef _UNICODE\r
10 #define scstrchr wcschr\r
11 #define scsnprintf wsnprintf\r
12 #define scatoi _wtoi\r
13 #else\r
14 #define scstrchr strchr\r
15 #define scsnprintf snprintf\r
16 #define scatoi atoi\r
17 #endif\r
18 #define MAX_FORMAT_LEN  20\r
19 #define MAX_WFORMAT_LEN 3\r
20 #define ADDITIONAL_FORMAT_SPACE (100*sizeof(SQChar))\r
21 \r
22 static int validate_format(HSQUIRRELVM v, SQChar *fmt, const SQChar *src, int n,int &width)\r
23 {\r
24         SQChar swidth[MAX_WFORMAT_LEN];\r
25         int wc = 0;\r
26         int start = n;\r
27         fmt[0] = '%';\r
28         while (scstrchr(_SC("-+ #0"), src[n])) n++;\r
29         while (scisdigit(src[n])) {\r
30                 swidth[wc] = src[n];\r
31                 n++;\r
32                 wc++;\r
33                 if(wc>=MAX_WFORMAT_LEN)\r
34                         return sq_throwerror(v,_SC("width format too long"));\r
35         }\r
36         swidth[wc] = '\0';\r
37         if(wc > 0) {\r
38                 width = scatoi(swidth);\r
39         }\r
40         else\r
41                 width = 0;\r
42         if (src[n] == '.') {\r
43             n++;\r
44         \r
45                 wc = 0;\r
46                 while (scisdigit(src[n])) {\r
47                         swidth[wc] = src[n];\r
48                         n++;\r
49                         wc++;\r
50                         if(wc>=MAX_WFORMAT_LEN)\r
51                                 return sq_throwerror(v,_SC("precision format too long"));\r
52                 }\r
53                 swidth[wc] = '\0';\r
54                 if(wc > 0) {\r
55                         width += scatoi(swidth);\r
56                 }\r
57         }\r
58         if (n-start > MAX_FORMAT_LEN )\r
59                 return sq_throwerror(v,_SC("format too long"));\r
60         memcpy(&fmt[1],&src[start],((n-start)+1)*sizeof(SQChar));\r
61         fmt[(n-start)+2] = '\0';\r
62         return n;\r
63 }\r
64 \r
65 static int _string_format(HSQUIRRELVM v)\r
66 {\r
67         const SQChar *format;\r
68         SQChar *dest;\r
69         SQChar fmt[MAX_FORMAT_LEN];\r
70         sq_getstring(v,2,&format);\r
71         int allocated = (sq_getsize(v,2)+1)*sizeof(SQChar);\r
72         dest = sq_getscratchpad(v,allocated);\r
73         int n = 0,i = 0, nparam = 3, w;\r
74         while(format[n] != '\0') {\r
75                 if(format[n] != '%') {\r
76                         dest[i++] = format[n];\r
77                         n++;\r
78                 }\r
79                 else if(format[++n] == '%') {\r
80                         dest[i++] = '%';\r
81                 }\r
82                 else {\r
83                         if( nparam > sq_gettop(v) )\r
84                                 return sq_throwerror(v,_SC("not enough paramters for the given format string"));\r
85                         n = validate_format(v,fmt,format,n,w);\r
86                         if(n < 0) return -1;\r
87                         int addlen = 0;\r
88                         int valtype = 0;\r
89                         const SQChar *ts;\r
90                         SQInteger ti;\r
91                         SQFloat tf;\r
92                         switch(format[n]) {\r
93                         case 's':\r
94                                 if(SQ_FAILED(sq_getstring(v,nparam,&ts))) \r
95                                         return sq_throwerror(v,_SC("string expected for the specified format"));\r
96                                 addlen = (sq_getsize(v,nparam)*sizeof(SQChar))+((w+1)*sizeof(SQChar));\r
97                                 valtype = 's';\r
98                                 break;\r
99                         case 'i': case 'd': case 'c':case 'o':  case 'u':  case 'x':  case 'X':\r
100                                 if(SQ_FAILED(sq_getinteger(v,nparam,&ti))) \r
101                                         return sq_throwerror(v,_SC("integer expected for the specified format"));\r
102                                 addlen = (ADDITIONAL_FORMAT_SPACE)+((w+1)*sizeof(SQChar));\r
103                                 valtype = 'i';\r
104                                 break;\r
105                         case 'f': case 'g': case 'G': case 'e':  case 'E':\r
106                                 if(SQ_FAILED(sq_getfloat(v,nparam,&tf))) \r
107                                         return sq_throwerror(v,_SC("float expected for the specified format"));\r
108                                 addlen = (ADDITIONAL_FORMAT_SPACE)+((w+1)*sizeof(SQChar));\r
109                                 valtype = 'f';\r
110                                 break;\r
111                         default:\r
112                                 return sq_throwerror(v,_SC("invalid format"));\r
113                         }\r
114                         n++;\r
115                         if((allocated-i) < addlen)\r
116                                 allocated += addlen - (allocated-i);\r
117                         dest = sq_getscratchpad(v,allocated);\r
118                         switch(valtype) {\r
119                         case 's': i += scsprintf(&dest[i],fmt,ts); break;\r
120                         case 'i': i += scsprintf(&dest[i],fmt,ti); break;\r
121                         case 'f': i += scsprintf(&dest[i],fmt,tf); break;\r
122                         };\r
123                         nparam ++;\r
124                 }\r
125         }\r
126         sq_pushstring(v,dest,i);\r
127         return 1;\r
128 }\r
129 \r
130 #define SETUP_REX(v) \\r
131         SQRex *self = NULL; \\r
132         sq_getinstanceup(v,1,(SQUserPointer *)&self,0); \r
133 \r
134 static int _rexobj_releasehook(SQUserPointer p, int size)\r
135 {\r
136         SQRex *self = ((SQRex *)p);\r
137         sqstd_rex_free(self);\r
138         return 1;\r
139 }\r
140 \r
141 static int _regexp_match(HSQUIRRELVM v)\r
142 {\r
143         SETUP_REX(v);\r
144         const SQChar *str;\r
145         sq_getstring(v,2,&str);\r
146         if(sqstd_rex_match(self,str) == SQTrue)\r
147         {\r
148                 sq_pushinteger(v,1);\r
149                 return 1;\r
150         }\r
151         return 0;\r
152 }\r
153 \r
154 static void _addrexmatch(HSQUIRRELVM v,const SQChar *str,const SQChar *begin,const SQChar *end)\r
155 {\r
156         sq_newtable(v);\r
157         sq_pushstring(v,_SC("begin"),-1);\r
158         sq_pushinteger(v,begin - str);\r
159         sq_rawset(v,-3);\r
160         sq_pushstring(v,_SC("end"),-1);\r
161         sq_pushinteger(v,end - str);\r
162         sq_rawset(v,-3);\r
163 }\r
164 \r
165 static int _regexp_search(HSQUIRRELVM v)\r
166 {\r
167         SETUP_REX(v);\r
168         const SQChar *str,*begin,*end;\r
169         SQInteger start = 0;\r
170         sq_getstring(v,2,&str);\r
171         if(sq_gettop(v) > 2) sq_getinteger(v,3,&start);\r
172         if(sqstd_rex_search(self,str+start,&begin,&end) == SQTrue) {\r
173                 _addrexmatch(v,str,begin,end);\r
174                 return 1;\r
175         }\r
176         return 0;\r
177 }\r
178 \r
179 static int _regexp_capture(HSQUIRRELVM v)\r
180 {\r
181         SETUP_REX(v);\r
182         const SQChar *str,*begin,*end;\r
183         SQInteger start = 0;\r
184         sq_getstring(v,2,&str);\r
185         if(sq_gettop(v) > 2) sq_getinteger(v,3,&start);\r
186         if(sqstd_rex_search(self,str+start,&begin,&end) == SQTrue) {\r
187                 SQInteger n = sqstd_rex_getsubexpcount(self);\r
188                 SQRexMatch match;\r
189                 sq_newarray(v,0);\r
190                 for(SQInteger i = 0;i < n; i++) {\r
191                         sqstd_rex_getsubexp(self,i,&match);\r
192                         if(match.len > 0)\r
193                                 _addrexmatch(v,str,match.begin,match.begin+match.len);\r
194                         else\r
195                                 _addrexmatch(v,str,str,str); //empty match\r
196                         sq_arrayappend(v,-2);\r
197                 }\r
198                 return 1;\r
199         }\r
200         return 0;\r
201 }\r
202 \r
203 static int _regexp_subexpcount(HSQUIRRELVM v)\r
204 {\r
205         SETUP_REX(v);\r
206         sq_pushinteger(v,sqstd_rex_getsubexpcount(self));\r
207         return 1;\r
208 }\r
209 \r
210 static int _regexp_constructor(HSQUIRRELVM v)\r
211 {\r
212         const SQChar *error,*pattern;\r
213         sq_getstring(v,2,&pattern);\r
214         SQRex *rex = sqstd_rex_compile(pattern,&error);\r
215         if(!rex) return sq_throwerror(v,error);\r
216         sq_setinstanceup(v,1,rex);\r
217         sq_setreleasehook(v,1,_rexobj_releasehook);\r
218         return 0;\r
219 }\r
220 \r
221 static int _regexp__typeof(HSQUIRRELVM v)\r
222 {\r
223         sq_pushstring(v,_SC("regexp"),-1);\r
224         return 1;\r
225 }\r
226 \r
227 #define _DECL_REX_FUNC(name,nparams,pmask) {_SC(#name),_regexp_##name,nparams,pmask}\r
228 static SQRegFunction rexobj_funcs[]={\r
229         _DECL_REX_FUNC(constructor,2,_SC(".s")),\r
230         _DECL_REX_FUNC(search,-2,_SC("xsn")),\r
231         _DECL_REX_FUNC(match,2,_SC("xs")),\r
232         _DECL_REX_FUNC(capture,-2,_SC("xsn")),\r
233         _DECL_REX_FUNC(subexpcount,1,_SC("x")),\r
234         _DECL_REX_FUNC(_typeof,1,_SC("x")),\r
235         {0,0}\r
236 };\r
237 \r
238 #define _DECL_FUNC(name,nparams,pmask) {_SC(#name),_string_##name,nparams,pmask}\r
239 static SQRegFunction stringlib_funcs[]={\r
240         _DECL_FUNC(format,-2,_SC(".s")),\r
241         {0,0}\r
242 };\r
243 \r
244 \r
245 int sqstd_register_stringlib(HSQUIRRELVM v)\r
246 {\r
247         sq_pushstring(v,_SC("regexp"),-1);\r
248         sq_newclass(v,SQFalse);\r
249         int i = 0;\r
250         while(rexobj_funcs[i].name != 0) {\r
251                 SQRegFunction &f = rexobj_funcs[i];\r
252                 sq_pushstring(v,f.name,-1);\r
253                 sq_newclosure(v,f.f,0);\r
254                 sq_setparamscheck(v,f.nparamscheck,f.typemask);\r
255                 sq_setnativeclosurename(v,-1,f.name);\r
256                 sq_createslot(v,-3);\r
257                 i++;\r
258         }\r
259         sq_createslot(v,-3);\r
260 \r
261         i = 0;\r
262         while(stringlib_funcs[i].name!=0)\r
263         {\r
264                 sq_pushstring(v,stringlib_funcs[i].name,-1);\r
265                 sq_newclosure(v,stringlib_funcs[i].f,0);\r
266                 sq_setparamscheck(v,stringlib_funcs[i].nparamscheck,stringlib_funcs[i].typemask);\r
267                 sq_setnativeclosurename(v,-1,stringlib_funcs[i].name);\r
268                 sq_createslot(v,-3);\r
269                 i++;\r
270         }\r
271         return 1;\r
272 }\r