1 /* see copyright notice in squirrel.h */
3 #include <sqstdstring.h>
6 #define scstrchr strchr
8 #define scstrtok strtok
9 #define MAX_FORMAT_LEN 20
10 #define MAX_WFORMAT_LEN 3
11 #define ADDITIONAL_FORMAT_SPACE (100*sizeof(SQChar))
13 static SQInteger
validate_format(HSQUIRRELVM v
, SQChar
*fmt
, const SQChar
*src
, SQInteger n
,SQInteger
&width
)
15 SQChar swidth
[MAX_WFORMAT_LEN
];
19 while (scstrchr("-+ #0", src
[n
])) n
++;
20 while (isdigit(src
[n
])) {
24 if(wc
>=MAX_WFORMAT_LEN
)
25 return sq_throwerror(v
,"width format too long");
37 while (isdigit(src
[n
])) {
41 if(wc
>=MAX_WFORMAT_LEN
)
42 return sq_throwerror(v
,"precision format too long");
46 width
+= atoi(swidth
);
49 if (n
-start
> MAX_FORMAT_LEN
)
50 return sq_throwerror(v
,"format too long");
51 memcpy(&fmt
[1],&src
[start
],((n
-start
)+1)*sizeof(SQChar
));
52 fmt
[(n
-start
)+2] = '\0';
57 * Little hack to remove the "format not a string literal, argument types not checked" warning.
58 * This check has been added to OpenTTD to make sure that nobody passes wrong string literals,
59 * but three lines in Squirrel have a little problem with those. Therefor we use this hack
60 * which basically uses vsnprintf instead of sprintf as vsnprintf is not testing for the right
61 * string literal at compile time.
63 static void _append_string(SQInteger
&i
, SQChar
*dest
, SQInteger allocated
, const SQChar
*fmt
, ...)
67 i
+= vsnprintf(&dest
[i
],allocated
-i
,fmt
,va
);
72 SQRESULT
sqstd_format(HSQUIRRELVM v
,SQInteger nformatstringidx
,SQInteger
*outlen
,SQChar
**output
)
76 SQChar fmt
[MAX_FORMAT_LEN
];
77 sq_getstring(v
,nformatstringidx
,&format
);
78 SQInteger allocated
= (sq_getsize(v
,nformatstringidx
)+2)*sizeof(SQChar
);
79 dest
= sq_getscratchpad(v
,allocated
);
80 SQInteger n
= 0,i
= 0, nparam
= nformatstringidx
+1, w
= 0;
81 while(format
[n
] != '\0') {
82 if(format
[n
] != '%') {
83 assert(i
< allocated
);
84 dest
[i
++] = format
[n
];
87 else if(format
[n
+1] == '%') { //handles %%
93 if( nparam
> sq_gettop(v
) )
94 return sq_throwerror(v
,"not enough paramters for the given format string");
95 n
= validate_format(v
,fmt
,format
,n
,w
);
98 SQInteger valtype
= 0;
104 if(SQ_FAILED(sq_getstring(v
,nparam
,&ts
)))
105 return sq_throwerror(v
,"string expected for the specified format");
106 addlen
= (sq_getsize(v
,nparam
)*sizeof(SQChar
))+((w
+1)*sizeof(SQChar
));
109 case 'i': case 'd': case 'c':case 'o': case 'u': case 'x': case 'X':
110 if(SQ_FAILED(sq_getinteger(v
,nparam
,&ti
)))
111 return sq_throwerror(v
,"integer expected for the specified format");
112 addlen
= (ADDITIONAL_FORMAT_SPACE
)+((w
+1)*sizeof(SQChar
));
115 case 'f': case 'g': case 'G': case 'e': case 'E':
116 if(SQ_FAILED(sq_getfloat(v
,nparam
,&tf
)))
117 return sq_throwerror(v
,"float expected for the specified format");
118 addlen
= (ADDITIONAL_FORMAT_SPACE
)+((w
+1)*sizeof(SQChar
));
122 return sq_throwerror(v
,"invalid format");
125 allocated
+= addlen
+ sizeof(SQChar
);
126 dest
= sq_getscratchpad(v
,allocated
);
128 case 's': _append_string(i
,dest
,allocated
,fmt
,ts
); break;
129 case 'i': _append_string(i
,dest
,allocated
,fmt
,ti
); break;
130 case 'f': _append_string(i
,dest
,allocated
,fmt
,tf
); break;
141 static SQInteger
_string_format(HSQUIRRELVM v
)
144 SQInteger length
= 0;
145 if(SQ_FAILED(sqstd_format(v
,2,&length
,&dest
)))
147 sq_pushstring(v
,dest
,length
);
151 static void __strip_l(const SQChar
*str
,const SQChar
**start
)
153 const SQChar
*t
= str
;
154 while(((*t
) != '\0') && isspace(*t
)){ t
++; }
158 static void __strip_r(const SQChar
*str
,SQInteger len
,const SQChar
**end
)
164 const SQChar
*t
= &str
[len
-1];
165 while(t
!= str
&& isspace(*t
)) { t
--; }
169 static SQInteger
_string_strip(HSQUIRRELVM v
)
171 const SQChar
*str
,*start
,*end
;
172 sq_getstring(v
,2,&str
);
173 SQInteger len
= sq_getsize(v
,2);
174 __strip_l(str
,&start
);
175 __strip_r(str
,len
,&end
);
176 sq_pushstring(v
,start
,end
- start
);
180 static SQInteger
_string_lstrip(HSQUIRRELVM v
)
182 const SQChar
*str
,*start
;
183 sq_getstring(v
,2,&str
);
184 __strip_l(str
,&start
);
185 sq_pushstring(v
,start
,-1);
189 static SQInteger
_string_rstrip(HSQUIRRELVM v
)
191 const SQChar
*str
,*end
;
192 sq_getstring(v
,2,&str
);
193 SQInteger len
= sq_getsize(v
,2);
194 __strip_r(str
,len
,&end
);
195 sq_pushstring(v
,str
,end
- str
);
199 static SQInteger
_string_split(HSQUIRRELVM v
)
201 const SQChar
*str
,*seps
;
203 sq_getstring(v
,2,&str
);
204 sq_getstring(v
,3,&seps
);
205 if(sq_getsize(v
,3) == 0) return sq_throwerror(v
,"empty separators string");
206 SQInteger memsize
= (sq_getsize(v
,2)+1)*sizeof(SQChar
);
207 stemp
= sq_getscratchpad(v
,memsize
);
208 memcpy(stemp
,str
,memsize
);
209 tok
= scstrtok(stemp
,seps
);
211 while( tok
!= NULL
) {
212 sq_pushstring(v
,tok
,-1);
213 sq_arrayappend(v
,-2);
214 tok
= scstrtok( NULL
, seps
);
219 #define SETUP_REX(v) \
220 SQRex *self = NULL; \
221 sq_getinstanceup(v,1,(SQUserPointer *)&self,0);
223 static SQInteger
_rexobj_releasehook(SQUserPointer p
, SQInteger size
)
225 SQRex
*self
= ((SQRex
*)p
);
226 sqstd_rex_free(self
);
230 static SQInteger
_regexp_match(HSQUIRRELVM v
)
234 sq_getstring(v
,2,&str
);
235 if(sqstd_rex_match(self
,str
) == SQTrue
)
237 sq_pushbool(v
,SQTrue
);
240 sq_pushbool(v
,SQFalse
);
244 static void _addrexmatch(HSQUIRRELVM v
,const SQChar
*str
,const SQChar
*begin
,const SQChar
*end
)
247 sq_pushstring(v
,"begin",-1);
248 sq_pushinteger(v
,begin
- str
);
250 sq_pushstring(v
,"end",-1);
251 sq_pushinteger(v
,end
- str
);
255 static SQInteger
_regexp_search(HSQUIRRELVM v
)
258 const SQChar
*str
,*begin
,*end
;
260 sq_getstring(v
,2,&str
);
261 if(sq_gettop(v
) > 2) sq_getinteger(v
,3,&start
);
262 if(sqstd_rex_search(self
,str
+start
,&begin
,&end
) == SQTrue
) {
263 _addrexmatch(v
,str
,begin
,end
);
269 static SQInteger
_regexp_capture(HSQUIRRELVM v
)
272 const SQChar
*str
,*begin
,*end
;
274 sq_getstring(v
,2,&str
);
275 if(sq_gettop(v
) > 2) sq_getinteger(v
,3,&start
);
276 if(sqstd_rex_search(self
,str
+start
,&begin
,&end
) == SQTrue
) {
277 SQInteger n
= sqstd_rex_getsubexpcount(self
);
280 for(SQInteger i
= 0;i
< n
; i
++) {
281 sqstd_rex_getsubexp(self
,i
,&match
);
283 _addrexmatch(v
,str
,match
.begin
,match
.begin
+match
.len
);
285 _addrexmatch(v
,str
,str
,str
); //empty match
286 sq_arrayappend(v
,-2);
293 static SQInteger
_regexp_subexpcount(HSQUIRRELVM v
)
296 sq_pushinteger(v
,sqstd_rex_getsubexpcount(self
));
300 static SQInteger
_regexp_constructor(HSQUIRRELVM v
)
302 const SQChar
*error
,*pattern
;
303 sq_getstring(v
,2,&pattern
);
304 SQRex
*rex
= sqstd_rex_compile(pattern
,&error
);
305 if(!rex
) return sq_throwerror(v
,error
);
306 sq_setinstanceup(v
,1,rex
);
307 sq_setreleasehook(v
,1,_rexobj_releasehook
);
311 static SQInteger
_regexp__typeof(HSQUIRRELVM v
)
313 sq_pushstring(v
,"regexp",-1);
317 #define _DECL_REX_FUNC(name,nparams,pmask) {#name,_regexp_##name,nparams,pmask}
318 static SQRegFunction rexobj_funcs
[]={
319 _DECL_REX_FUNC(constructor
,2,".s"),
320 _DECL_REX_FUNC(search
,-2,"xsn"),
321 _DECL_REX_FUNC(match
,2,"xs"),
322 _DECL_REX_FUNC(capture
,-2,"xsn"),
323 _DECL_REX_FUNC(subexpcount
,1,"x"),
324 _DECL_REX_FUNC(_typeof
,1,"x"),
328 #define _DECL_FUNC(name,nparams,pmask) {#name,_string_##name,nparams,pmask}
329 static SQRegFunction stringlib_funcs
[]={
330 _DECL_FUNC(format
,-2,".s"),
331 _DECL_FUNC(strip
,2,".s"),
332 _DECL_FUNC(lstrip
,2,".s"),
333 _DECL_FUNC(rstrip
,2,".s"),
334 _DECL_FUNC(split
,3,".ss"),
339 SQInteger
sqstd_register_stringlib(HSQUIRRELVM v
)
341 sq_pushstring(v
,"regexp",-1);
342 sq_newclass(v
,SQFalse
);
344 while(rexobj_funcs
[i
].name
!= 0) {
345 SQRegFunction
&f
= rexobj_funcs
[i
];
346 sq_pushstring(v
,f
.name
,-1);
347 sq_newclosure(v
,f
.f
,0);
348 sq_setparamscheck(v
,f
.nparamscheck
,f
.typemask
);
349 sq_setnativeclosurename(v
,-1,f
.name
);
356 while(stringlib_funcs
[i
].name
!=0)
358 sq_pushstring(v
,stringlib_funcs
[i
].name
,-1);
359 sq_newclosure(v
,stringlib_funcs
[i
].f
,0);
360 sq_setparamscheck(v
,stringlib_funcs
[i
].nparamscheck
,stringlib_funcs
[i
].typemask
);
361 sq_setnativeclosurename(v
,-1,stringlib_funcs
[i
].name
);