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