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