1 /* Steven Andrews, 1/99
2 See documentation called string2_doc.doc
3 Copyright 2003-2007 by Steven Andrews. This work is distributed under the terms
4 of the Gnu Lesser General Public License (LGPL). */
5
6 #include <math.h>
7 #include <string.h>
8 #include <stdarg.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <ctype.h>
12 #include "random2.h"
13 #include "string2.h"
14
15 #ifndef NAN // NAN is defined in math.h, so should already be defined
16 #include <limits>
17 #define NAN std::numeric_limits<double>::quiet_NaN( );
18 #endif
19
20
21 /******************************************************************/
22 /************ Declarations for internal functions ****************/
23 /******************************************************************/
24
25 #define CHECKS(A,...) if(!(A)) {snprintf(StrErrorString,sizeof(StrErrorString),__VA_ARGS__); goto failure;} else (void)0
26 #define CHECK(A) if(!(A)) {goto failure;} else (void)0
27
28 char StrErrorString[STRCHAR];
29 int MathParseError=0;
30
31 int permutelex(int *seq,int n);
32 int allocresults(char ***resultsptr,int *maxrptr,int nchar);
33
34
35 /******************************************************************/
36 /******************* String classification ************************/
37 /******************************************************************/
38
39
40 /* strisnumber */
strisnumber(const char * str)41 int strisnumber(const char *str) {
42 char *ptr;
43 int len;
44
45 if(!(len=strlen(str))) return 0;
46 strtod(str,&ptr);
47 return(ptr==str+len); }
48
49
50 /* strokname */
strokname(const char * name)51 int strokname(const char *name) {
52 int ok;
53
54 ok=1;
55 ok=ok && isalpha(*name);
56 for(name++;*name && ok;name++)
57 ok=ok && (isalnum(*name) || *name=='_');
58 return ok; }
59
60
61 /* strhasname */
strhasname(const char * string,const char * name)62 int strhasname(const char *string,const char *name) {
63 int i,len;
64
65 len=strlen(name);
66 while(*string) {
67 for(i=0;i<len && *string==name[i];i++) string++;
68 if(i==len && (*string=='\0' || !(isalnum(*string) || *string=='_'))) return 1;
69 while(*string && (*string!=name[0] || isalnum(*(string-1)) || *(string-1)=='_')) string++; }
70 return 0; }
71
72
73 /* strbegin */
strbegin(const char * strshort,const char * strlong,int casesensitive)74 int strbegin(const char *strshort,const char *strlong,int casesensitive) {
75 int i;
76
77 i=0;
78 if(casesensitive)
79 while(strshort[i]!='\0' && strshort[i]==strlong[i]) i++;
80 else
81 while(strshort[i]!='\0' && tolower(strshort[i])==tolower(strlong[i])) i++;
82 if(strshort[i]=='\0' && i>0) return 1;
83 return 0; }
84
85
86 /* strsymbolcount */
strsymbolcount(const char * s,char c)87 int strsymbolcount(const char *s,char c) {
88 int n;
89
90 n=0;
91 for(;*s;s++)
92 if(*s==c) n++;
93 return n; }
94
95
96 /* strisfunctionform */
strisfunctionform(char * str,char ** parenptr)97 int strisfunctionform(char *str,char **parenptr) {
98 int i,len,ok;
99 char *ptr;
100
101 len=strlen(str);
102 if(len<3 || str[len-1]!=')') return 0;
103 if(!(ptr=strchr(str+1,'('))) return 0;
104
105 len=ptr-str;
106 ok=isalpha(*str);
107 for(i=1;i<len && ok;i++)
108 ok=isalnum(str[i]) || str[i]=='_';
109 if(parenptr) *parenptr=ptr;
110 return ok; }
111
112
113 /******************************************************************/
114 /*********************** Character locating ***********************/
115 /******************************************************************/
116
117
118 /* strchrindex */
strchrindex(const char * cs,char c,int i)119 int strchrindex(const char *cs,char c,int i) {
120 while(cs[i]!='\0') {
121 if(cs[i]==c) return i;
122 i++; }
123 return -1; }
124
125
126 /* strrpbrk */
strrpbrk(char * cs,const char * ct)127 char *strrpbrk(char *cs,const char *ct) {
128 char *s2;
129 int i,n;
130
131 if(!cs || !ct) return NULL;
132 n=strlen(ct);
133 for(s2=cs+strlen(cs)-1;s2>=cs;s2--)
134 for(i=0;i<n;i++)
135 if(*s2==ct[i]) return s2;
136 return NULL; }
137
138
139 /* StrChrQuote */
StrChrQuote(char * cs,char c)140 char *StrChrQuote(char *cs,char c) {
141 int qt;
142
143 qt=0;
144 for(;*cs;cs++) {
145 if(*cs=='"') qt=!qt;
146 else if(*cs==c && !qt) return cs; }
147 return NULL; }
148
149
150 /* StrChrPQuote */
StrChrPQuote(const char * cs,char c)151 int StrChrPQuote(const char *cs,char c) {
152 unsigned int i,pn,qt;
153
154 pn=qt=0;
155 for(i=0;i<strlen(cs);i++)
156 if(cs[i]=='"') qt=!qt;
157 else if(cs[i]==c && !qt && !pn) return i;
158 else if(cs[i]=='(' && !qt) pn++;
159 else if(cs[i]==')' && !qt && pn) pn--;
160 else if(cs[i]==')' && !qt) return -2;
161 if(pn) return -2;
162 if(qt) return -3;
163 return -1; }
164
165
166 /* StrrChrPQuote */
StrrChrPQuote(const char * cs,char c)167 int StrrChrPQuote(const char *cs,char c) {
168 int i,pn,qt;
169
170 pn=qt=0;
171 for(i=strlen(cs)-1;i>=0;i--)
172 if(cs[i]=='"') qt=!qt;
173 else if(cs[i]==c && !qt && !pn) return i;
174 else if(cs[i]==')' && !qt) pn++;
175 else if(cs[i]=='(' && !qt && pn) pn--;
176 else if(cs[i]=='(' && !qt) return -2;
177 if(pn) return -2;
178 if(qt) return -3;
179 return -1; }
180
181
182 /* strChrBrackets */
strChrBrackets(const char * string,int n,char c,const char * delimit)183 int strChrBrackets(const char *string,int n,char c,const char *delimit) {
184 int i,pn,bk,bc,qt,sq,ckpn,ckbk,ckbc,ckqt,cksq;
185 char ch;
186
187 pn=bk=bc=qt=sq=0;
188 ckpn=strchr(delimit,'(')?1:0;
189 ckbk=strchr(delimit,'[')?1:0;
190 ckbc=strchr(delimit,'{')?1:0;
191 ckqt=strchr(delimit,'"')?1:0;
192 cksq=strchr(delimit,'\'')?1:0;
193 if(n<0)
194 n=strlen(string);
195
196 for(i=0;i<n;i++) {
197 ch=string[i];
198 if(ch==c) {
199 if(pn!=0 || bk!=0 || bc!=0 || qt!=0 || sq!=0);
200 else return i; }
201 else if(ckpn && ch=='(') pn++;
202 else if(ckbk && ch=='[') bk++;
203 else if(ckbc && ch=='{') bc++;
204 else if(ckqt && ch=='"') qt=!qt;
205 else if(cksq && ch=='\'') sq=!sq;
206 else if(ckpn && ch==')') {if(--pn<0) return -2;}
207 else if(ckbk && ch==']') {if(--bk<0) return -3;}
208 else if(ckbc && ch=='}') {if(--bc<0) return -4;} }
209
210 return -1; }
211
212
213 /* strPbrkBrackets */
strPbrkBrackets(const char * string,int n,const char * c,const char * delimit,int imin)214 int strPbrkBrackets(const char *string,int n,const char *c,const char *delimit,int imin) {
215 int i,pn,bk,bc,qt,sq,ckpn,ckbk,ckbc,ckqt,cksq;
216 char ch;
217
218 pn=bk=bc=qt=sq=0;
219 ckpn=strchr(delimit,'(')?1:0;
220 ckbk=strchr(delimit,'[')?1:0;
221 ckbc=strchr(delimit,'{')?1:0;
222 ckqt=strchr(delimit,'"')?1:0;
223 cksq=strchr(delimit,'\'')?1:0;
224 if(n<0)
225 n=strlen(string);
226
227 for(i=0;i<n;i++) {
228 ch=string[i];
229 if(strchr(c,ch)) {
230 if(pn!=0 || bk!=0 || bc!=0 || qt!=0 || sq!=0 || i<imin);
231 else return i; }
232 else if(ckpn && ch=='(') pn++;
233 else if(ckbk && ch=='[') bk++;
234 else if(ckbc && ch=='{') bc++;
235 else if(ckqt && ch=='"') qt=!qt;
236 else if(cksq && ch=='\'') sq=!sq;
237 else if(ckpn && ch==')') {if(--pn<0) return -2;}
238 else if(ckbk && ch==']') {if(--bk<0) return -3;}
239 else if(ckbc && ch=='}') {if(--bc<0) return -4;} }
240
241 return -1; }
242
243
244 /* strparenmatch */
strparenmatch(const char * string,int index)245 int strparenmatch(const char *string,int index) {
246 char ch1,ch2;
247 int dir,i,count;
248
249 ch1=string[index];
250 if(ch1=='(') {dir=1;ch2=')';}
251 else if(ch1=='[') {dir=1;ch2=']';}
252 else if(ch1=='{') {dir=1;ch2='}';}
253 else if(ch1==')') {dir=-1;ch2='(';}
254 else if(ch1==']') {dir=-1;ch2='[';}
255 else if(ch1=='}') {dir=-1;ch2='{';}
256 else return -1;
257
258 i=index+dir;
259 count=0;
260 for(;;) {
261 while(i>=0 && string[i]!='\0' && string[i]!=ch1 && string[i]!=ch2) i+=dir;
262 if(i<0 || string[i]=='\0') return -2;
263 if(string[i]==ch1) count++;
264 else if(count==0) return i;
265 else count--;
266 i+=dir; }
267 return 0; }
268
269
270 /* strsymbolmatch */
strsymbolmatch(char * str1,char * str2,const char * symbols)271 int strsymbolmatch(char *str1,char *str2,const char *symbols) {
272 char *s1,*s2;
273
274 s1=str1;
275 s2=str2;
276 while(1) {
277 s1=strpbrk(s1,symbols);
278 s2=strpbrk(s2,symbols);
279 if(!s1 && !s2) return 1;
280 if(!s1 || !s2) return 0;
281 if(*s1!=*s2) return 0;
282 s1++;
283 s2++; }
284 return 0; }
285
286
287
288 /******************************************************************/
289 /************************* Word operations ************************/
290 /******************************************************************/
291
292
293 /* wordcount */
wordcount(const char * s)294 int wordcount(const char *s) {
295 int n,sp;
296 const char *s2;
297
298 n=0;
299 sp=1;
300 for(s2=s;*s2;s2++) {
301 if(sp && !isspace(*s2)) n++;
302 sp=isspace(*s2); }
303 return n; }
304
305
306 /* wordcountpbrk */
wordcountpbrk(const char * s,const char * symbols)307 int wordcountpbrk(const char *s,const char *symbols) {
308 int n,sp,ischar;
309 const char *s2;
310
311 n=0;
312 sp=1;
313 ischar=0;
314 for(s2=s;*s2;s2++) {
315 if(sp && (ischar=!strchr(symbols,*s2))) n++;
316 sp=!ischar; }
317 return n; }
318
319
320 /* strwhichword */
strwhichword(const char * s,const char * end)321 int strwhichword(const char *s,const char *end) {
322 int n,sp;
323 const char *s2;
324
325 n=0;
326 sp=1;
327 for(s2=s;*s2 && s2!=end+1;s2++) {
328 if(sp && !isspace(*s2)) n++;
329 sp=isspace(*s2); }
330 return n; }
331
332
333 /* strnword */
strnword(char * s,int n)334 char *strnword(char *s,int n) {
335 char *s2;
336
337 if(!s) return NULL;
338 s2=s;
339 if(!isspace(*s)) n--;
340 for(;n>0 && *s2;n--) {
341 while(!isspace(*s2) && *s2) s2++;
342 while(isspace(*s2)) s2++; }
343 return *s2?s2:NULL; }
344
345
346 /* strnwordc */
strnwordc(const char * s,int n)347 const char *strnwordc(const char *s,int n) {
348 const char *s2;
349
350 if(!s) return NULL;
351 s2=s;
352 if(!isspace(*s)) n--;
353 for(;n>0 && *s2;n--) {
354 while(!isspace(*s2) && *s2) s2++;
355 while(isspace(*s2)) s2++; }
356 return *s2?s2:NULL; }
357
358
359 /* strnword1 */
strnword1(char * s,int n)360 char *strnword1(char *s,int n) {
361 char *s2;
362
363 if(!s) return NULL;
364 s2=s;
365 for(n--;n>0 && *s2;n--) {
366 while(*s2 && *s2!=' ' && *s2!='\t') s2++;
367 if(*s2) s2++; }
368 if(*s2==' ' || *s2=='\t' || !*s2) return NULL;
369 else return s2;}
370
371
372 /* strnwordend */
strnwordend(char * s,int n)373 char *strnwordend(char *s,int n) {
374 char *s2;
375
376 if(!s) return NULL;
377 s2=s;
378 for(;n>0 && *s2;n--) {
379 while(isspace(*s2)) s2++;
380 while(!isspace(*s2) && *s2) s2++; }
381 return n==0?s2:NULL; }
382
383
384 /* strwordcpy */
strwordcpy(char * destination,const char * source,int n)385 char *strwordcpy(char *destination,const char *source,int n) {
386 int i;
387
388 i=0;
389 while(n) {
390 while(isspace(source[i])) {
391 destination[i]=source[i];
392 i++; }
393 while(!isspace(source[i])) {
394 destination[i]=source[i];
395 i++; }
396 n--; }
397
398 if(i>0 && destination[i-1]!='\0')
399 destination[i]='\0';
400
401 return destination; }
402
403
404 /******************************************************************/
405 /************************** String arrays *************************/
406 /******************************************************************/
407
408
409 /* stringfind */
410 // C++ supports const in nested lists but C does not
411 #ifdef __GNUG__
stringfind(const char * const * slist,int n,const char * s)412 int stringfind(const char * const *slist,int n,const char *s) {
413 #else
414 int stringfind(char **slist,int n,const char *s) {
415 #endif
416 int i;
417
418 for(i=0;i<n && strcmp(slist[i],s);i++);
419 return i<n?i:-1; }
420
421
422 /* stringnfind */
423 // C++ supports const in nested lists but C does not
424 #ifdef __GNUG__
425 int stringnfind(const char * const *slist,int n,const char *s,int nchar) {
426 #else
427 int stringnfind(char **slist,int n,const char *s,int nchar) {
428 #endif
429 int i;
430
431 for(i=0;i<n && strncmp(slist[i],s,nchar);i++);
432 return i<n?i:-1; }
433
434
435 /******************************************************************/
436 /**************** Reading sequential items from strings ***********/
437 /******************************************************************/
438
439
440 /* strreadni */
441 int strreadni(char *s,int n,int *a,char **endp) {
442 int i,ok;
443 char *s2;
444
445 s2=s;
446 ok=1;
447 for(i=0;i<n && ok;i++) {
448 a[i]=(int) strtol(s,&s2,10);
449 if(s2==s) ok=0;
450 s=s2; }
451 if(endp) *endp=s2;
452 return ok?i:i-1; }
453
454
455 /* strreadnli */
456 int strreadnli(char *s,int n,long int *a,char **endp) {
457 int i,ok;
458 char *s2;
459
460 s2=s;
461 ok=1;
462 for(i=0;i<n && ok;i++) {
463 a[i]=(long int) strtol(s,&s2,10);
464 if(s2==s) ok=0;
465 s=s2; }
466 if(endp) *endp=s2;
467 return ok?i:i-1; }
468
469
470 /* strreadnf */
471 int strreadnf(char *s,int n,float *a,char **endp) {
472 int i,ok;
473 char *s2;
474
475 s2=s;
476 ok=1;
477 for(i=0;i<n && ok;i++) {
478 a[i]=(float) strtod(s,&s2);
479 if(s2==s) ok=0;
480 s=s2; }
481 if(endp) *endp=s2;
482 return ok?i:i-1; }
483
484
485 /* strreadnd */
486 int strreadnd(char *s,int n,double *a,char **endp) {
487 int i,ok;
488 char *s2;
489
490 s2=s;
491 ok=1;
492 for(i=0;i<n && ok;i++) {
493 a[i]=strtod(s,&s2);
494 if(s2==s) ok=0;
495 s=s2; }
496 if(endp) *endp=s2;
497 return ok?i:i-1; }
498
499
500 /* strreadns */
501 int strreadns(char *s,int n,char **a,char **endp) {
502 int i,j;
503 char *s2;
504
505 s2=s;
506 j=1;
507 for(i=0;i<n && *s2;i++) {
508 while(isspace(*s2)) s2++;
509 for(j=0;!isspace(*s2) && *s2;j++) a[i][j]=*(s2++);
510 if(j) a[i][j]='\0'; }
511 if(endp) *endp=s2;
512 return j?i:i-1; }
513
514
515 /******************************************************************/
516 /************ String copying with memory allocation ***************/
517 /******************************************************************/
518
519
520 /* EmptyString */
521 char *EmptyString() {
522 char *s;
523 int i;
524
525 s=(char*) calloc(STRCHAR,sizeof(char));
526 if(s) for(i=0;i<STRCHAR;i++) s[i]='\0';
527 return s; }
528
529
530 /* StringCopy */
531 char *StringCopy(const char *s) {
532 char *s2;
533 int i;
534
535 s2=(char *) calloc(strlen(s)+1,sizeof(char));
536 if(!s2) return NULL;
537 for(i=0;s[i];i++) s2[i]=s[i];
538 s2[i]='\0';
539 return s2; }
540
541
542 /* PascalString */
543 unsigned char *PascalString(const char *s) {
544 unsigned char *s2;
545 int i;
546
547 s2=(unsigned char *) calloc(strlen(s)+1,sizeof(unsigned char));
548 if(!s2) return 0;
549 for(i=0;s[i];i++) s2[i+1]=s[i];
550 s2[0]=(unsigned char) i;
551 return s2; }
552
553
554 /******************************************************************/
555 /************ String modifying without memory allocation **********/
556 /******************************************************************/
557
558
559 /* strPreCat */
560 char *strPreCat(char *str,const char *cat,int start,int stop) {
561 int i,n,len;
562
563 n=stop-start;
564 len=strlen(str);
565 for(i=len+n;i>=n;i--) str[i]=str[i-n];
566 for(;i>=0;i--) str[i]=cat[start+i];
567 return str; }
568
569
570 /* strPostCat */
571 char *strPostCat(char *str,const char *cat,int start,int stop) {
572 int i,n,len;
573
574 n=stop-start;
575 len=strlen(str);
576 for(i=0;i<n;i++) str[len+i]=cat[start+i];
577 str[len+i]='\0';
578 return str; }
579
580
581 /* strMidCat */
582 char *strMidCat(char *str,int s1,int s2,const char *cat,int start,int stop) {
583 int i,n,len,shift;
584
585 if(stop<0) stop=strlen(cat);
586 n=stop-start;
587 shift=n-(s2-s1);
588 len=strlen(str);
589 if(shift>0)
590 for(i=len+shift;i>=s2+shift;i--) str[i]=str[i-shift];
591 else if(shift<0)
592 for(i=s2+shift;i<=len+shift;i++) str[i]=str[i-shift];
593 for(i=0;i<n;i++) str[i+s1]=cat[start+i];
594 return str; }
595
596
597 /* strchrreplace */
598 int strchrreplace(char *str,char charfrom,char charto) {
599 int n;
600 char *s1;
601
602 n=0;
603 while((s1=strchr(str,charfrom))) {
604 *s1=charto;
605 n++; }
606 return n; }
607
608
609 /* strstrreplace */
610 int strstrreplace(char *str,const char *strfrom,const char *strto,int max) {
611 int n,diff,lento,lenfrom,over;
612 char *s1,*s2;
613 int i,j;
614
615 if(strto) lento=strlen(strto);
616 else lento=0;
617 lenfrom=strlen(strfrom);
618 diff=lento-lenfrom;
619 over=0;
620 n=0;
621 s2=str;
622 while((s1=strstr(s2,strfrom))) {
623 i=s1-str;
624 if(diff<0) {
625 for(j=i+lenfrom;str[j-1] && j<max;j++)
626 str[j+diff]=str[j]; }
627 else if(diff>0) {
628 for(j=strlen(str);j>=i+lenfrom;j--)
629 if(j+diff<max) str[j+diff]=str[j];
630 else over=1; }
631 for(j=0;j<lento;j++)
632 if(i+j<max) str[i+j]=strto[j];
633 else over=1;
634 if(i+lento<max) s2=s1+lento;
635 else s2=str+strlen(str);
636 n++; }
637 if(over) return -n;
638 return n; }
639
640
641 /* strcutwhite */
642 void strcutwhite(char *str,int end) {
643 int i,j;
644
645 if(end&2) { // end of string
646 for(i=strlen(str)-1;i>=0 && isspace(str[i]);i--);
647 str[i+1]='\0'; }
648 if(end&1) { // start of string
649 for(i=0;str[i]!='\0' && isspace(str[i]);i++);
650 j=0;
651 for(;str[i]!='\0';i++) str[j++]=str[i];
652 str[j]='\0'; }
653 return; }
654
655
656 /* strbslash2escseq */
657 int strbslash2escseq(char *str) {
658 char *s1,*s2;
659
660 s1=s2=str;
661 while(*s2) {
662 if(*s2=='\\') {
663 s2++;
664 if(*s2=='a') *s1='\a';
665 else if(*s2=='b') *s1='\b';
666 else if(*s2=='t') *s1='\t';
667 else if(*s2=='n') *s1='\n';
668 else if(*s2=='v') *s1='\v';
669 else if(*s2=='f') *s1='\f';
670 else if(*s2=='r') *s1='\r';
671 else if(*s2=='\\') *s1='\\';
672 else if(*s2=='"') *s1='\"';
673 else *s1='\\'; }
674 else
675 *s1=*s2;
676 s1++;
677 s2++; }
678 *s1=*s2;
679 return s2-s1; }
680
681
682 /******************************************************************/
683 /**************************** Wildcards ***************************/
684 /******************************************************************/
685
686
687 /* strcharlistmatch */
688 int strcharlistmatch(const char *pat,const char ch,int n) {
689 int p;
690
691 if(n<0) n=strlen(pat);
692 for(p=0;p<n;p++) {
693 if(pat[p]=='-') { // initial -
694 if(p+1==n) return 1; // only -
695 if(ch<=pat[p+1]) return 1; // match initial -
696 p++; }
697 else if(p+1<n && pat[p+1]=='-') { // internal or terminal -
698 if(p+2==n) { // terminal -
699 if(ch>=pat[p]) return 1; // terminal - match
700 return 0; } // terminal - no match
701 if(ch>=pat[p] && ch<=pat[p+2]) return 1; // internal - match
702 p+=2; }
703 else if(pat[p]==ch) return 1; } // character match
704 return 0; }
705
706
707 /* strwildcardmatch */
708 int strwildcardmatch(const char *pat,const char *str) {
709 int s,p,s1,p1,match,blen,brend;
710
711 p1=s1=-1;
712 s=p=0;
713 while(str[s]) {
714 if(pat[p]=='*') { // star found in pat
715 if(!pat[p+1]) return 1; // terminal star, so this is a match
716 p++;
717 p1=p; // p and p1 are at '*'+1, where post-star text will resume
718 s1=s; } // s1 is at s, where any star text will start
719 else if(pat[p]=='?') {s++;p++;} // '?' wildcard character
720 else if(pat[p]=='[') { // character list or range
721 brend=strchrindex(pat,']',p);
722 if(brend==-1) return -1;
723 blen=brend-p-1;
724 match=strcharlistmatch(pat+p+1,str[s],blen);
725 if(match) {
726 s++;
727 p+=blen+2; }
728 else if(p1>=0) goto starlabel; // act as if this option weren't ever selected
729 else return 0; }
730 else if(pat[p]==str[s]) {s++;p++;} // same character
731 else if(p1>=0) { // in star text
732 starlabel:
733 if(p==p1) s++;
734 else {
735 p=p1;
736 s1++;
737 s=s1; }}
738 else return 0; } // no match
739 while(pat[p]=='*') p++;
740 if(!pat[p]) return 1; // match
741 return 0; } // more pattern, so no match
742
743
744 /* strwildcardmatchandsub */
745 int strwildcardmatchandsub(const char *pat,const char *str,char *dest,int starextra) {
746 int s,p,s1,p1,starpt,isub,nsub,isubstar,match,blen,d,brend,starxc;
747 int maxsub=16;
748 char subst[16][STRCHAR],patst[16][STRCHAR];
749
750 p1=s1=-1; // p1 and s1 are pat and str indicies following star text
751 p=s=0; // p and s are current pat and str indicies
752 starpt=0; // starpt is star start location in str
753 isub=0; // isub is current substitution string index
754 isubstar=0; // isubstar is substitution string index for most recent open star
755 starxc=0; // starxc is extra characters that were included in first star text
756 while(str[s]) { // walk through pat and str, determining if match and recording pattern and substitution strings
757 if(pat[p]=='*') {
758 if(p1>=0) { // resolve any open star
759 if(starxc<starextra) {
760 starxc++;
761 goto starlabel; }
762 if(isub==maxsub) return -6;
763 strncpy(subst[isubstar],str+starpt,s1-starpt);
764 subst[isubstar][s1-starpt]='\0';
765 strcpy(patst[isubstar],"**");
766 p1=-1; }
767 starpt=s; // point in str where star was reached
768 if(!pat[p+1]) { // terminal star
769 s=strlen(str);
770 if(isub==maxsub) return -6;
771 strncpy(subst[isub],str+starpt,s-starpt);
772 subst[isub][s-starpt]='\0';
773 strcpy(patst[isub],"**");
774 isub++;
775 p++; }
776 else { // new star, which is not terminal
777 isubstar=isub++;
778 p++;
779 p1=p;
780 s1=s; }}
781
782 else if(pat[p]=='?') { // '?' wildcard character
783 if(isub==maxsub) return -6;
784 subst[isub][0]=str[s];
785 subst[isub][1]='\0';
786 strcpy(patst[isub],"??");
787 isub++;
788 s++;
789 p++; }
790
791 else if(pat[p]=='[') { // character list or range
792 brend=strchrindex(pat,']',p);
793 if(brend==-1) return -7;
794 blen=brend-p-1; // length of text within brackets not including brackets
795 match=strcharlistmatch(pat+p+1,str[s],blen);
796 if(match) {
797 if(isub==maxsub) return -6;
798 subst[isub][0]=str[s];
799 subst[isub][1]='\0';
800 patst[isub][0]='[';
801 strncpy(patst[isub]+1,pat+p,blen+2);
802 patst[isub][blen+3]='\0';
803 isub++;
804 s++;
805 p+=blen+2; }
806 else if(p1>=0) goto starlabel; // act as if this option weren't ever selected
807 else return 0; } // bracket pattern doesn't match and no open star, so no match
808
809 else if(pat[p]==str[s]) { // same character
810 s++;
811 p++; }
812
813 else if(p1>=0) { // in star text
814 starlabel:
815 if(p==p1) { // str and pat still don't match so keep going
816 s++;
817 s1++; }
818 else { // str and pat did match but now don't, so try one larger star text
819 isub=isubstar+1;
820 p=p1;
821 s1++;
822 s=s1; }}
823
824 else return 0; } // no match
825
826 if(starxc<starextra) return 0; // doesn't qualify as match because extra characters weren't used
827
828 if(p1>=0) { // resolve any open star
829 if(isub==maxsub) return -6;
830 strncpy(subst[isubstar],str+starpt,s1-starpt);
831 subst[isubstar][s1-starpt]='\0';
832 strcpy(patst[isubstar],"**");
833 p1=-1; }
834 while(pat[p]=='*') { // any additional stars in pat represent no characters
835 if(isub==maxsub) return -6;
836 subst[isub][0]='\0';
837 strcpy(patst[isub],"**");
838 isub++;
839 p++; }
840 if(pat[p]) return 0; // more text remains in pat, so no match
841 nsub=isub;
842
843 // At this point, have returned 0 if no match; continuing if match. Have nsub substitutions, recorded in substr and subpat
844 // for(isub=0;isub<nsub;isub++) { // debug code
845 // printf("%i: pat='%s' subst='%s'\n",isub,patst[isub],subst[isub]); }
846
847 if(dest) { // perform substitutions
848 for(d=0;dest[d]!='\0';d++) {
849 if(dest[d]=='*') {
850 for(isub=0;isub<nsub && (patst[isub][0]=='x' || strcmp(patst[isub],"**"));isub++);
851 if(isub==nsub) return -9;
852 patst[isub][0]='x';
853 strMidCat(dest,d,d+1,subst[isub],0,-1); }
854 else if(dest[d]=='?') {
855 for(isub=0;isub<nsub && (patst[isub][0]=='x' || strcmp(patst[isub],"??"));isub++);
856 if(isub==nsub) return -9;
857 patst[isub][0]='x';
858 strMidCat(dest,d,d+1,subst[isub],0,-1); }
859 else if(dest[d]=='[') {
860 brend=strchrindex(dest,']',d);
861 if(brend==-1) return -8;
862 blen=brend-d-1;
863 for(isub=0;isub<nsub && (patst[isub][0]=='x' || strncmp(patst[isub]+1,dest+d,blen+2));isub++);
864 if(isub==nsub) return -9;
865 patst[isub][0]='x';
866 strMidCat(dest,d,d+blen+2,subst[isub],0,-1); }
867 else if(dest[d]=='$') {
868 if(!dest[d+1]) return -10;
869 isub=((int)dest[d+1])-((int)'1');
870 if(isub<0 || isub>nsub-1) return -10;
871 strMidCat(dest,d,d+2,subst[isub],0,-1); }}}
872
873 return 1; }
874
875
876 /* permutelex - internal function, duplicate of a Zn.c function */
877 int permutelex(int *seq,int n) {
878 int i,j;
879 int temp;
880
881 i=n-1;
882 while(i>0 && seq[i-1]>=seq[i]) i--;
883 if(i==0) { // input was final sequence
884 i=0;
885 j=n-1;
886 while(i<j) {
887 temp=seq[i]; // swap values at positions i and j
888 seq[i]=seq[j];
889 seq[j]=temp;
890 i++;
891 j--; }
892 return 2; }
893
894 j=n;
895 while(seq[j-1]<=seq[i-1]) j--;
896
897 temp=seq[i-1]; // swap values at positions (i-1) and (j-1)
898 seq[i-1]=seq[j-1];
899 seq[j-1]=temp;
900
901 i++;
902 j=n;
903 while(i<j) {
904 temp=seq[i-1]; // swap values at positions (i-1) and (j-1)
905 seq[i-1]=seq[j-1];
906 seq[j-1]=temp;
907 i++;
908 j--; }
909
910 i=n-1;
911 while(i>0 && seq[i-1]>=seq[i]) i--;
912 if(i==0) return 1; // at final sequence
913
914 return 0; }
915
916
917 /* allocresults - internal function used by strexpandlogic */
918 int allocresults(char ***resultsptr,int *maxrptr,int nchar) {
919 char **results,**newresults;
920 int maxr,newmaxr,i;
921
922 results=*resultsptr;
923 maxr=*maxrptr;
924 if(!results) maxr=0;
925
926 if(nchar<0) { // free memory
927 if(results) {
928 for(i=0;i<maxr;i++) free(results[i]);
929 free(results);
930 results=NULL; }
931 maxr=0; }
932
933 else { // expand current list or make new one
934 newmaxr=maxr*2+2;
935 newresults=(char **) calloc(newmaxr,sizeof(char*));
936 if(!newresults) return 1;
937 for(i=0;i<newmaxr;i++) newresults[i]=NULL;
938 for(i=0;i<newmaxr;i++) {
939 newresults[i]=(char*) calloc(nchar,sizeof(char));
940 if(!newresults[i]) return 1;
941 newresults[i][0]='\0'; }
942 for(i=0;i<maxr;i++) {
943 strncpy(newresults[i],results[i],nchar-1);
944 newresults[i][nchar-1]='\0'; }
945 allocresults(resultsptr,maxrptr,-1);
946 results=newresults;
947 maxr=newmaxr; }
948
949 *resultsptr=results;
950 *maxrptr=maxr;
951 return 0; }
952
953
954 /* strexpandlogic */
955 int strexpandlogic(const char *pat,int start,int stop,char ***resultsptr) {
956 char **results;
957 int isym,il,ir,lnum,rnum,i2,ires;
958 char **llist,**rlist;
959
960 results=*resultsptr=NULL;
961 if(stop<0) stop=strlen(pat);
962
963 if(stop==start) return 0; // empty pattern
964
965 isym=start+strChrBrackets(pat+start,stop-start,' ',"{"); // word separator
966 if(isym>=start) { // space operator found at i2
967 if(isym==start || isym==stop-1) return -2; // missing space operand
968 lnum=strexpandlogic(pat,start,isym,&llist);
969 if(lnum<0) return lnum;
970 rnum=strexpandlogic(pat,isym+1,stop,&rlist);
971 if(rnum<0) return rnum;
972 if(lnum*rnum>0) {
973 results=(char**) calloc(lnum*rnum,sizeof(char*));
974 if(!results) return -1; }
975 for(il=0;il<lnum;il++)
976 for(ir=0;ir<rnum;ir++) {
977 ires=il*rnum+ir;
978 results[ires]=(char*)calloc(strlen(llist[il])+1+strlen(rlist[ir])+1,sizeof(char));
979 if(!results[ires]) return -1;
980 strcpy(results[ires],llist[il]);
981 strcat(results[ires]," ");
982 strcat(results[ires],rlist[ir]); }
983 for(il=0;il<lnum;il++) free(llist[il]);
984 for(ir=0;ir<rnum;ir++) free(rlist[ir]);
985 free(llist);
986 free(rlist);
987 *resultsptr=results;
988 return lnum*rnum; }
989
990 isym=start+strChrBrackets(pat+start,stop-start,'|',"{"); // OR operator
991 if(isym>=start) { // OR operator found at i2
992 if(isym>start) { // left operand
993 lnum=strexpandlogic(pat,start,isym,&llist);
994 if(lnum<0) return lnum; }
995 else { // empty left operand
996 lnum=1;
997 llist=(char**)malloc(sizeof(char*));
998 if(!llist) return -1;
999 llist[0]=(char*)malloc(sizeof(char));
1000 if(!llist[0]) return -1;
1001 llist[0][0]='\0'; }
1002 if(isym<stop-1) { // right operand
1003 rnum=strexpandlogic(pat,isym+1,stop,&rlist);
1004 if(rnum<0) return rnum; }
1005 else { // empty right operand
1006 rnum=1;
1007 rlist=(char**)malloc(sizeof(char*));
1008 if(!rlist) return -1;
1009 rlist[0]=(char*)malloc(sizeof(char));
1010 if(!rlist[0]) return -1;
1011 rlist[0][0]='\0'; }
1012 if(lnum==0 && rnum==0) return 0;
1013 results=(char**) calloc(lnum+rnum,sizeof(char*));
1014 if(!results) return -1;
1015 for(il=0;il<lnum;il++) results[il]=llist[il];
1016 for(ir=0;ir<rnum;ir++) results[lnum+ir]=rlist[ir];
1017 free(llist);
1018 free(rlist);
1019 *resultsptr=results;
1020 return lnum+rnum; }
1021
1022 isym=start+strChrBrackets(pat+start,stop-start,'&',"{"); // AND operator
1023 if(isym>=start) { // AND operator found at i2
1024 if(isym==start || isym==stop-1) return -3; // missing AND operand
1025 lnum=strexpandlogic(pat,start,isym,&llist);
1026 if(lnum<0) return lnum;
1027 rnum=strexpandlogic(pat,isym+1,stop,&rlist);
1028 if(rnum<0) return rnum;
1029 if(lnum*rnum>0) {
1030 results=(char**) calloc(2*lnum*rnum,sizeof(char*));
1031 if(!results) return -1; }
1032 for(il=0;il<lnum;il++)
1033 for(ir=0;ir<rnum;ir++) {
1034 ires=il*rnum+ir;
1035 results[ires]=(char*)calloc(strlen(llist[il])+strlen(rlist[ir])+1,sizeof(char));
1036 if(!results[ires]) return -1;
1037 strcpy(results[ires],llist[il]);
1038 strcat(results[ires],rlist[ir]); }
1039 for(il=0;il<lnum;il++)
1040 for(ir=0;ir<rnum;ir++) {
1041 ires=lnum*rnum+il*rnum+ir;
1042 results[ires]=(char*)calloc(strlen(llist[il])+strlen(rlist[ir])+1,sizeof(char));
1043 if(!results[ires]) return -1;
1044 strcpy(results[ires],rlist[ir]);
1045 strcat(results[ires],llist[il]); }
1046 for(il=0;il<lnum;il++) free(llist[il]);
1047 for(ir=0;ir<rnum;ir++) free(rlist[ir]);
1048 free(llist);
1049 free(rlist);
1050 *resultsptr=results;
1051 return 2*lnum*rnum; }
1052
1053 isym=start+strChrBrackets(pat+start,stop-start,'{',""); // braces
1054 if(isym>=start) {
1055 i2=strparenmatch(pat,isym);
1056 if(i2<0) return -5; // no matching brace
1057 lnum=strexpandlogic(pat,isym+1,i2,&llist);
1058 if(lnum<0) return lnum;
1059 if(i2+1==stop) { // right brace at stop
1060 *resultsptr=llist;
1061 for(il=0;il<lnum;il++)
1062 strPreCat(llist[il],pat,start,isym);
1063 return lnum; }
1064 rnum=strexpandlogic(pat,i2+1,stop,&rlist);
1065 if(rnum<0) return rnum;
1066 if(lnum*rnum>0) {
1067 results=(char**) calloc(lnum*rnum,sizeof(char*));
1068 if(!results) return -1; }
1069 for(il=0;il<lnum;il++)
1070 for(ir=0;ir<rnum;ir++) {
1071 ires=il*rnum+ir;
1072 results[ires]=(char*)calloc(isym+strlen(llist[il])+strlen(rlist[ir])+1,sizeof(char));
1073 if(!results[ires]) return -1;
1074 strncpy(results[ires],pat+start,isym-start);
1075 strcat(results[ires],llist[il]);
1076 strcat(results[ires],rlist[ir]); }
1077 for(il=0;il<lnum;il++) free(llist[il]);
1078 for(ir=0;ir<rnum;ir++) free(rlist[ir]);
1079 free(llist);
1080 free(rlist);
1081 *resultsptr=results;
1082 return lnum*rnum; }
1083
1084 results=(char**) malloc(sizeof(char*)); // no special symbols
1085 if(!results) return -1;
1086 results[0]=(char*)calloc(stop-start+1,sizeof(char));
1087 if(!results[0]) return -1;
1088 strncpy(results[0],pat+start,stop-start);
1089 results[0][stop-start]='\0';
1090 *resultsptr=results;
1091 return 1; }
1092
1093
1094 /* strEnhWildcardMatch */
1095 int strEnhWildcardMatch(const char *pat,const char *str) {
1096 static char *localpat=NULL;
1097 static char **results=NULL;
1098 static int nr=0;
1099 int i;
1100
1101 if(!pat || !localpat || strcmp(pat,localpat)) { // create list of patterns
1102 if(nr>0) {
1103 for(i=0;i<nr;i++) free(results[i]);
1104 free(results);
1105 results=NULL;
1106 nr=0; }
1107 if(localpat) {
1108 free(localpat);
1109 localpat=NULL; }
1110 if(pat) {
1111 localpat=(char*)calloc(strlen(pat)+1,sizeof(char));
1112 if(!localpat) return -1;
1113 strcpy(localpat,pat);
1114 nr=strexpandlogic(localpat,0,-1,&results);
1115 if(nr<0) return nr; }}
1116
1117 // for(i=0;i<nr;i++) printf("%s\n",results[i]); //?? debug
1118
1119 if(str)
1120 for(i=0;i<nr;i++)
1121 if(strwildcardmatch(results[i],str)) return 1;
1122
1123 return 0; }
1124
1125
1126 /* strEnhWildcardMatchAndSub */
1127 int strEnhWildcardMatchAndSub(const char *pat,const char *str,const char *destpat,char *dest) {
1128 static char *localpat=NULL,*localdestpat=NULL;
1129 static char **patlist=NULL,**destlist=NULL;
1130 static int npr=0,ndr=0,iresults=0,starextra=0;
1131 int i,ismatch,destwords;
1132
1133 if(!pat || !localpat || strcmp(pat,localpat)) {
1134 if(npr>0) { // npr is number of pattern results, which is items in patlist
1135 for(i=0;i<npr;i++) free(patlist[i]);
1136 free(patlist);
1137 patlist=NULL;
1138 npr=0; }
1139 if(localpat) {
1140 free(localpat);
1141 localpat=NULL; }
1142 if(pat) {
1143 localpat=(char*)calloc(strlen(pat)+1,sizeof(char));
1144 if(!localpat) return -1;
1145 strcpy(localpat,pat); // localpat is local copy of pat
1146 npr=strexpandlogic(localpat,0,-1,&patlist); // patlist lists the same pattern as pat but with the logic expanded
1147 if(npr<0) return npr; } // error occured
1148 iresults=0; // which result is being returned
1149 starextra=0; }
1150
1151 // for(i=0;i<npr;i++) printf("%s\n",patlist[i]); //?? debug
1152
1153 if(!destpat || !localdestpat || strcmp(destpat,localdestpat)) {
1154 if(ndr>0) { // ndr is number of destination results, which is items in destlist
1155 for(i=0;i<ndr;i++) free(destlist[i]);
1156 free(destlist);
1157 destlist=NULL;
1158 ndr=0; }
1159 if(localdestpat) {
1160 free(localdestpat);
1161 localdestpat=NULL; }
1162 if(destpat) {
1163 localdestpat=(char*)calloc(strlen(destpat)+1,sizeof(char));
1164 if(!localdestpat) return -1;
1165 strcpy(localdestpat,destpat);
1166 ndr=strexpandlogic(localdestpat,0,-1,&destlist); // destlist lists the same pattern as destpat but with logic expanded
1167 if(ndr<0) return ndr; }
1168 iresults=0;
1169 starextra=0; }
1170
1171 if(ndr>1 && npr>1 && ndr!=npr) return -10;
1172
1173 if(!str) {
1174 iresults=0;
1175 starextra=0;
1176 return 0; }
1177
1178 destwords=wordcount(destpat);
1179
1180 if((ndr==0 || ndr==1) && npr>0) {
1181 while(iresults<npr) { // iresults scans of list of patterns
1182 if(strwildcardmatch(patlist[iresults],str)) {
1183 strncpy(dest,destlist?destlist[0]:"",STRCHAR-1);
1184 dest[STRCHAR-1]='\0';
1185 ismatch=strwildcardmatchandsub(patlist[iresults],str,dest,starextra);
1186 if(ismatch) starextra++; // starextra looks for multiple matches when there are 2 stars
1187 else {
1188 starextra=0;
1189 iresults++; }
1190 if(ismatch && wordcount(dest)==destwords) return 1; }
1191 else {
1192 starextra=0;
1193 iresults++; }}}
1194
1195 else if((npr==0 || npr==1) && ndr>0) {
1196 if(patlist?strwildcardmatch(patlist[0],str):str[0]=='\0') {
1197 while(iresults<ndr) { // iresults scans of list of destinations
1198 strncpy(dest,destlist[iresults],STRCHAR-1);
1199 dest[STRCHAR-1]='\0';
1200 ismatch=strwildcardmatchandsub(patlist?patlist[0]:"",str,dest,starextra);
1201 if(ismatch) starextra++; // starextra looks for multiple matches when there are 2 stars
1202 else {
1203 starextra=0;
1204 iresults++; }
1205 if(ismatch && wordcount(dest)==destwords) return 1; }}}
1206
1207 else if(npr>0 && ndr>0) { // ndr==npr and ndr,ndr>0
1208 while(iresults<npr) { // iresults scans list of patterns
1209 if(strwildcardmatch(patlist[iresults],str)) {
1210 strncpy(dest,destlist[iresults],STRCHAR-1);
1211 dest[STRCHAR-1]='\0';
1212 ismatch=strwildcardmatchandsub(patlist[iresults],str,dest,starextra);
1213 if(ismatch) starextra++; // starextra looks for multiple matches when there are 2 stars
1214 else {
1215 starextra=0;
1216 iresults++; }
1217 if(ismatch && wordcount(dest)==destwords) return 1; }
1218 else {
1219 starextra=0;
1220 iresults++; }}}
1221
1222 iresults=0;
1223
1224 return 0; }
1225
1226
1227
1228 /******************************************************************/
1229 /***************************** Math parsing ***********************/
1230 /******************************************************************/
1231
1232
1233
1234 /* dblnan */
1235 double dblnan() {
1236 return (double)NAN; }
1237
1238
1239 /* strloadmathfunctions */
1240 int strloadmathfunctions(void) {
1241 double er;
1242 char str1[STRCHAR],str2[STRCHAR];
1243 double (*fnptrdd)(double);
1244 double (*fnptrddd)(double,double);
1245
1246 er=0;
1247 // functions from standard library math.h
1248 er+=strevalfunction(strcpy(str1,"acos"),strcpy(str2,"dd"),NULL,(void*) (fnptrdd=&acos),NULL,NULL,0);
1249 er+=strevalfunction(strcpy(str1,"asin"),strcpy(str2,"dd"),NULL,(void*) (fnptrdd=&asin),NULL,NULL,0);
1250 er+=strevalfunction(strcpy(str1,"atan"),strcpy(str2,"dd"),NULL,(void*) (fnptrdd=&atan),NULL,NULL,0);
1251 er+=strevalfunction(strcpy(str1,"cos"),strcpy(str2,"dd"),NULL,(void*) (fnptrdd=&cos),NULL,NULL,0);
1252 er+=strevalfunction(strcpy(str1,"cosh"),strcpy(str2,"dd"),NULL,(void*) (fnptrdd=&cosh),NULL,NULL,0);
1253 er+=strevalfunction(strcpy(str1,"sin"),strcpy(str2,"dd"),NULL,(void*) (fnptrdd=&sin),NULL,NULL,0);
1254 er+=strevalfunction(strcpy(str1,"sinh"),strcpy(str2,"dd"),NULL,(void*) (fnptrdd=&sinh),NULL,NULL,0);
1255 er+=strevalfunction(strcpy(str1,"tan"),strcpy(str2,"dd"),NULL,(void*) (fnptrdd=&tan),NULL,NULL,0);
1256 er+=strevalfunction(strcpy(str1,"tanh"),strcpy(str2,"dd"),NULL,(void*) (fnptrdd=&tanh),NULL,NULL,0);
1257 er+=strevalfunction(strcpy(str1,"exp"),strcpy(str2,"dd"),NULL,(void*) (fnptrdd=&exp),NULL,NULL,0);
1258 er+=strevalfunction(strcpy(str1,"log"),strcpy(str2,"dd"),NULL,(void*) (fnptrdd=&log),NULL,NULL,0);
1259 er+=strevalfunction(strcpy(str1,"log10"),strcpy(str2,"dd"),NULL,(void*) (fnptrdd=&log10),NULL,NULL,0);
1260 er+=strevalfunction(strcpy(str1,"sqrt"),strcpy(str2,"dd"),NULL,(void*) (fnptrdd=&sqrt),NULL,NULL,0);
1261 er+=strevalfunction(strcpy(str1,"ceil"),strcpy(str2,"dd"),NULL,(void*) (fnptrdd=&ceil),NULL,NULL,0);
1262 er+=strevalfunction(strcpy(str1,"fabs"),strcpy(str2,"dd"),NULL,(void*) (fnptrdd=&fabs),NULL,NULL,0);
1263 er+=strevalfunction(strcpy(str1,"floor"),strcpy(str2,"dd"),NULL,(void*) (fnptrdd=&floor),NULL,NULL,0);
1264
1265 er+=strevalfunction(strcpy(str1,"atan2"),strcpy(str2,"ddd"),NULL,(void*) (fnptrddd=&atan2),NULL,NULL,0);
1266 er+=strevalfunction(strcpy(str1,"pow"),strcpy(str2,"ddd"),NULL,(void*) (fnptrddd=&pow),NULL,NULL,0);
1267 er+=strevalfunction(strcpy(str1,"rand"),strcpy(str2,"ddd"),NULL,(void*) (fnptrddd=&unirandCCD),NULL,NULL,0);
1268
1269 return (int) er; }
1270
1271
1272 /* strevalfunction */
1273 double strevalfunction(char *expression,char *parameters,void *voidptr,void *funcptr,char **varnames,const double *varvalues,int nvar) {
1274 static int maxfunc=0,nfunc=0;
1275 static char **funclist=NULL,**paramlist=NULL;
1276 static void **funcptrs=NULL,**voidptrs=NULL;
1277 int newmaxfunc;
1278 char **newfunclist,**newparamlist;
1279 void **newfuncptrs,**newvoidptrs;
1280 char erstr[STRCHAR];
1281
1282 int i,comma;
1283 double (*fnptrdd)(double);
1284 double (*fnptrddd)(double,double);
1285 double (*fnptrdves)(void*,char*,char*);
1286
1287 double answer,f1,f2;
1288 char *s1;
1289
1290 if(!expression) {
1291 for(i=0;i<nfunc;i++) {
1292 free(funclist[i]);
1293 free(paramlist[i]); }
1294 free(funclist);
1295 free(paramlist);
1296 free(funcptrs);
1297 free(voidptrs);
1298 maxfunc=0;
1299 nfunc=0;
1300 return 0; }
1301
1302 if(funcptr) {
1303 if(nfunc==maxfunc) {
1304 newmaxfunc=2*maxfunc+1;
1305 newfunclist=(char **) calloc(newmaxfunc,sizeof(char *));
1306 if(!newfunclist) return 1;
1307 for(i=0;i<nfunc;i++)
1308 newfunclist[i]=funclist[i];
1309 for(;i<newmaxfunc;i++)
1310 newfunclist[i]=NULL;
1311
1312 newparamlist=(char **) calloc(newmaxfunc,sizeof(char *));
1313 if(!newparamlist) return 1;
1314 for(i=0;i<nfunc;i++)
1315 newparamlist[i]=paramlist[i];
1316 for(;i<newmaxfunc;i++)
1317 newparamlist[i]=NULL;
1318
1319 newfuncptrs=(void **) calloc(newmaxfunc,sizeof(void *));
1320 if(!newfuncptrs) return 1;
1321 for(i=0;i<nfunc;i++)
1322 newfuncptrs[i]=funcptrs[i];
1323 for(;i<newmaxfunc;i++)
1324 newfuncptrs[i]=NULL;
1325
1326 newvoidptrs=(void **) calloc(newmaxfunc,sizeof(void *));
1327 if(!newvoidptrs) return 1;
1328 for(i=0;i<nfunc;i++)
1329 newvoidptrs[i]=voidptrs[i];
1330 for(;i<newmaxfunc;i++)
1331 newvoidptrs[i]=NULL;
1332
1333 free(funclist);
1334 free(paramlist);
1335 free(funcptrs);
1336 free(voidptrs);
1337 funclist=newfunclist;
1338 paramlist=newparamlist;
1339 funcptrs=newfuncptrs;
1340 voidptrs=newvoidptrs;
1341 maxfunc=newmaxfunc; }
1342
1343 funclist[nfunc]=StringCopy(expression);
1344 if(!funclist[nfunc]) return 1;
1345 paramlist[nfunc]=StringCopy(parameters);
1346 if(!paramlist[nfunc]) return 1;
1347 funcptrs[nfunc]=funcptr;
1348 voidptrs[nfunc]=voidptr;
1349 nfunc++;
1350 return 0; }
1351
1352 for(i=0;i<nfunc && strcmp(expression,funclist[i]);i++); // i is function number
1353 CHECKS(i<nfunc,"unknown function name");
1354
1355 if(!strcmp(paramlist[i],"dd")) {
1356 fnptrdd=(double(*)(double)) funcptrs[i];
1357 f1=strmatheval(parameters,varnames,varvalues,nvar);
1358 answer=(*fnptrdd)(f1); }
1359 else if(!strcmp(paramlist[i],"ddd")) {
1360 fnptrddd=(double(*)(double,double)) funcptrs[i];
1361 CHECKS((comma=strChrBrackets(parameters,-1,',',"([{,\"'"))>0,"missing parameter");
1362 parameters[comma]='\0';
1363 f1=strmatheval(parameters,varnames,varvalues,nvar);
1364 parameters+=comma+1;
1365 f2=strmatheval(parameters,varnames,varvalues,nvar);
1366 answer=(*fnptrddd)(f1,f2); }
1367 else if(!strcmp(paramlist[i],"dves")) {
1368 fnptrdves=(double(*)(void*,char*,char*)) funcptrs[i];
1369 s1=parameters;
1370 answer=(*fnptrdves)(voidptrs[i],erstr,s1);
1371 CHECKS(answer>=0 || answer<0,"%s",erstr); }
1372 else
1373 CHECKS(0,"BUG: unknown function format");
1374
1375 return answer;
1376
1377 failure:
1378 MathParseError=1;
1379 return dblnan(); }
1380
1381
1382 /* strmatheval */
1383 double strmatheval(char *expression,char **varnames,const double *varvalues,int nvar) {
1384 static int unarysymbol=0;
1385 int length,i1,i2;
1386 double answer,term;
1387 char *ptr,*ptr2,ptrchar,ptr2char;
1388
1389 // printf("strmatheval expression: '%s'\n",expression); // DEBUG
1390
1391 MathParseError=0;
1392 length=strlen(expression);
1393 CHECKS(length>0,"missing expression");
1394
1395 if(strisnumber(expression)) { // number
1396 unarysymbol=0;
1397 answer=strtod(expression,NULL); }
1398
1399 else if((i1=stringfind(varnames,nvar,expression))>=0) { // variable
1400 unarysymbol=0;
1401 answer=varvalues[i1]; }
1402
1403 else if(strchr("([{",expression[0]) && strparenmatch(expression,0)==length-1) { // {[()]}
1404 unarysymbol=0;
1405 ptr=expression+length-1;
1406 ptrchar=*ptr;
1407 *ptr='\0';
1408 answer=strmatheval(expression+1,varnames,varvalues,nvar);
1409 *ptr=ptrchar; }
1410
1411 else if(strisfunctionform(expression,&ptr)) { // function
1412 unarysymbol=0;
1413 expression[length-1]='\0';
1414 *ptr='\0';
1415 ptr++;
1416 answer=strevalfunction(expression,ptr,NULL,NULL,varnames,varvalues,nvar);
1417 CHECK(answer>=0 || answer<0); }
1418
1419 else if((i1=strPbrkBrackets(expression,length-1,"+-","([{",1))>0 && !strchr("^*/",expression[i1-1]) && !(strchr("Ee",expression[i1-1]) && i1>1 && strchr("0123456789",expression[i1-2]))) { // binary + -
1420 unarysymbol=0;
1421 ptr=expression+i1;
1422 ptrchar=*ptr;
1423 *ptr='\0';
1424 answer=strmatheval(expression,varnames,varvalues,nvar); // first term
1425 *ptr=ptrchar;
1426 while((i2=strPbrkBrackets(ptr+1,strlen(ptr+1)-1,"+-","([{",1))>0 && !strchr("^*/",ptr[i2]) && !(strchr("Ee",ptr[i2]) && strchr("0123456789",ptr[i2-1]))) {
1427 ptr2=ptr+1+i2;
1428 ptr2char=*ptr2;
1429 *ptr2='\0';
1430 term=strmatheval(ptr+1,varnames,varvalues,nvar); // middle terms
1431 *ptr2=ptr2char;
1432 if(ptrchar=='+') answer=answer+term;
1433 else answer=answer-term;
1434 ptr=ptr2;
1435 ptrchar=ptr2char; }
1436 term=strmatheval(ptr+1,varnames,varvalues,nvar); // last term
1437 if(ptrchar=='+') answer=answer+term;
1438 else answer=answer-term; }
1439
1440 else if((i1=strPbrkBrackets(expression,length-1,"*/%","([{",1))>0) { // binary * / %
1441 unarysymbol=0;
1442 ptr=expression+i1;
1443 ptrchar=*ptr;
1444 *ptr='\0';
1445 answer=strmatheval(expression,varnames,varvalues,nvar); // first term
1446 *ptr=ptrchar;
1447 while((i2=strPbrkBrackets(ptr+1,strlen(ptr+1)-1,"*/%","([{",1))>0) {
1448 ptr2=ptr+1+i2;
1449 ptr2char=*ptr2;
1450 *ptr2='\0';
1451 term=strmatheval(ptr+1,varnames,varvalues,nvar); // middle terms
1452 *ptr2=ptr2char;
1453 if(ptrchar=='*') answer=answer*term;
1454 else if(ptrchar=='/') {
1455 CHECKS(term!=0,"divide by zero");
1456 answer=answer/term; }
1457 else {
1458 CHECKS(term>0.5,"illegal modulo value");
1459 answer=(double)((long int)(answer+0.5)%(long int)(term+0.5)); }
1460 ptr=ptr2;
1461 ptrchar=ptr2char; }
1462 term=strmatheval(ptr+1,varnames,varvalues,nvar); // last term
1463 if(ptrchar=='*') answer=answer*term;
1464 else if(ptrchar=='/') {
1465 CHECKS(term!=0,"divide by zero");
1466 answer=answer/term; }
1467 else {
1468 CHECKS(term>0.5,"illegal modulo value");
1469 answer=(double)((long int)(answer+0.5)%(long int)(term+0.5)); }}
1470
1471 else if(expression[0]=='+' || expression[0]=='-') { // unary + -
1472 CHECKS(!unarysymbol,"cannot have multiple preceding signs");
1473 unarysymbol=1;
1474 term=strmatheval(expression+1,varnames,varvalues,nvar);
1475 answer=expression[0]=='+'?term:-term; }
1476
1477 else if((i1=strPbrkBrackets(expression,length-1,"^","([{",1))>0) { // binary ^
1478 unarysymbol=0;
1479 ptr=expression+i1;
1480 ptrchar=*ptr;
1481 *ptr='\0';
1482 answer=strmatheval(expression,varnames,varvalues,nvar);
1483 *ptr=ptrchar;
1484 term=strmatheval(ptr+1,varnames,varvalues,nvar);
1485 CHECKS(answer>0 || (answer==0 && term>0) || (answer<0 && term==round(term)),"exponent error");
1486 answer=pow(answer,term); }
1487
1488 else {
1489 answer=0;
1490 CHECKS(0,"syntax error"); }
1491
1492 // printf("\t=%g\n",answer); // DEBUG
1493
1494 return answer;
1495 failure:
1496 MathParseError=1;
1497 return dblnan(); }
1498
1499
1500 /* strmathevalint */
1501 int strmathevalint(char *expression,char **varnames,const double *varvalues,int nvar) {
1502 double value;
1503
1504 value=strmatheval(expression,varnames,varvalues,nvar);
1505 return (int)round(value); }
1506
1507
1508 /* strmatherror */
1509 int strmatherror(char *string,int clear) {
1510 int er;
1511
1512 if(string)
1513 strcpy(string,MathParseError?StrErrorString:"");
1514 er=MathParseError;
1515 if(clear) {
1516 MathParseError=0;
1517 StrErrorString[0]='\0'; }
1518 return er; }
1519
1520
1521 /* strmathsscanf */
1522 int strmathsscanf(const char *str,const char *format,char **varnames,const double *varvalues,int nvar,...) {
1523 va_list arguments;
1524 char newformat[STRCHAR],newstr[STRCHAR],expression[STRCHAR];
1525 const char *fmtpos1,*fmtpos2,*strpos1,*strpos2;
1526 int word,count,readint,valueint;
1527 double value;
1528
1529 if(!str || !format) return 0;
1530
1531 newformat[0]='\0';
1532 newstr[0]='\0';
1533 fmtpos1=format; // position in original format string
1534 strpos1=str; // position in original str string
1535
1536 fmtpos2=strstr(fmtpos1,"%m"); // location of math operation to deal with
1537
1538 while(fmtpos2) {
1539 if(*(fmtpos2+2)=='i') readint=1;
1540 else if(*(fmtpos2+2)=='l' && *(fmtpos2+3)=='g') readint=0;
1541 else CHECKS(0,"BUG: illegal string formatting argument");
1542
1543 word=strwhichword(fmtpos1,fmtpos2);
1544 strpos2=strnwordc(strpos1,word); // position in string with math for parsing
1545 if(!strpos2) break;
1546
1547 strncat(newformat,fmtpos1,fmtpos2-fmtpos1);
1548 strncat(newstr,strpos1,strpos2-strpos1);
1549 sscanf(strpos2,"%s",expression);
1550 if(readint) {
1551 valueint=strmathevalint(expression,varnames,varvalues,nvar);
1552 if(strmatherror(NULL,0)) break;
1553 strcat(newformat,"%i ");
1554 snprintf(newstr+strlen(newstr),STRCHAR-strlen(newstr),"%i ",valueint); }
1555 else {
1556 value=strmatheval(expression,varnames,varvalues,nvar);
1557 if(strmatherror(NULL,0)) break;
1558 strcat(newformat,"%lg ");
1559 snprintf(newstr+strlen(newstr),STRCHAR-strlen(newstr),"%.17g ",value); }
1560
1561 fmtpos1=strnwordc(fmtpos2,2);
1562 strpos1=strnwordc(strpos2,2);
1563 fmtpos2=fmtpos1?strstr(fmtpos1,"%m"):NULL; }
1564
1565 if(!strmatherror(NULL,0)) {
1566 if(fmtpos1) strcat(newformat,fmtpos1);
1567 if(strpos1) strcat(newstr,strpos1); }
1568
1569 va_start(arguments,nvar);
1570 count=vsscanf(newstr,newformat,arguments);
1571 va_end(arguments);
1572
1573 return count;
1574
1575 failure:
1576 return 0; }
1577
1578
1579
1580
1581
1582