LMMS
Loading...
Searching...
No Matches
eel_strings.h
Go to the documentation of this file.
1#ifndef __EEL__STRINGS_H__
2#define __EEL__STRINGS_H__
3
4#include "ns-eel-int.h"
5#include "../wdlcstring.h"
6#include "../wdlstring.h"
7
8// required for context
9// #define EEL_STRING_GET_CONTEXT_POINTER(opaque) (((sInst *)opaque)->m_eel_string_state)
10
11
12/*
13 // writeable user-strings are 0..1023 (EEL_STRING_MAX_USER_STRINGS-1), and can be up to about EEL_STRING_MAXUSERSTRING_LENGTH_HINT bytes long
14
15 printf("string %d blah"); -- output to log, allows %d %u %f etc, if host implements formats [1]
16 sprintf(str,"string %d blah"); -- output to str [1]
17 strlen(str); -- returns string length
18 match("*test*", "this is a test") -- search for first parameter regex-style in second parameter
19 matchi("*test*", "this is a test") -- search for first parameter regex-style in second parameter (case insensitive)
20 // %s means 1 or more chars
21 // %0s means 0 or more chars
22 // %5s means exactly 5 chars
23 // %5-s means 5 or more chars
24 // %-10s means 1-10 chars
25 // %3-5s means 3-5 chars.
26 // %0-5s means 0-5 chars.
27 // %S (uppercase) indicates lazy match (%D, %F, %X, etc)
28
29 strcpy(str, srcstr); -- replaces str with srcstr
30 strcat(str, srcstr); -- appends srcstr to str
31 strcmp(str, str2) -- compares strings
32 stricmp(str, str2) -- compares strings (ignoring case)
33 strncmp(str, str2, maxlen) -- compares strings up to maxlen bytes
34 strnicmp(str, str2, maxlen) -- compares strings (ignoring case) up to maxlen bytes
35 strncpy(str, srcstr, maxlen); -- replaces str with srcstr, up to maxlen (-1 for unlimited)
36 strncat(str, srcstr, maxlen); -- appends up to maxlen of srcstr to str (-1 for unlimited)
37 strcpy_from(str,srcstr, offset); -- copies srcstr to str, but starts reading srcstr at offset offset
38 strcpy_substr(str, srcstr, offs, ml) -- php-style (start at offs, offs<0 means from end, ml for maxlen, ml<0 = reduce length by this amt)
39 str_getchar(str, offset[, type]); -- returns value at offset offset, type can be omitted or 0 or 'c', 's', 'S', 'i', 'I', 'f', 'F', 'd', 'D', 'uc', 'us', 'US', 'ui', 'UI'
40 -- negative offset is offset from end of string
41 str_setchar(str, offset, val[, type]); - sets value at offset offset, type optional. offset must be [0,length], if length it can lengthen string, if >length then call fails
42 -- negative offset is offset from end of string
43
44 str_setlen(str, len); -- sets length of string (if increasing, will be space-padded)
45 str_delsub(str, pos, len); -- deletes len chars at pos
46 str_insert(str, srcstr, pos); -- inserts srcstr at pos
47
48 [1]: note: printf/sprintf are NOT binary safe when using %s with modifiers (such as %100s etc) -- the source string being formatted
49 will terminate at the first NULL character
50 );
51
52
53
54 */
55
56// define this to allow modifying literal strings via code, i.e. foobar = strcat("foo","bar");
57// disabled by default, so literals can be pooled/reused/etc
58// #define EEL_STRINGS_MUTABLE_LITERALS
59
60#ifndef EEL_STRING_MAXUSERSTRING_LENGTH_HINT
61#define EEL_STRING_MAXUSERSTRING_LENGTH_HINT 16384
62#endif
63
64#ifndef EEL_STRING_MAX_USER_STRINGS
65// strings 0...x-1
66#define EEL_STRING_MAX_USER_STRINGS 1024
67#endif
68
69#ifndef EEL_STRING_LITERAL_BASE
70// strings defined by "xyz"
71#define EEL_STRING_LITERAL_BASE 10000
72#endif
73
74// base for named mutable strings (#xyz)
75#ifndef EEL_STRING_NAMED_BASE
76#define EEL_STRING_NAMED_BASE 90000
77#endif
78
79// base for unnamed mutable strings (#)
80#ifndef EEL_STRING_UNNAMED_BASE
81#define EEL_STRING_UNNAMED_BASE 190000
82#endif
83
84// define EEL_STRING_MUTEXLOCK_SCOPE for custom, otherwise EEL_STRING_WANT_MUTEX for builtin locking
85#ifndef EEL_STRING_MUTEXLOCK_SCOPE
86 #ifdef EEL_STRING_WANT_MUTEX
87 #include "../mutex.h"
88 #define EEL_STRING_MUTEXLOCK_SCOPE WDL_MutexLock __lock(&(EEL_STRING_GET_CONTEXT_POINTER(opaque)->m_mutex));
89 #else
90 #define EEL_STRING_MUTEXLOCK_SCOPE
91 #endif
92#endif
93
94// allow overriding behavior
95#ifndef EEL_STRING_GET_FOR_INDEX
96#define EEL_STRING_GET_FOR_INDEX(x, wr) (EEL_STRING_GET_CONTEXT_POINTER(opaque)->GetStringForIndex(x, wr, false))
97#endif
98
99#ifndef EEL_STRING_GET_FOR_WRITE
100#define EEL_STRING_GET_FOR_WRITE(x, wr) (EEL_STRING_GET_CONTEXT_POINTER(opaque)->GetStringForIndex(x, wr, true))
101#endif
102
103#ifndef EEL_STRING_GETFMTVAR
104#define EEL_STRING_GETFMTVAR(x) (EEL_STRING_GET_CONTEXT_POINTER(opaque)->GetVarForFormat(x))
105#endif
106
107#ifndef EEL_STRING_GETNAMEDVAR
108#define EEL_STRING_GETNAMEDVAR(x,createOK,altOut) (EEL_STRING_GET_CONTEXT_POINTER(opaque)->GetNamedVar(x,createOK,altOut))
109#endif
110
111
112
113
114
115#ifndef EEL_STRING_STORAGECLASS
116#define EEL_STRING_STORAGECLASS WDL_FastString
117#endif
118
119
120
122{
123 public:
124 static int cmpistr(const char **a, const char **b) { return stricmp(*a,*b); }
125
132 {
133 clear_state(true);
134 }
135
136 void clear_state(bool full)
137 {
138 if (full)
139 {
140 int x;
142 {
143 delete m_user_strings[x];
144 m_user_strings[x]=0;
145 }
146 m_named_strings_names.DeleteAll();
147 m_named_strings.Empty(true);
148 }
149 if (full) m_literal_strings.Empty(true);
150 m_varname_cache.DeleteAll();
151 m_unnamed_strings.Empty(true);
152 }
153
154 void update_named_vars(NSEEL_VMCTX vm) // call after compiling any code, or freeing code, etc
155 {
156 m_vm = vm;
157 m_varname_cache.DeleteAll();
158 if (vm) NSEEL_VM_enumallvars(vm,varEnumProc, this);
159 m_varname_cache.Resort();
160 }
161
162 EEL_F *GetVarForFormat(int formatidx)
163 {
164 return NULL; // must use %{xyz}s syntax -- override to change defaults
165 }
166
167 // if named variables are used, must call update_named_vars(vm) to set context/generate list
168 EEL_F *GetNamedVar(const char *s, bool createIfNotExists, EEL_F *altOut)
169 {
170 if (!s || !*s) return NULL;
171
172 if (s[0] == '#')
173 {
174 if (!s[1] || !altOut) return NULL;
175
176 int idx = m_named_strings_names.Get(s+1);
177 if (!idx && createIfNotExists)
178 {
179 idx = m_named_strings.GetSize() + EEL_STRING_NAMED_BASE;
181 m_named_strings_names.Insert(s+1,idx);
182 }
183 if (!idx) return NULL;
184
185 *altOut = (EEL_F) idx;
186 return altOut;
187 }
188
189 EEL_F *r = m_varname_cache.Get(s);
190 if (r || !createIfNotExists || !m_vm) return r;
191
192 const char *p=NULL;
194 if (r&&p) m_varname_cache.Insert(p,r);
195 return r;
196 }
197
198 const char *GetStringForIndex(EEL_F val, EEL_STRING_STORAGECLASS **stringContainerOut=NULL, bool is_for_write=false)
199 {
200 int idx = (int) (val+0.5);
201 if (idx>=0 && idx < EEL_STRING_MAX_USER_STRINGS)
202 {
203 if (stringContainerOut)
204 {
206 *stringContainerOut = m_user_strings[idx];
207 }
208 return m_user_strings[idx]?m_user_strings[idx]->Get():"";
209 }
212 if (!s) s= m_named_strings.Get(idx - EEL_STRING_NAMED_BASE);
213
214 if (s)
215 {
216 // mutable string
217 if (stringContainerOut) *stringContainerOut=s;
218 }
219 else
220 {
222 #ifdef EEL_STRINGS_MUTABLE_LITERALS
223 if (stringContainerOut) *stringContainerOut=s;
224 #else
225 if (stringContainerOut) *stringContainerOut=is_for_write ? NULL : s;
226 #endif
227 }
228 return s ? s->Get() : NULL;
229 }
230
231 WDL_PtrList<EEL_STRING_STORAGECLASS> m_literal_strings; // "this kind", normally immutable
233 WDL_PtrList<EEL_STRING_STORAGECLASS> m_named_strings; // #xyz by index, but stringkeyed below for names
235
237 WDL_AssocArray<const char *, EEL_F_PTR> m_varname_cache; // cached pointers when using %{xyz}s, %{#xyz}s bypasses
238
240#ifdef EEL_STRING_WANT_MUTEX
242#endif
243
244 static EEL_F addNamedStringCallback(void *opaque, const char *name)
245 {
246 if (!opaque) return -1.0;
248 if (!_this) return -1.0;
249#ifdef EEL_STRING_NAMEDSTRINGCALLBACK_HOOK
250 EEL_STRING_NAMEDSTRINGCALLBACK_HOOK
251#endif
252
254 if (!name || !name[0])
255 {
257 return (EEL_F) (_this->m_unnamed_strings.GetSize()-1 + EEL_STRING_UNNAMED_BASE);
258 }
259
260 int a = _this->m_named_strings_names.Get(name);
261 if (a) return (EEL_F)a;
262
266
267 return (EEL_F)a;
268 }
269
270 static EEL_F addStringCallback(void *opaque, struct eelStringSegmentRec *list)
271 {
272 if (!opaque) return -1.0;
273
275 if (!_this) return -1.0;
276
278 // could probably do a faster implementation using AddRaw() etc but this should also be OK
279 int sz=nseel_stringsegments_tobuf(NULL,0,list);
280 ns->SetLen(sz+32);
281 sz=nseel_stringsegments_tobuf((char *)ns->Get(),sz,list);
282 ns->SetLen(sz);
284 return (EEL_F)_this->AddString(ns);
285 }
287 {
288#ifdef EEL_STRINGS_MUTABLE_LITERALS
289 m_literal_strings.Add(ns);
291#else
292 const int l = ns->GetLength();
293 const int sz=m_literal_strings.GetSize();
294 int x;
295 for (x=0;x<sz;x++)
296 {
298 if (ns->GetLength() == l && !strcmp(s->Get(),ns->Get())) break;
299 }
300 if (x<sz) delete ns;
301 else m_literal_strings.Add(ns);
303#endif
304 }
305
306 static int varEnumProc(const char *name, EEL_F *val, void *ctx)
307 {
308 ((eel_string_context_state *)ctx)->m_varname_cache.AddUnsorted(name,val);
309 return 1;
310 }
311
312};
313
314
315
316static int eel_validate_format_specifier(const char *fmt_in, char *typeOut,
317 char *fmtOut, int fmtOut_sz,
318 char *varOut, int varOut_sz,
319 int *varOut_used
320 )
321{
322 const char *fmt = fmt_in+1;
323 int state=0;
324 if (fmt_in[0] != '%') return 0; // ugh passed a non-specifier
325
326 *varOut_used = 0;
327 *varOut = 0;
328
329 if (fmtOut_sz-- < 2) return 0;
330 *fmtOut++ = '%';
331
332 while (*fmt)
333 {
334 const char c = *fmt++;
335 if (fmtOut_sz < 2) return 0;
336
337 if (c == 'f'|| c=='e' || c=='E' || c=='g' || c=='G' || c == 'd' || c == 'u' ||
338 c == 'x' || c == 'X' || c == 'c' || c == 'C' || c =='s' || c=='S' || c=='i')
339 {
340 *typeOut = c;
341 fmtOut[0] = c;
342 fmtOut[1] = 0;
343 return (int) (fmt - fmt_in);
344 }
345 else if (c == '.')
346 {
347 *fmtOut++ = c; fmtOut_sz--;
348 if (state&(2)) break;
349 state |= 2;
350 }
351 else if (c == '+')
352 {
353 *fmtOut++ = c; fmtOut_sz--;
354 if (state&(32|16|8|4)) break;
355 state |= 8;
356 }
357 else if (c == '-' || c == ' ')
358 {
359 *fmtOut++ = c; fmtOut_sz--;
360 if (state&(32|16|8|4)) break;
361 state |= 16;
362 }
363 else if (c >= '0' && c <= '9')
364 {
365 *fmtOut++ = c; fmtOut_sz--;
366 state|=4;
367 }
368 else if (c == '{')
369 {
370 if (state & 64) break;
371 state|=64;
372 if (*fmt == '.' || (*fmt >= '0' && *fmt <= '9')) return 0; // symbol name can't start with 0-9 or .
373
374 while (*fmt != '}')
375 {
376 if ((*fmt >= 'a' && *fmt <= 'z') ||
377 (*fmt >= 'A' && *fmt <= 'Z') ||
378 (*fmt >= '0' && *fmt <= '9') ||
379 *fmt == '_' || *fmt == '.' || *fmt == '#')
380 {
381 if (varOut_sz < 2) return 0;
382 *varOut++ = *fmt++;
383 varOut_sz -- ;
384 }
385 else
386 {
387 return 0; // bad character in variable name
388 }
389 }
390 fmt++;
391 *varOut = 0;
392 *varOut_used=1;
393 }
394 else
395 {
396 break;
397 }
398 }
399 return 0;
400}
401
402int eel_format_strings(void *opaque, const char *fmt, const char *fmt_end, char *buf, int buf_sz, int num_fmt_parms, EEL_F **fmt_parms)
403{
404 int fmt_parmpos = 0;
405 char *op = buf;
406 while ((fmt_end ? fmt < fmt_end : *fmt) && op < buf+buf_sz-128)
407 {
408 if (fmt[0] == '%' && fmt[1] == '%')
409 {
410 *op++ = '%';
411 fmt+=2;
412 }
413 else if (fmt[0] == '%')
414 {
415 char ct=0;
416 char fs[128];
417 char varname[128];
418 int varname_used=0;
419 const int l=eel_validate_format_specifier(fmt,&ct,fs,sizeof(fs),varname,sizeof(varname),&varname_used);
420 if (!l || !ct)
421 {
422 *op=0;
423 return -1;
424 }
425
426 EEL_F vv=0.0;
427 const EEL_F *varptr = NULL;
428 if (varname_used)
429 {
430#ifdef EEL_STRING_GETNAMEDVAR
431 if (varname[0]) varptr=EEL_STRING_GETNAMEDVAR(varname,0,&vv);
432#endif
433 }
434 else
435 {
436 if (fmt_parmpos < num_fmt_parms) varptr = fmt_parms[fmt_parmpos];
437#ifdef EEL_STRING_GETFMTVAR
438 if (!varptr) varptr = EEL_STRING_GETFMTVAR(fmt_parmpos);
439#endif
440 fmt_parmpos++;
441 }
442 double v = varptr ? (double)*varptr : 0.0;
443
444 if (ct == 's' || ct=='S')
445 {
447 const char *str = EEL_STRING_GET_FOR_INDEX(v,&wr);
448 const int maxl=(int) (buf+buf_sz - 2 - op);
449 if (wr && !fs[2]) // %s or %S -- todo: implement padding modes for binary compat too?
450 {
451 int wl = wr->GetLength();
452 if (wl > maxl) wl=maxl;
453 memcpy(op,wr->Get(),wl);
454 op += wl;
455 *op=0;
456 }
457 else
458 {
459 snprintf(op,maxl,fs,str ? str : "");
460 }
461 }
462 else
463 {
464 if (varptr == &vv) // passed %{#str}d etc, convert to float
465 {
466 const char *str = EEL_STRING_GET_FOR_INDEX(v,NULL);
467 v = str ? atof(str) : 0.0;
468 }
469
470 if (ct == 'x' || ct == 'X' || ct == 'd' || ct == 'u' || ct=='i')
471 {
472 snprintf(op,64,fs,(int) (v));
473 }
474 else if (ct == 'c')
475 {
476 *op++=(char) (int)v;
477 *op=0;
478 }
479 else if (ct == 'C')
480 {
481 const unsigned int iv = (unsigned int) v;
482 int bs = 0;
483 if (iv & 0xff000000) bs=24;
484 else if (iv & 0x00ff0000) bs=16;
485 else if (iv & 0x0000ff00) bs=8;
486 while (bs>=0)
487 {
488 const char c=(char) (iv>>bs);
489 *op++=c?c:' ';
490 bs-=8;
491 }
492 *op=0;
493 }
494 else
495 {
496 snprintf(op,64,fs,v);
497 }
498 }
499
500 while (*op) op++;
501
502 fmt += l;
503 }
504 else
505 {
506 *op++ = *fmt++;
507 }
508
509 }
510 *op=0;
511 return (int) (op - buf);
512}
513
514
515
516static int eel_string_match(void *opaque, const char *fmt, const char *msg, int match_fmt_pos, int ignorecase, const char *fmt_endptr, const char *msg_endptr, int num_fmt_parms, EEL_F **fmt_parms)
517{
518 // check for match, updating EEL_STRING_GETFMTVAR(*) as necessary
519 // %d=12345
520 // %f=12345[.678]
521 // %c=any nonzero char, ascii value
522 // %x=12354ab
523 // %*, %?, %+, %% literals
524 // * ? + match minimal groups of 0+,1, or 1+ chars
525 for (;;)
526 {
527 if (fmt>=fmt_endptr)
528 {
529 if (msg>=msg_endptr) return 1;
530 return 0; // format ends before matching string
531 }
532
533 // if string ends and format is not on a wildcard, early-out to 0
534 if (msg>=msg_endptr && *fmt != '*' && *fmt != '%') return 0;
535
536 switch (*fmt)
537 {
538 case '*':
539 case '+':
540 // if last char of search pattern, we're done!
541 if (fmt+1>=fmt_endptr || (fmt[1] == '?' && fmt+2>=fmt_endptr)) return *fmt == '*' || msg<msg_endptr;
542
543 if (fmt[0] == '+') msg++; // skip a character for + . Note that in this case msg[1] is valid, because of the !*msg && *fmt != '*' check above
544
545 fmt++;
546 if (*fmt == '?')
547 {
548 // *? or +? are lazy matches
549 fmt++;
550
551 while (msg<msg_endptr && !eel_string_match(opaque,fmt, msg,match_fmt_pos,ignorecase,fmt_endptr, msg_endptr,num_fmt_parms,fmt_parms)) msg++;
552 return msg<msg_endptr;
553 }
554 else
555 {
556 // greedy match
557 int len = (int) (msg_endptr-msg);
558 while (len >= 0 && !eel_string_match(opaque,fmt, msg+len,match_fmt_pos,ignorecase,fmt_endptr, msg_endptr,num_fmt_parms,fmt_parms)) len--;
559 return len >= 0;
560 }
561 break;
562 case '?':
563 fmt++;
564 msg++;
565 break;
566 case '%':
567 {
568 fmt++;
569 unsigned short fmt_minlen = 1, fmt_maxlen = 0;
570 if (*fmt >= '0' && *fmt <= '9')
571 {
572 fmt_minlen = *fmt++ - '0';
573 while (*fmt >= '0' && *fmt <= '9') fmt_minlen = fmt_minlen * 10 + (*fmt++ - '0');
574 fmt_maxlen = fmt_minlen;
575 }
576 if (*fmt == '-')
577 {
578 fmt++;
579 fmt_maxlen = 0;
580 while (*fmt >= '0' && *fmt <= '9') fmt_maxlen = fmt_maxlen * 10 + (*fmt++ - '0');
581 }
582 const char *dest_varname=NULL;
583 if (*fmt == '{')
584 {
585 dest_varname=++fmt;
586 while (*fmt && fmt < fmt_endptr && *fmt != '}') fmt++;
587 if (fmt >= fmt_endptr-1 || *fmt != '}') return 0; // malformed %{var}s
588 fmt++; // skip '}'
589 }
590
591 char fmt_char = *fmt++;
592 if (!fmt_char) return 0; // malformed
593
594 if (fmt_char == '*' ||
595 fmt_char == '?' ||
596 fmt_char == '+' ||
597 fmt_char == '%')
598 {
599 if (*msg++ != fmt_char) return 0;
600 }
601 else if (fmt_char == 'c')
602 {
603 EEL_F *varOut = NULL;
604 EEL_F vv=0.0;
605 if (!dest_varname)
606 {
607 if (match_fmt_pos < num_fmt_parms) varOut = fmt_parms[match_fmt_pos];
608#ifdef EEL_STRING_GETFMTVAR
609 if (!varOut) varOut = EEL_STRING_GETFMTVAR(match_fmt_pos);
610#endif
611 match_fmt_pos++;
612 }
613 else
614 {
615#ifdef EEL_STRING_GETNAMEDVAR
616 char tmp[128];
617 int idx=0;
618 while (dest_varname < fmt_endptr && *dest_varname && *dest_varname != '}' && idx<(int)sizeof(tmp)-1) tmp[idx++] = *dest_varname++;
619 tmp[idx]=0;
620 if (idx>0) varOut = EEL_STRING_GETNAMEDVAR(tmp,1,&vv);
621#endif
622 }
623 if (msg >= msg_endptr) return 0; // out of chars
624
625 if (varOut)
626 {
627 if (varOut == &vv) // %{#foo}c
628 {
631 if (wr) wr->Set(msg,1);
632 }
633 else
634 {
635 *varOut = (EEL_F)*(unsigned char *)msg;
636 }
637 }
638 msg++;
639 }
640 else
641 {
642 int len=0;
643 int lazy=0;
644 if (fmt_char>='A'&&fmt_char<='Z') { lazy=1; fmt_char += 'a' - 'A'; }
645
646 if (fmt_char == 's')
647 {
648 len = (int) (msg_endptr-msg);
649 }
650 else if (fmt_char == 'x')
651 {
652 while ((msg[len] >= '0' && msg[len] <= '9') ||
653 (msg[len] >= 'A' && msg[len] <= 'F') ||
654 (msg[len] >= 'a' && msg[len] <= 'f')) len++;
655 }
656 else if (fmt_char == 'f')
657 {
658 if (msg[len] == '-') len++;
659 while (msg[len] >= '0' && msg[len] <= '9') len++;
660 if (msg[len] == '.')
661 {
662 len++;
663 while (msg[len] >= '0' && msg[len] <= '9') len++;
664 }
665 }
666 else if (fmt_char == 'd' || fmt_char == 'u' || fmt_char == 'i')
667 {
668 if (fmt_char != 'u' && msg[len] == '-') len++;
669 while (msg[len] >= '0' && msg[len] <= '9') len++;
670 }
671 else
672 {
673 // bad format
674 return 0;
675 }
676
677 if (fmt_maxlen>0 && len > fmt_maxlen) len = fmt_maxlen;
678
679 if (!dest_varname) match_fmt_pos++;
680
681 if (lazy)
682 {
683 if (fmt_maxlen<1 || fmt_maxlen>len) fmt_maxlen=len;
684 len=fmt_minlen;
685 while (len <= fmt_maxlen && !eel_string_match(opaque,fmt, msg+len,match_fmt_pos,ignorecase,fmt_endptr, msg_endptr,num_fmt_parms,fmt_parms)) len++;
686 if (len > fmt_maxlen) return 0;
687 }
688 else
689 {
690 while (len >= fmt_minlen && !eel_string_match(opaque,fmt, msg+len,match_fmt_pos,ignorecase,fmt_endptr, msg_endptr,num_fmt_parms,fmt_parms)) len--;
691 if (len < fmt_minlen) return 0;
692 }
693
694 EEL_F vv=0.0;
695 EEL_F *varOut = NULL;
696 if (!dest_varname)
697 {
698 if (match_fmt_pos>0 && match_fmt_pos-1 < num_fmt_parms) varOut = fmt_parms[match_fmt_pos-1];
699#ifdef EEL_STRING_GETFMTVAR
700 if (!varOut) varOut = EEL_STRING_GETFMTVAR(match_fmt_pos-1);
701#endif
702 }
703 else
704 {
705#ifdef EEL_STRING_GETNAMEDVAR
706 char tmp[128];
707 int idx=0;
708 while (dest_varname < fmt_endptr && *dest_varname && *dest_varname != '}' && idx<(int)sizeof(tmp)-1) tmp[idx++] = *dest_varname++;
709 tmp[idx]=0;
710 if (idx>0) varOut = EEL_STRING_GETNAMEDVAR(tmp,1,&vv);
711#endif
712 }
713 if (varOut)
714 {
715 if (fmt_char == 's')
716 {
718 EEL_STRING_GET_FOR_WRITE(*varOut, &wr);
719 if (wr)
720 {
721 if (msg_endptr >= wr->Get() && msg_endptr <= wr->Get() + wr->GetLength())
722 {
723#ifdef EEL_STRING_DEBUGOUT
724 EEL_STRING_DEBUGOUT("match: destination specifier passed is also haystack, will not update");
725#endif
726 }
727 else if (fmt_endptr >= wr->Get() && fmt_endptr <= wr->Get() + wr->GetLength())
728 {
729#ifdef EEL_STRING_DEBUGOUT
730 EEL_STRING_DEBUGOUT("match: destination specifier passed is also format, will not update");
731#endif
732 }
733 else
734 {
735 wr->SetRaw(msg,len);
736 }
737 }
738 else
739 {
740#ifdef EEL_STRING_DEBUGOUT
741 EEL_STRING_DEBUGOUT("match: bad destination specifier passed as %d: %f",match_fmt_pos,*varOut);
742#endif
743 }
744 }
745 else
746 {
747 char tmp[128];
748 lstrcpyn_safe(tmp,msg,wdl_min(len+1,(int)sizeof(tmp)));
749 if (varOut == &vv)
750 {
753 if (wr) wr->Set(tmp);
754 }
755 else
756 {
757 char *bl=(char*)msg;
758 if (fmt_char == 'u')
759 *varOut = (EEL_F)strtoul(tmp,&bl,10);
760 else if (fmt_char == 'x')
761 *varOut = (EEL_F)strtoul(msg,&bl,16);
762 else
763 *varOut = (EEL_F)atof(tmp);
764 }
765 }
766 }
767 return 1;
768 }
769 }
770 break;
771 default:
772 if (ignorecase ? (toupper(*fmt) != toupper(*msg)) : (*fmt!= *msg)) return 0;
773 fmt++;
774 msg++;
775 break;
776 }
777 }
778}
779
780
781
782static EEL_F NSEEL_CGEN_CALL _eel_sprintf(void *opaque, INT_PTR num_param, EEL_F **parms)
783{
784 if (num_param<2) return 0.0;
785
786 if (opaque)
787 {
790 EEL_STRING_GET_FOR_WRITE(*(parms[0]), &wr);
791 if (!wr)
792 {
793#ifdef EEL_STRING_DEBUGOUT
794 EEL_STRING_DEBUGOUT("sprintf: bad destination specifier passed %f",*(parms[0]));
795#endif
796 }
797 else
798 {
800 const char *fmt = EEL_STRING_GET_FOR_INDEX(*(parms[1]),&wr_src);
801 if (fmt)
802 {
803 char buf[16384];
804 const int fmt_len = eel_format_strings(opaque,fmt,wr_src?(fmt+wr_src->GetLength()):NULL,buf,(int)sizeof(buf), (int)num_param-2, parms+2);
805
806 if (fmt_len>=0)
807 {
808 wr->SetRaw(buf,fmt_len);
809 }
810 else
811 {
812#ifdef EEL_STRING_DEBUGOUT
813 EEL_STRING_DEBUGOUT("sprintf: bad format string %s",fmt);
814#endif
815 }
816 }
817 else
818 {
819#ifdef EEL_STRING_DEBUGOUT
820 EEL_STRING_DEBUGOUT("sprintf: bad format specifier passed %f",*(parms[1]));
821#endif
822 }
823 }
824 }
825 return *(parms[0]);
826}
827
828
829static EEL_F NSEEL_CGEN_CALL _eel_strncat(void *opaque, EEL_F *strOut, EEL_F *fmt_index, EEL_F *maxlen)
830{
831 if (opaque)
832 {
834 EEL_STRING_STORAGECLASS *wr=NULL, *wr_src=NULL;
835 EEL_STRING_GET_FOR_WRITE(*strOut, &wr);
836 if (!wr)
837 {
838#ifdef EEL_STRING_DEBUGOUT
839 EEL_STRING_DEBUGOUT("str%scat: bad destination specifier passed %f",maxlen ? "n":"",*strOut);
840#endif
841 }
842 else
843 {
844 const char *fmt = EEL_STRING_GET_FOR_INDEX(*fmt_index,&wr_src);
845 if (fmt||wr_src)
846 {
847 if (wr->GetLength() > EEL_STRING_MAXUSERSTRING_LENGTH_HINT)
848 {
849#ifdef EEL_STRING_DEBUGOUT
850 EEL_STRING_DEBUGOUT("str%scat: will not grow string since it is already %d bytes",maxlen ? "n":"",wr->GetLength());
851#endif
852 }
853 else
854 {
855 int ml=0;
856 if (maxlen && *maxlen > 0) ml = (int)*maxlen;
857 if (wr_src)
858 {
860 if (wr_src == wr) *(wr_src=&tmp) = *wr;
861 wr->AppendRaw(wr_src->Get(), ml > 0 && ml < wr_src->GetLength() ? ml : wr_src->GetLength());
862 }
863 else
864 wr->Append(fmt, ml);
865 }
866 }
867 else
868 {
869#ifdef EEL_STRING_DEBUGOUT
870 EEL_STRING_DEBUGOUT("str%scat: bad format specifier passed %f",maxlen ? "n":"",*fmt_index);
871#endif
872 }
873 }
874 }
875 return *strOut;
876}
877
878static EEL_F NSEEL_CGEN_CALL _eel_strcpysubstr(void *opaque, INT_PTR nparm, EEL_F **parms) //EEL_F *strOut, EEL_F *fmt_index, EEL_F *offs
879{
880 if (opaque && nparm>=3)
881 {
883 EEL_STRING_STORAGECLASS *wr=NULL, *wr_src=NULL;
884 EEL_STRING_GET_FOR_WRITE(parms[0][0], &wr);
885 if (!wr)
886 {
887#ifdef EEL_STRING_DEBUGOUT
888 EEL_STRING_DEBUGOUT("strcpy_substr: bad destination specifier passed %f",parms[0][0]);
889#endif
890 }
891 else
892 {
893 const char *fmt = EEL_STRING_GET_FOR_INDEX(parms[1][0],&wr_src);
894 if (fmt)
895 {
896 const int fmt_len = wr_src ? wr_src->GetLength() : (int) strlen(fmt);
897 int maxlen, o = (int) parms[2][0];
898 if (o < 0)
899 {
900 o = fmt_len + o;
901 if (o < 0) o=0;
902 }
903 maxlen = fmt_len - o;
904 if (nparm >= 4)
905 {
906 const int a = (int) parms[3][0];
907 if (a<0) maxlen += a;
908 else if (a<maxlen) maxlen=a;
909 }
910
911 if (maxlen < 1 || o >= fmt_len)
912 {
913 wr->Set("");
914 }
915 else
916 {
917 if (wr_src==wr)
918 {
919 wr->DeleteSub(0,o);
920 if (wr->GetLength() > maxlen) wr->SetLen(maxlen);
921 }
922 else
923 {
924 wr->SetRaw(fmt+o,maxlen);
925 }
926 }
927 }
928 else
929 {
930#ifdef EEL_STRING_DEBUGOUT
931 EEL_STRING_DEBUGOUT("strcpy_substr: bad format specifier passed %f",parms[1][0]);
932#endif
933 }
934 }
935 return parms[0][0];
936 }
937 return 0.0;
938}
939
940
941static EEL_F NSEEL_CGEN_CALL _eel_strncpy(void *opaque, EEL_F *strOut, EEL_F *fmt_index, EEL_F *maxlen)
942{
943 if (opaque)
944 {
946 EEL_STRING_STORAGECLASS *wr=NULL, *wr_src=NULL;
947 EEL_STRING_GET_FOR_WRITE(*strOut, &wr);
948 if (!wr)
949 {
950#ifdef EEL_STRING_DEBUGOUT
951 EEL_STRING_DEBUGOUT("str%scpy: bad destination specifier passed %f",maxlen ? "n":"",*strOut);
952#endif
953 }
954 else
955 {
956 const char *fmt = EEL_STRING_GET_FOR_INDEX(*fmt_index,&wr_src);
957 if (fmt)
958 {
959 int ml=-1;
960 if (maxlen && *maxlen >= 0) ml = (int)*maxlen;
961
962 if (wr_src == wr)
963 {
964 if (ml>=0 && ml < wr->GetLength()) wr->SetLen(ml); // shorten string if strncpy(x,x,len) and len >=0
965 return *strOut;
966 }
967
968 if (wr_src) wr->SetRaw(fmt, ml>0 && ml < wr_src->GetLength() ? ml : wr_src->GetLength());
969 else wr->Set(fmt,ml);
970 }
971 else
972 {
973#ifdef EEL_STRING_DEBUGOUT
974 EEL_STRING_DEBUGOUT("str%scpy: bad format specifier passed %f",maxlen ? "n":"",*fmt_index);
975#endif
976 }
977 }
978 }
979 return *strOut;
980}
981
982static EEL_F _eel_strcmp_int(const char *a, int a_len, const char *b, int b_len, int ml, bool ignorecase)
983{
984 // binary-safe comparison (at least if a_len>=0 etc)
985 int pos = 0;
986 for (;;)
987 {
988 if (ml > 0 && pos == ml) return 0.0;
989 const bool a_end = a_len >= 0 ? pos == a_len : !a[pos];
990 const bool b_end = b_len >= 0 ? pos == b_len : !b[pos];
991 if (a_end || b_end)
992 {
993 if (!b_end) return -1.0; // b[pos] is nonzero, a[pos] is zero
994 if (!a_end) return 1.0;
995 return 0.0;
996 }
997 char av = a[pos];
998 char bv = b[pos];
999 if (ignorecase)
1000 {
1001 av=toupper(av);
1002 bv=toupper(bv);
1003 }
1004 if (bv > av) return -1.0;
1005 if (av > bv) return 1.0;
1006
1007 pos++;
1008 }
1009}
1010
1011static EEL_F NSEEL_CGEN_CALL _eel_strncmp(void *opaque, EEL_F *aa, EEL_F *bb, EEL_F *maxlen)
1012{
1013 if (opaque)
1014 {
1016 EEL_STRING_STORAGECLASS *wr_a=NULL,*wr_b=NULL;
1017 const char *a = EEL_STRING_GET_FOR_INDEX(*aa,&wr_a);
1018 const char *b = EEL_STRING_GET_FOR_INDEX(*bb,&wr_b);
1019 if (!a || !b)
1020 {
1021#ifdef EEL_STRING_DEBUGOUT
1022 EEL_STRING_DEBUGOUT("str%scmp: bad specifier(s) passed %f/%f",maxlen ? "n" : "",*aa,*bb);
1023#endif
1024 }
1025 else
1026 {
1027 const int ml = maxlen ? (int) *maxlen : -1;
1028 if (!ml || a==b) return 0; // strncmp(x,y,0) == 0
1029
1030 return _eel_strcmp_int(a,wr_a ? wr_a->GetLength() : -1,b,wr_b ? wr_b->GetLength() : -1, ml, false);
1031 }
1032 }
1033 return -1.0;
1034}
1035
1036static EEL_F NSEEL_CGEN_CALL _eel_strnicmp(void *opaque, EEL_F *aa, EEL_F *bb, EEL_F *maxlen)
1037{
1038 if (opaque)
1039 {
1041 EEL_STRING_STORAGECLASS *wr_a=NULL,*wr_b=NULL;
1042 const char *a = EEL_STRING_GET_FOR_INDEX(*aa,&wr_a);
1043 const char *b = EEL_STRING_GET_FOR_INDEX(*bb,&wr_b);
1044 if (!a || !b)
1045 {
1046#ifdef EEL_STRING_DEBUGOUT
1047 EEL_STRING_DEBUGOUT("str%sicmp: bad specifier(s) passed %f/%f",maxlen ? "n" : "",*aa,*bb);
1048#endif
1049 }
1050 else
1051 {
1052 const int ml = maxlen ? (int) *maxlen : -1;
1053 if (!ml || a==b) return 0; // strncmp(x,y,0) == 0
1054 return _eel_strcmp_int(a,wr_a ? wr_a->GetLength() : -1,b,wr_b ? wr_b->GetLength() : -1, ml, true);
1055 }
1056 }
1057 return -1.0;
1058}
1059
1060
1061static EEL_F NSEEL_CGEN_CALL _eel_strcat(void *opaque, EEL_F *strOut, EEL_F *fmt_index)
1062{
1063 return _eel_strncat(opaque,strOut,fmt_index,NULL);
1064}
1065
1066static EEL_F NSEEL_CGEN_CALL _eel_strcpy(void *opaque, EEL_F *strOut, EEL_F *fmt_index)
1067{
1068 return _eel_strncpy(opaque,strOut,fmt_index,NULL);
1069}
1070
1071
1072static EEL_F NSEEL_CGEN_CALL _eel_strcmp(void *opaque, EEL_F *strOut, EEL_F *fmt_index)
1073{
1074 return _eel_strncmp(opaque,strOut,fmt_index,NULL);
1075}
1076
1077static EEL_F NSEEL_CGEN_CALL _eel_stricmp(void *opaque, EEL_F *strOut, EEL_F *fmt_index)
1078{
1079 return _eel_strnicmp(opaque,strOut,fmt_index,NULL);
1080}
1081
1082
1083static EEL_F NSEEL_CGEN_CALL _eel_strgetchar(void *opaque, EEL_F *strOut, EEL_F *idx)
1084{
1085 if (opaque)
1086 {
1089 const char *fmt = EEL_STRING_GET_FOR_INDEX(*strOut, &wr);
1090 if (!fmt)
1091 {
1092#ifdef EEL_STRING_DEBUGOUT
1093 EEL_STRING_DEBUGOUT("str_getchar: bad specifier passed %f",*strOut);
1094#endif
1095 }
1096 else
1097 {
1098 const int wl=(wr?wr->GetLength():(int)strlen(fmt));
1099 int l = (int) *idx;
1100 if (*idx < 0.0) l+=wl;
1101 if (l>=0 && l < wl) return ((unsigned char *)fmt)[l];
1102 }
1103 }
1104 return 0;
1105}
1106
1107#define EEL_GETCHAR_FLAG_ENDIANSWAP 0x10
1108#define EEL_GETCHAR_FLAG_UNSIGNED 0x20
1109#define EEL_GETCHAR_FLAG_FLOAT 0x40
1110static int eel_getchar_flag(int type)
1111{
1112#ifdef __ppc__
1113 int ret=EEL_GETCHAR_FLAG_ENDIANSWAP; // default to LE
1114#else
1115 int ret=0;
1116#endif
1117
1118 if (toupper((type>>8)&0xff) == 'U') ret|=EEL_GETCHAR_FLAG_UNSIGNED;
1119 else if (type>255 && toupper(type&0xff) == 'U') { ret|=EEL_GETCHAR_FLAG_UNSIGNED; type>>=8; }
1120 type&=0xff;
1121
1122 if (isupper(type)) ret^=EEL_GETCHAR_FLAG_ENDIANSWAP;
1123 else type += 'A'-'a';
1124
1125 switch (type)
1126 {
1127 case 'F': return ret|4|EEL_GETCHAR_FLAG_FLOAT;
1128 case 'D': return ret|8|EEL_GETCHAR_FLAG_FLOAT;
1129 case 'S': return ret|2;
1130 case 'I': return ret|4;
1131 }
1132
1133 return ret|1;
1134}
1135
1136static void eel_setchar_do(int flag, char *dest, EEL_F val)
1137{
1138 union
1139 {
1140 char buf[8];
1141 float asFloat;
1142 double asDouble;
1143 int asInt;
1144 short asShort;
1145 char asChar;
1146 unsigned int asUInt;
1147 unsigned short asUShort;
1148 unsigned char asUChar;
1149 } a;
1150 const int type_sz=flag&0xf;
1151
1153 {
1154 if (type_sz==8) a.asDouble=val;
1155 else a.asFloat=(float)val;
1156 }
1158 {
1159 if (type_sz==4) a.asUInt=(unsigned int)val;
1160 else if (type_sz==2) a.asUShort=(unsigned short)val;
1161 else a.asUChar=(unsigned char)val;
1162 }
1163 else if (type_sz==4) a.asInt=(int)val;
1164 else if (type_sz==2) a.asShort=(short)val;
1165 else a.asChar=(char)val;
1166
1168 {
1169 dest += type_sz;
1170 int x;
1171 for(x=0;x<type_sz;x++) *--dest=a.buf[x];
1172 }
1173 else
1174 memcpy(dest,a.buf,type_sz);
1175
1176}
1177
1178
1179static EEL_F eel_getchar_do(int flag, const char *src)
1180{
1181 union
1182 {
1183 char buf[8];
1184 float asFloat;
1185 double asDouble;
1186 int asInt;
1187 short asShort;
1188 char asChar;
1189 unsigned int asUInt;
1190 unsigned short asUShort;
1191 unsigned char asUChar;
1192 } a;
1193 const int type_sz=flag&0xf;
1194
1195 memset(&a, 0, sizeof(a));
1197 {
1198 src += type_sz;
1199 int x;
1200 for(x=0;x<type_sz;x++) a.buf[x]=*--src;
1201 }
1202 else
1203 memcpy(a.buf,src,type_sz);
1204
1206 {
1207 if (type_sz==8) return a.asDouble;
1208 return a.asFloat;
1209 }
1211 {
1212 if (type_sz==4) return a.asUInt;
1213 if (type_sz==2) return a.asUShort;
1214 return a.asUChar;
1215 }
1216 if (type_sz==4) return a.asInt;
1217 if (type_sz==2) return a.asShort;
1218 return a.asChar;
1219}
1220
1221static EEL_F NSEEL_CGEN_CALL _eel_strgetchar2(void *opaque, INT_PTR np, EEL_F **parms)
1222{
1223 if (opaque && np>=3)
1224 {
1227 const char *fmt = EEL_STRING_GET_FOR_INDEX(parms[0][0], &wr);
1228 if (!fmt)
1229 {
1230#ifdef EEL_STRING_DEBUGOUT
1231 EEL_STRING_DEBUGOUT("str_getchar: bad specifier passed %f",parms[0][0]);
1232#endif
1233 }
1234 else
1235 {
1236 const int wl=(wr?wr->GetLength():(int)strlen(fmt));
1237 const int flags=eel_getchar_flag((int) parms[2][0]);
1238 int l = (int) parms[1][0];
1239 if (parms[1][0] < 0.0) l+=wl;
1240
1241 if (l>=0 && l <= wl-(flags&0xf))
1242 {
1243 return eel_getchar_do(flags,fmt+l);
1244 }
1245 }
1246 }
1247 return 0;
1248}
1249
1250static EEL_F NSEEL_CGEN_CALL _eel_strsetchar2(void *opaque, INT_PTR np, EEL_F **parms)
1251{
1252 if (opaque && np>=4)
1253 {
1256 EEL_STRING_GET_FOR_WRITE(parms[0][0], &wr);
1257 if (!wr)
1258 {
1259#ifdef EEL_STRING_DEBUGOUT
1260 EEL_STRING_DEBUGOUT("str_setchar: bad destination specifier passed %f",parms[0][0]);
1261#endif
1262 }
1263 else
1264 {
1265 const int wl=wr->GetLength();
1266
1267 int l = (int) parms[1][0];
1268 if (parms[1][0] < 0.0) l+=wl;
1269 if (l>=0 && l <= wl)
1270 {
1271 const int flags=eel_getchar_flag((int) parms[3][0]);
1272 if (l==wl)
1273 {
1275 {
1276#ifdef EEL_STRING_DEBUGOUT
1277 EEL_STRING_DEBUGOUT("str_setchar: will not grow string since it is already %d bytes",wl);
1278#endif
1279 }
1280 else
1281 {
1282 char buf[32];
1283 eel_setchar_do(flags,buf,parms[2][0]);
1284 wr->AppendRaw(buf,flags&0xf);
1285 }
1286 }
1287 else
1288 eel_setchar_do(flags,(char*)wr->Get()+l,parms[2][0]);
1289 }
1290 }
1291 }
1292 return parms[0][0];
1293}
1294
1295static EEL_F NSEEL_CGEN_CALL _eel_strsetchar(void *opaque, EEL_F *strOut, EEL_F *idx, EEL_F *val)
1296{
1297 if (opaque)
1298 {
1301 EEL_STRING_GET_FOR_WRITE(*strOut, &wr);
1302 if (!wr)
1303 {
1304#ifdef EEL_STRING_DEBUGOUT
1305 EEL_STRING_DEBUGOUT("str_setchar: bad destination specifier passed %f",*strOut);
1306#endif
1307 }
1308 else
1309 {
1310 const int wl=wr->GetLength();
1311 int l = (int) *idx;
1312 if (*idx < 0.0) l+=wl;
1313 if (l>=0 && l <= wl)
1314 {
1315 const unsigned char v=((int)*val)&255;
1316 if (l==wl)
1317 {
1319 {
1320#ifdef EEL_STRING_DEBUGOUT
1321 EEL_STRING_DEBUGOUT("str_setchar: will not grow string since it is already %d bytes",wl);
1322#endif
1323 }
1324 else
1325 wr->AppendRaw((const char*)&v,1);
1326 }
1327 else
1328 ((unsigned char *)wr->Get())[l]=v; // allow putting nulls in string, strlen() will still get the full size
1329 }
1330 }
1331 }
1332 return *strOut;
1333}
1334
1335static EEL_F NSEEL_CGEN_CALL _eel_strinsert(void *opaque, EEL_F *strOut, EEL_F *fmt_index, EEL_F *pos)
1336{
1337 if (opaque)
1338 {
1340 EEL_STRING_STORAGECLASS *wr=NULL, *wr_src=NULL;
1341 EEL_STRING_GET_FOR_WRITE(*strOut, &wr);
1342 if (!wr)
1343 {
1344#ifdef EEL_STRING_DEBUGOUT
1345 EEL_STRING_DEBUGOUT("str_insert: bad destination specifier passed %f",*strOut);
1346#endif
1347 }
1348 else
1349 {
1350 const char *fmt = EEL_STRING_GET_FOR_INDEX(*fmt_index,&wr_src);
1351 if (fmt)
1352 {
1354 if (wr_src == wr) *(wr_src=&tmp) = *wr; // insert from copy
1355
1356 // if wr_src, fmt is guaranteed to be wr_src.Get()
1357 int p = (int)*pos;
1358 int insert_l = wr_src ? wr_src->GetLength() : (int)strlen(fmt);
1359 if (p < 0)
1360 {
1361 insert_l += p; // decrease insert_l
1362 fmt -= p; // advance fmt -- if fmt gets advanced past NULL term, insert_l will be < 0 anyway
1363 p=0;
1364 }
1365
1366 if (insert_l>0)
1367 {
1368 if (wr->GetLength() > EEL_STRING_MAXUSERSTRING_LENGTH_HINT)
1369 {
1370#ifdef EEL_STRING_DEBUGOUT
1371 EEL_STRING_DEBUGOUT("str_insert: will not grow string since it is already %d bytes",wr->GetLength());
1372#endif
1373 }
1374 else
1375 {
1376 if (wr_src)
1377 {
1378 wr->InsertRaw(fmt,p, insert_l);
1379 }
1380 else
1381 {
1382 wr->Insert(fmt,p);
1383 }
1384 }
1385 }
1386 }
1387 else
1388 {
1389#ifdef EEL_STRING_DEBUGOUT
1390 EEL_STRING_DEBUGOUT("str_insert: bad source specifier passed %f",*fmt_index);
1391#endif
1392 }
1393 }
1394 }
1395 return *strOut;
1396}
1397
1398static EEL_F NSEEL_CGEN_CALL _eel_strdelsub(void *opaque, EEL_F *strOut, EEL_F *pos, EEL_F *len)
1399{
1400 if (opaque)
1401 {
1404 EEL_STRING_GET_FOR_WRITE(*strOut, &wr);
1405 if (!wr)
1406 {
1407#ifdef EEL_STRING_DEBUGOUT
1408 EEL_STRING_DEBUGOUT("str_delsub: bad destination specifier passed %f",*strOut);
1409#endif
1410 }
1411 else
1412 {
1413 int p=(int)*pos;
1414 int l=(int)*len;
1415 if (p<0)
1416 {
1417 l+=p;
1418 p=0;
1419 }
1420 if (l>0)
1421 wr->DeleteSub(p,l);
1422 }
1423 }
1424 return *strOut;
1425}
1426
1427static EEL_F NSEEL_CGEN_CALL _eel_strsetlen(void *opaque, EEL_F *strOut, EEL_F *newlen)
1428{
1429 if (opaque)
1430 {
1433 EEL_STRING_GET_FOR_WRITE(*strOut, &wr);
1434 if (!wr)
1435 {
1436#ifdef EEL_STRING_DEBUGOUT
1437 EEL_STRING_DEBUGOUT("str_setlen: bad destination specifier passed %f",*strOut);
1438#endif
1439 }
1440 else
1441 {
1442 int l = (int) *newlen;
1443 if (l < 0) l=0;
1445 {
1446#ifdef EEL_STRING_DEBUGOUT
1447 EEL_STRING_DEBUGOUT("str_setlen: clamping requested length of %d to %d",l,EEL_STRING_MAXUSERSTRING_LENGTH_HINT);
1448#endif
1450 }
1451 wr->SetLen(l);
1452
1453 }
1454 }
1455 return *strOut;
1456}
1457
1458
1459static EEL_F NSEEL_CGEN_CALL _eel_strlen(void *opaque, EEL_F *fmt_index)
1460{
1461 if (opaque)
1462 {
1465 const char *fmt = EEL_STRING_GET_FOR_INDEX(*fmt_index,&wr);
1466 if (wr) return (EEL_F) wr->GetLength();
1467 if (fmt) return (EEL_F) strlen(fmt);
1468 }
1469 return 0.0;
1470}
1471
1472
1473
1474
1475static EEL_F NSEEL_CGEN_CALL _eel_printf(void *opaque, INT_PTR num_param, EEL_F **parms)
1476{
1477 if (num_param>0 && opaque)
1478 {
1481 const char *fmt = EEL_STRING_GET_FOR_INDEX(*(parms[0]),&wr_src);
1482 if (fmt)
1483 {
1484 char buf[16384];
1485 const int len = eel_format_strings(opaque,fmt,wr_src?(fmt+wr_src->GetLength()):NULL,buf,(int)sizeof(buf), (int)num_param-1, parms+1);
1486
1487 if (len >= 0)
1488 {
1489#ifdef EEL_STRING_STDOUT_WRITE
1490 EEL_STRING_STDOUT_WRITE(buf,len);
1491#endif
1492 return 1.0;
1493 }
1494 else
1495 {
1496#ifdef EEL_STRING_DEBUGOUT
1497 EEL_STRING_DEBUGOUT("printf: bad format string %s",fmt);
1498#endif
1499 }
1500 }
1501 else
1502 {
1503#ifdef EEL_STRING_DEBUGOUT
1504 EEL_STRING_DEBUGOUT("printf: bad format specifier passed %f",*(parms[0]));
1505#endif
1506 }
1507 }
1508 return 0.0;
1509}
1510
1511
1512
1513static EEL_F NSEEL_CGEN_CALL _eel_match(void *opaque, INT_PTR num_parms, EEL_F **parms)
1514{
1515 if (opaque && num_parms >= 2)
1516 {
1518 EEL_STRING_STORAGECLASS *fmt_wr=NULL, *msg_wr=NULL;
1519 const char *fmt = EEL_STRING_GET_FOR_INDEX(*(parms[0]),&fmt_wr);
1520 const char *msg = EEL_STRING_GET_FOR_INDEX(*(parms[1]),&msg_wr);
1521
1522 if (fmt && msg) return eel_string_match(opaque,fmt,msg,0,0, fmt + (fmt_wr?fmt_wr->GetLength():strlen(fmt)), msg + (msg_wr?msg_wr->GetLength():strlen(msg)),(int)num_parms-2,parms+2) ? 1.0 : 0.0;
1523 }
1524 return 0.0;
1525}
1526static EEL_F NSEEL_CGEN_CALL _eel_matchi(void *opaque, INT_PTR num_parms, EEL_F **parms)
1527{
1528 if (opaque && num_parms >= 2)
1529 {
1531 EEL_STRING_STORAGECLASS *fmt_wr=NULL, *msg_wr=NULL;
1532 const char *fmt = EEL_STRING_GET_FOR_INDEX(*(parms[0]),&fmt_wr);
1533 const char *msg = EEL_STRING_GET_FOR_INDEX(*(parms[1]),&msg_wr);
1534
1535 if (fmt && msg) return eel_string_match(opaque,fmt,msg,0,1, fmt + (fmt_wr?fmt_wr->GetLength():strlen(fmt)), msg + (msg_wr?msg_wr->GetLength():strlen(msg)),(int)num_parms-2,parms+2) ? 1.0 : 0.0;
1536 }
1537 return 0.0;
1538}
1539
1541{
1543
1548
1554 NSEEL_addfunc_exparms("strcpy_from",3,NSEEL_PProc_THIS,&_eel_strcpysubstr); // alias
1555 NSEEL_addfunc_exparms("strcpy_substr",3,NSEEL_PProc_THIS,&_eel_strcpysubstr); // only allow 3 or 4 parms
1557
1562
1565
1568
1571
1572}
1577
1578#ifdef EEL_WANT_DOCUMENTATION
1579static const char *eel_strings_function_reference =
1580#ifdef EEL_STRING_STDOUT_WRITE
1581"printf\t\"format\"[, ...]\tOutput formatted string to system-specific destination, see sprintf() for more information\0"
1582#endif
1583"sprintf\t#dest,\"format\"[, ...]\tFormats a string and stores it in #dest. Format specifiers begin with %, and may include:\3\n"
1584 "\4 %% = %\n"
1585 "\4 %s = string from parameter\n"
1586 "\4 %d = parameter as integer\n"
1587 "\4 %i = parameter as integer\n"
1588 "\4 %u = parameter as unsigned integer\n"
1589 "\4 %x = parameter as hex (lowercase) integer\n"
1590 "\4 %X = parameter as hex (uppercase) integer\n"
1591 "\4 %c = parameter as character\n"
1592 "\4 %f = parameter as floating point\n"
1593 "\4 %e = parameter as floating point (scientific notation, lowercase)\n"
1594 "\4 %E = parameter as floating point (scientific notation, uppercase)\n"
1595 "\4 %g = parameter as floating point (shortest representation, lowercase)\n"
1596 "\4 %G = parameter as floating point (shortest representation, uppercase)\n"
1597 "\2\n"
1598 "Many standard C printf() modifiers can be used, including:\3\n"
1599 "\4 %.10s = string, but only print up to 10 characters\n"
1600 "\4 %-10s = string, left justified to 10 characters\n"
1601 "\4 %10s = string, right justified to 10 characters\n"
1602 "\4 %+f = floating point, always show sign\n"
1603 "\4 %.4f = floating point, minimum of 4 digits after decimal point\n"
1604 "\4 %10d = integer, minimum of 10 digits (space padded)\n"
1605 "\4 %010f = integer, minimum of 10 digits (zero padded)\n"
1606 "\2\n"
1607 "Values for format specifiers can be specified as additional parameters to sprintf, or within {} in the format specifier (such as %{varname}d, in that case a global variable is always used).\0"
1608
1609 "matchi\t\"needle\",\"haystack\"[, ...]\tCase-insensitive version of match().\0"
1610 "match\t\"needle\",\"haystack\"[, ...]\tSearches for the first parameter in the second parameter, using a simplified regular expression syntax.\3\n"
1611 "\4* = match 0 or more characters\n"
1612 "\4*? = match 0 or more characters, lazy\n"
1613 "\4+ = match 1 or more characters\n"
1614 "\4+? = match 1 or more characters, lazy\n"
1615 "\4? = match one character\n"
1616 "\2\n"
1617 "You can also use format specifiers to match certain types of data, and optionally put that into a variable:\3\n"
1618 "\4%s means 1 or more chars\n"
1619 "\4%0s means 0 or more chars\n"
1620 "\4%5s means exactly 5 chars\n"
1621 "\4%5-s means 5 or more chars\n"
1622 "\4%-10s means 1-10 chars\n"
1623 "\4%3-5s means 3-5 chars\n"
1624 "\4%0-5s means 0-5 chars\n"
1625 "\4%x, %d, %u, and %f are available for use similarly\n"
1626 "\4%c can be used, but can't take any length modifiers\n"
1627 "\4Use uppercase (%S, %D, etc) for lazy matching\n"
1628 "\2\n"
1629 "See also sprintf() for other notes, including specifying direct variable references via {}.\0"
1630
1631 "strlen\t\"str\"\tReturns the length of the string passed as a parameter\0"
1632 "strcpy\t#str,\"srcstr\"\tCopies the contents of srcstr to #str, and returns #str\0"
1633 "strcat\t#str,\"srcstr\"\tAppends srcstr to #str, and returns #str\0"
1634 "strcmp\t\"str\",\"str2\"\tCompares strings, returning 0 if equal\0"
1635 "stricmp\t\"str\",\"str2\"\tCompares strings ignoring case, returning 0 if equal\0"
1636 "strncmp\t\"str\",\"str2\",maxlen\tCompares strings giving up after maxlen characters, returning 0 if equal\0"
1637 "strnicmp\t\"str\",\"str2\",maxlen\tCompares strings giving up after maxlen characters, ignoring case, returning 0 if equal\0"
1638 "strncpy\t#str,\"srcstr\",maxlen\tCopies srcstr to #str, stopping after maxlen characters. Returns #str.\0"
1639 "strncat\t#str,\"srcstr\",maxlen\tAppends srcstr to #str, stopping after maxlen characters of srcstr. Returns #str.\0"
1640 "strcpy_from\t#str,\"srcstr\",offset\tCopies srcstr to #str, but starts reading srcstr at offset offset\0"
1641 "strcpy_substr\t#str,\"srcstr\",offs,ml)\tPHP-style (start at offs, offs<0 means from end, ml for maxlen, ml<0 = reduce length by this amt)\0"
1642 "str_getchar\t\"str\",offset[,type]\tReturns the data at byte-offset offset of str. If offset is negative, position is relative to end of string."
1643 "type defaults to signed char, but can be specified to read raw binary data in other formats (note the single quotes, these are single/multi-byte characters):\3\n"
1644 "\4'c' - signed char\n"
1645 "\4'cu' - unsigned char\n"
1646 "\4's' - signed short\n"
1647 "\4'S' - signed short, big endian\n"
1648 "\4'su' - unsigned short\n"
1649 "\4'Su' - unsigned short, big endian\n"
1650 "\4'i' - signed int\n"
1651 "\4'I' - signed int, big endian\n"
1652 "\4'iu' - unsigned int\n"
1653 "\4'Iu' - unsigned int, big endian\n"
1654 "\4'f' - float\n"
1655 "\4'F' - float, big endian\n"
1656 "\4'd' - double\n"
1657 "\4'D' - double, big endian\n"
1658 "\2\0"
1659 "str_setchar\t#str,offset,val[,type])\tSets value at offset offset, type optional. offset may be negative to refer to offset relative to end of string, or between 0 and length, inclusive, and if set to length it will lengthen string. See str_getchar() for more information on types.\0"
1660 "str_setlen\t#str,len\tSets length of #str (if increasing, will be space-padded), and returns #str.\0"
1661 "str_delsub\t#str,pos,len\tDeletes len characters at offset pos from #str, and returns #str.\0"
1662 "str_insert\t#str,\"srcstr\",pos\tInserts srcstr into #str at offset pos. Returns #str\0"
1663;
1664#endif
1665
1666
1667#endif
1668
#define NULL
Definition CarlaBridgeFormat.cpp:30
uint8_t a
Definition Spc_Cpu.h:141
CAdPlugDatabase::CRecord::RecordType type
Definition adplugdb.cpp:93
Definition assocarray.h:320
VAL Get(KEY key, VAL notfound=0) const
Definition assocarray.h:328
int Insert(KEY key, VAL val)
Definition assocarray.h:53
Definition mutex.h:59
Definition ptrlist.h:40
PTRTYPE * Add(PTRTYPE *item)
Definition ptrlist.h:82
int GetSize(void) const
Definition ptrlist.h:58
Definition assocarray.h:376
EEL_F * GetVarForFormat(int formatidx)
Definition eel_strings.h:162
void clear_state(bool full)
Definition eel_strings.h:136
WDL_PtrList< EEL_STRING_STORAGECLASS > m_literal_strings
Definition eel_strings.h:231
WDL_AssocArray< const char *, EEL_F_PTR > m_varname_cache
Definition eel_strings.h:237
~eel_string_context_state()
Definition eel_strings.h:131
EEL_F * GetNamedVar(const char *s, bool createIfNotExists, EEL_F *altOut)
Definition eel_strings.h:168
int AddString(EEL_STRING_STORAGECLASS *ns)
Definition eel_strings.h:286
static EEL_F addNamedStringCallback(void *opaque, const char *name)
Definition eel_strings.h:244
WDL_PtrList< EEL_STRING_STORAGECLASS > m_unnamed_strings
Definition eel_strings.h:232
EEL_STRING_STORAGECLASS * m_user_strings[EEL_STRING_MAX_USER_STRINGS]
Definition eel_strings.h:236
const char * GetStringForIndex(EEL_F val, EEL_STRING_STORAGECLASS **stringContainerOut=NULL, bool is_for_write=false)
Definition eel_strings.h:198
eel_string_context_state()
Definition eel_strings.h:126
NSEEL_VMCTX m_vm
Definition eel_strings.h:239
WDL_PtrList< EEL_STRING_STORAGECLASS > m_named_strings
Definition eel_strings.h:233
static int cmpistr(const char **a, const char **b)
Definition eel_strings.h:124
void update_named_vars(NSEEL_VMCTX vm)
Definition eel_strings.h:154
static EEL_F addStringCallback(void *opaque, struct eelStringSegmentRec *list)
Definition eel_strings.h:270
WDL_StringKeyedArray< int > m_named_strings_names
Definition eel_strings.h:234
static int varEnumProc(const char *name, EEL_F *val, void *ctx)
Definition eel_strings.h:306
int * l
Definition inflate.c:1579
G bb
Definition inflate.c:1057
unsigned v[N_MAX]
Definition inflate.c:1584
unsigned ml
Definition inflate.c:944
unsigned bl
Definition inflate.c:935
unsigned s
Definition inflate.c:1555
unsigned x[BMAX+1]
Definition inflate.c:1586
#define NSEEL_addfunc_varparm(name, min_np, pproc, fptr)
Definition eel_import.h:63
#define NSEEL_addfunc_exparms(name, np, pproc, fptr)
Definition eel_import.h:67
void(* NSEEL_VM_SetStringFunc)(NSEEL_VMCTX ctx, EEL_F(*onString)(void *caller_this, struct eelStringSegmentRec *list), EEL_F(*onNamedString)(void *caller_this, const char *name))
Definition eel_import.h:32
EEL_F *(* nseel_int_register_var)(compileContext *ctx, const char *name, int isReg, const char **namePtrOut)
Definition eel_import.h:21
int(* nseel_stringsegments_tobuf)(char *bufOut, int bufout_sz, struct eelStringSegmentRec *list)
Definition eel_import.h:37
#define NSEEL_addfunc_retval(name, np, pproc, fptr)
Definition eel_import.h:51
void(* NSEEL_VM_enumallvars)(NSEEL_VMCTX ctx, int(*func)(const char *name, EEL_F *val, void *ctx), void *userctx)
Definition eel_import.h:22
void *(* NSEEL_PProc_THIS)(void *data, int data_size, struct _compileContext *ctx)
Definition eel_import.h:40
static EEL_F NSEEL_CGEN_CALL _eel_strinsert(void *opaque, EEL_F *strOut, EEL_F *fmt_index, EEL_F *pos)
Definition eel_strings.h:1335
static EEL_F eel_getchar_do(int flag, const char *src)
Definition eel_strings.h:1179
static EEL_F NSEEL_CGEN_CALL _eel_strcpysubstr(void *opaque, INT_PTR nparm, EEL_F **parms)
Definition eel_strings.h:878
void EEL_string_register()
Definition eel_strings.h:1540
static EEL_F NSEEL_CGEN_CALL _eel_strncat(void *opaque, EEL_F *strOut, EEL_F *fmt_index, EEL_F *maxlen)
Definition eel_strings.h:829
static void eel_setchar_do(int flag, char *dest, EEL_F val)
Definition eel_strings.h:1136
#define EEL_STRING_GETFMTVAR(x)
Definition eel_strings.h:104
#define EEL_STRING_GETNAMEDVAR(x, createOK, altOut)
Definition eel_strings.h:108
static EEL_F NSEEL_CGEN_CALL _eel_strdelsub(void *opaque, EEL_F *strOut, EEL_F *pos, EEL_F *len)
Definition eel_strings.h:1398
static int eel_getchar_flag(int type)
Definition eel_strings.h:1110
#define EEL_STRING_UNNAMED_BASE
Definition eel_strings.h:81
static EEL_F NSEEL_CGEN_CALL _eel_strcmp(void *opaque, EEL_F *strOut, EEL_F *fmt_index)
Definition eel_strings.h:1072
static EEL_F NSEEL_CGEN_CALL _eel_printf(void *opaque, INT_PTR num_param, EEL_F **parms)
Definition eel_strings.h:1475
#define EEL_GETCHAR_FLAG_UNSIGNED
Definition eel_strings.h:1108
static EEL_F NSEEL_CGEN_CALL _eel_stricmp(void *opaque, EEL_F *strOut, EEL_F *fmt_index)
Definition eel_strings.h:1077
static EEL_F NSEEL_CGEN_CALL _eel_match(void *opaque, INT_PTR num_parms, EEL_F **parms)
Definition eel_strings.h:1513
#define EEL_STRING_GET_FOR_WRITE(x, wr)
Definition eel_strings.h:100
#define EEL_STRING_LITERAL_BASE
Definition eel_strings.h:71
static EEL_F NSEEL_CGEN_CALL _eel_strncpy(void *opaque, EEL_F *strOut, EEL_F *fmt_index, EEL_F *maxlen)
Definition eel_strings.h:941
static int eel_validate_format_specifier(const char *fmt_in, char *typeOut, char *fmtOut, int fmtOut_sz, char *varOut, int varOut_sz, int *varOut_used)
Definition eel_strings.h:316
void eel_string_initvm(NSEEL_VMCTX vm)
Definition eel_strings.h:1573
#define EEL_STRING_GET_FOR_INDEX(x, wr)
Definition eel_strings.h:96
static EEL_F NSEEL_CGEN_CALL _eel_strnicmp(void *opaque, EEL_F *aa, EEL_F *bb, EEL_F *maxlen)
Definition eel_strings.h:1036
#define EEL_STRING_STORAGECLASS
Definition eel_strings.h:116
#define EEL_STRING_NAMED_BASE
Definition eel_strings.h:76
static EEL_F NSEEL_CGEN_CALL _eel_sprintf(void *opaque, INT_PTR num_param, EEL_F **parms)
Definition eel_strings.h:782
#define EEL_GETCHAR_FLAG_ENDIANSWAP
Definition eel_strings.h:1107
static int eel_string_match(void *opaque, const char *fmt, const char *msg, int match_fmt_pos, int ignorecase, const char *fmt_endptr, const char *msg_endptr, int num_fmt_parms, EEL_F **fmt_parms)
Definition eel_strings.h:516
static EEL_F NSEEL_CGEN_CALL _eel_matchi(void *opaque, INT_PTR num_parms, EEL_F **parms)
Definition eel_strings.h:1526
static EEL_F NSEEL_CGEN_CALL _eel_strncmp(void *opaque, EEL_F *aa, EEL_F *bb, EEL_F *maxlen)
Definition eel_strings.h:1011
static EEL_F NSEEL_CGEN_CALL _eel_strgetchar2(void *opaque, INT_PTR np, EEL_F **parms)
Definition eel_strings.h:1221
#define EEL_STRING_MAX_USER_STRINGS
Definition eel_strings.h:66
static EEL_F _eel_strcmp_int(const char *a, int a_len, const char *b, int b_len, int ml, bool ignorecase)
Definition eel_strings.h:982
static EEL_F NSEEL_CGEN_CALL _eel_strsetchar(void *opaque, EEL_F *strOut, EEL_F *idx, EEL_F *val)
Definition eel_strings.h:1295
static EEL_F NSEEL_CGEN_CALL _eel_strcpy(void *opaque, EEL_F *strOut, EEL_F *fmt_index)
Definition eel_strings.h:1066
#define EEL_STRING_MUTEXLOCK_SCOPE
Definition eel_strings.h:90
static EEL_F NSEEL_CGEN_CALL _eel_strcat(void *opaque, EEL_F *strOut, EEL_F *fmt_index)
Definition eel_strings.h:1061
int eel_format_strings(void *opaque, const char *fmt, const char *fmt_end, char *buf, int buf_sz, int num_fmt_parms, EEL_F **fmt_parms)
Definition eel_strings.h:402
static EEL_F NSEEL_CGEN_CALL _eel_strgetchar(void *opaque, EEL_F *strOut, EEL_F *idx)
Definition eel_strings.h:1083
static EEL_F NSEEL_CGEN_CALL _eel_strlen(void *opaque, EEL_F *fmt_index)
Definition eel_strings.h:1459
#define EEL_GETCHAR_FLAG_FLOAT
Definition eel_strings.h:1109
static EEL_F NSEEL_CGEN_CALL _eel_strsetchar2(void *opaque, INT_PTR np, EEL_F **parms)
Definition eel_strings.h:1250
static EEL_F NSEEL_CGEN_CALL _eel_strsetlen(void *opaque, EEL_F *strOut, EEL_F *newlen)
Definition eel_strings.h:1427
#define opaque
Definition eelscript.h:281
#define EEL_STRING_GET_CONTEXT_POINTER(opaque)
Definition eelscript.h:168
static const char * name
Definition pugl.h:1582
int val
Definition jpeglib.h:956
const char * msg
Definition missing_descriptor.c:20
struct _compileContext compileContext
#define NSEEL_CGEN_CALL
Definition ns-eel.h:44
void * NSEEL_VMCTX
Definition ns-eel.h:117
#define false
Definition ordinals.h:83
Definition eel_import.h:27
static WDL_Mutex m_mutex
Definition swell-ini.cpp:67
#define stricmp(x, y)
Definition swell-types.h:68
intptr_t INT_PTR
Definition swell-types.h:42
uch * p
Definition crypt.c:594
return c
Definition crypt.c:175
memcpy(hh, h, RAND_HEAD_LEN)
int r
Definition crypt.c:458
b
Definition crypt.c:628
fmt[0]
Definition fileio.c:2503
int flag
Definition unix.c:754
typedef int(UZ_EXP MsgFn)()
_WDL_CSTRING_PREFIX void lstrcpyn_safe(char *o, const char *in, INT_PTR count)
Definition wdlcstring.h:129
#define wdl_min(x, y)
Definition wdltypes.h:107
#define EEL_STRING_STDOUT_WRITE(x, len)
Definition ysfx_api_eel.cpp:30
#define EEL_STRING_MAXUSERSTRING_LENGTH_HINT
Definition ysfx_api_eel.cpp:35