A hint: This file contains one or more very long lines, so maybe it is better readable using the pure text view mode that shows the contents as wrapped lines within the browser window.
1 /* #includes */ /*{{{C}}}*//*{{{*/ 2 #ifndef NO_POSIX_SOURCE 3 #undef _POSIX_SOURCE 4 #define _POSIX_SOURCE 1 5 #undef _POSIX_C_SOURCE 6 #define _POSIX_C_SOURCE 2 7 #endif 8 9 #define _XOPEN_SOURCE /* glibc2 needs this */ 10 11 #ifdef DMALLOC 12 #include "dmalloc.h" 13 #endif 14 15 #include <assert.h> 16 #include <errno.h> 17 #include <limits.h> 18 #include <math.h> 19 #include <stdlib.h> 20 extern double strtod(const char *nptr, char **endptr); /* SunOS 4 hack */ 21 #include <stdio.h> 22 #include <string.h> 23 #include <time.h> 24 25 26 #include "default.h" 27 #include "eval.h" 28 #include "func.h" 29 #include "main.h" 30 #include "misc.h" 31 #include "parser.h" 32 #include "scanner.h" 33 #include "sheet.h" 34 /*}}}*/ 35 /* #defines */ /*{{{*/ 36 /* There is a BSD extensions, but they are possibly more exact. */ 37 #ifdef M_E 38 #define CONST_E M_E 39 #else 40 #define CONST_E ((double)2.7182818284590452354) 41 #endif 42 #ifdef M_PI 43 #define CONST_PI M_PI 44 #else 45 #define CONST_PI ((double)3.14159265358979323846) 46 #endif 47 /*}}}*/ 48 49 #ifdef WIN32 50 // This strptime implementation Copyright 2009 Google Inc. 51 // 52 // Licensed under the Apache License, Version 2.0 (the "License"); 53 // you may not use this file except in compliance with the License. 54 // You may obtain a copy of the License at 55 // 56 // http://www.apache.org/licenses/LICENSE-2.0 57 // 58 // Unless required by applicable law or agreed to in writing, software 59 // distributed under the License is distributed on an "AS IS" BASIS, 60 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 61 // See the License for the specific language governing permissions and 62 // limitations under the License. 63 64 // Implement strptime under windows 65 static const char* kWeekFull[] = { 66 "Sunday", "Monday", "Tuesday", "Wednesday", 67 "Thursday", "Friday", "Saturday" 68 }; 69 70 static const char* kWeekAbbr[] = { 71 "Sun", "Mon", "Tue", "Wed", 72 "Thu", "Fri", "Sat" 73 }; 74 75 static const char* kMonthFull[] = { 76 "January", "February", "March", "April", "May", "June", 77 "July", "August", "September", "October", "November", "December" 78 }; 79 80 static const char* kMonthAbbr[] = { 81 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 82 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 83 }; 84 85 static const char* _parse_num(const char* s, int low, int high, int* value) { 86 const char* p = s; 87 for (*value = 0; *p && isdigit(*p); ++p) { 88 *value = (*value) * 10 + *p - '0'; 89 } 90 91 if (p == s || *value < low || *value > high) return NULL; 92 return p; 93 } 94 95 static char* _strptime(const char *s, const char *format, struct tm *tm) { 96 int i, len; 97 while (*format && *s) { 98 if (*format != '%') { 99 if (*s != *format) return NULL; 100 101 ++format; 102 ++s; 103 continue; 104 } 105 106 ++format; 107 len = 0; 108 switch (*format) { 109 // weekday name. 110 case 'a': 111 case 'A': 112 tm->tm_wday = -1; 113 for (i = 0; i < 7; ++i) { 114 len = strlen(kWeekAbbr[i]); 115 if (strnicmp(kWeekAbbr[i], s, len) == 0) { 116 tm->tm_wday = i; 117 break; 118 } 119 120 len = strlen(kWeekFull[i]); 121 if (strnicmp(kWeekFull[i], s, len) == 0) { 122 tm->tm_wday = i; 123 break; 124 } 125 } 126 if (tm->tm_wday == -1) return NULL; 127 s += len; 128 break; 129 130 // month name. 131 case 'b': 132 case 'B': 133 case 'h': 134 tm->tm_mon = -1; 135 for (i = 0; i < 12; ++i) { 136 len = strlen(kMonthAbbr[i]); 137 if (strnicmp(kMonthAbbr[i], s, len) == 0) { 138 tm->tm_mon = i; 139 break; 140 } 141 142 len = strlen(kMonthFull[i]); 143 if (strnicmp(kMonthFull[i], s, len) == 0) { 144 tm->tm_mon = i; 145 break; 146 } 147 } 148 if (tm->tm_mon == -1) return NULL; 149 s += len; 150 break; 151 152 // month [1, 12]. 153 case 'm': 154 s = _parse_num(s, 1, 12, &tm->tm_mon); 155 if (s == NULL) return NULL; 156 --tm->tm_mon; 157 break; 158 159 // day [1, 31]. 160 case 'd': 161 case 'e': 162 s = _parse_num(s, 1, 31, &tm->tm_mday); 163 if (s == NULL) return NULL; 164 break; 165 166 // hour [0, 23]. 167 case 'H': 168 s = _parse_num(s, 0, 23, &tm->tm_hour); 169 if (s == NULL) return NULL; 170 break; 171 172 // minute [0, 59] 173 case 'M': 174 s = _parse_num(s, 0, 59, &tm->tm_min); 175 if (s == NULL) return NULL; 176 break; 177 178 // seconds [0, 60]. 60 is for leap year. 179 case 'S': 180 s = _parse_num(s, 0, 60, &tm->tm_sec); 181 if (s == NULL) return NULL; 182 break; 183 184 // year [1900, 9999]. 185 case 'Y': 186 s = _parse_num(s, 1900, 9999, &tm->tm_year); 187 if (s == NULL) return NULL; 188 tm->tm_year -= 1900; 189 break; 190 191 // year [0, 99]. 192 case 'y': 193 s = _parse_num(s, 0, 99, &tm->tm_year); 194 if (s == NULL) return NULL; 195 if (tm->tm_year <= 68) { 196 tm->tm_year += 100; 197 } 198 break; 199 200 // arbitray whitespace. 201 case 't': 202 case 'n': 203 while (isspace(*s)) ++s; 204 break; 205 206 // '%'. 207 case '%': 208 if (*s != '%') return NULL; 209 ++s; 210 break; 211 212 // All the other format are not supported. 213 default: 214 return NULL; 215 } 216 ++format; 217 } 218 219 if (*format) { 220 return NULL; 221 } else { 222 return (char *)s; 223 } 224 } 225 226 char* strptime(const char *buf, const char *fmt, struct tm *tm) { 227 return _strptime(buf, fmt, tm); 228 } 229 #endif 230 231 /* sci_func -- map a double to a double */ /*{{{*/ 232 static Token sci_func(int argc, const Token argv[], double (*func)(double), const char *func_name) 233 { 234 Token result; 235 236 if (argc==1 && argv[0].type==FLOAT) 237 { 238 result.type=FLOAT; 239 errno=0; 240 result.u.flt=(func)(argv[0].u.flt); 241 if (errno) 242 { 243 result.type=EEK; 244 result.u.err=malloc(strlen(func_name)+2+strlen(strerror(errno))+1); 245 sprintf(result.u.err,"%s: %s",func_name,strerror(errno)); 246 } 247 } 248 else 249 { 250 if (argc==1 && argv[0].type==INT) 251 { 252 result.type=FLOAT; 253 errno=0; 254 result.u.flt=(func)((double)argv[0].u.integer); 255 if (errno) 256 { 257 result.type=EEK; 258 result.u.err=malloc(strlen(func_name)+2+strlen(strerror(errno))+1); 259 sprintf(result.u.err,"%s: %s",func_name,strerror(errno)); 260 } 261 } 262 else 263 { 264 result.type=EEK; 265 /* This is actually too much, but always enough for %s formats. */ 266 result.u.err=malloc(strlen(_("Usage: %s(float)"))+strlen(func_name)+1); 267 sprintf(result.u.err,_("Usage: %s(float)"),func_name); 268 } 269 } 270 return result; 271 } 272 /*}}}*/ 273 /* arsinh */ /*{{{*/ 274 static double arsinh(double x) 275 { 276 return log(x+sqrt(x*x+1.0)); 277 } 278 /*}}}*/ 279 /* arcosh */ /*{{{*/ 280 static double arcosh(double x) 281 { 282 if (x>=1.0) return log(x+sqrt(x*x-1.0)); 283 else { errno=EDOM; return 0.0; } 284 } 285 /*}}}*/ 286 /* artanh */ /*{{{*/ 287 static double artanh(double x) 288 { 289 if (x>-1.0 && x<1.0) return 0.5*log((1.0+x)/(1.0-x)); 290 else { errno=EDOM; return 0.0; } 291 } 292 /*}}}*/ 293 /* rad2deg */ /*{{{*/ 294 static double rad2deg(double x) 295 { 296 return (360.0/(2.0*CONST_PI))*x; 297 } 298 /*}}}*/ 299 /* deg2rad */ /*{{{*/ 300 static double deg2rad(double x) 301 { 302 return (2.0*CONST_PI/360.0)*x; 303 } 304 /*}}}*/ 305 306 /* @ */ /*{{{*/ 307 static Token at_func(int argc, const Token argv[]) 308 { 309 /* variables */ /*{{{*/ 310 Token result; 311 /*}}}*/ 312 313 /* asserts */ /*{{{*/ 314 assert(argv!=(Token*)0); 315 /*}}}*/ 316 if (argc==0) 317 /* return value at current location */ /*{{{*/ 318 return (getvalue(upd_sheet,upd_x,upd_y,upd_z)); 319 /*}}}*/ 320 if (argc==1 && argv[0].type==LOCATION) 321 /* return value at location pointed to by argument */ /*{{{*/ 322 return (getvalue(upd_sheet,argv[0].u.location[0],argv[0].u.location[1],argv[0].u.location[2])); 323 /*}}}*/ 324 else if (argc==1 && (argv[0].type==INT || argv[0].type==EMPTY)) 325 /* return value at x on current y,z */ /*{{{*/ 326 return (getvalue(upd_sheet,argv[0].type==INT ? argv[0].u.integer : upd_x,upd_y,upd_z)); 327 /*}}}*/ 328 else if (argc==2 && (argv[0].type==INT || argv[0].type==EMPTY) && (argv[1].type==INT || argv[1].type==EMPTY)) 329 /* return value at x,y on current z */ /*{{{*/ 330 return (getvalue(upd_sheet,argv[0].type==INT ? argv[0].u.integer : upd_x,argv[1].type==INT ? argv[1].u.integer : upd_y,upd_z)); 331 /*}}}*/ 332 else if (argc==3 && (argv[0].type==INT || argv[0].type==EMPTY) && (argv[1].type==INT || argv[1].type==EMPTY) && (argv[2].type==INT || argv[2].type==EMPTY)) 333 /* return value at x,y,z */ /*{{{*/ 334 return (getvalue(upd_sheet,argv[0].type==INT ? argv[0].u.integer : upd_x,argv[1].type==INT ? argv[1].u.integer : upd_y,argv[2].type==INT ? argv[2].u.integer : upd_z)); 335 /*}}}*/ 336 else 337 /* return error */ /*{{{*/ 338 { 339 result.type=EEK; 340 result.u.err=strcpy(malloc(strlen(_("Usage: @([integer x][,[integer y][,[integer z]]]) or @(location)"))+1),_("Usage: @([integer x][,[integer y][,[integer z]]]) or @(location)")); 341 return result; 342 } 343 /*}}}*/ 344 } 345 /*}}}*/ 346 /* & */ /*{{{*/ 347 static Token adr_func(int argc, const Token argv[]) 348 { 349 /* variables */ /*{{{*/ 350 Token result; 351 /*}}}*/ 352 353 /* asserts */ /*{{{*/ 354 assert(argv!=(Token*)0); 355 /*}}}*/ 356 if (argc==3 && (argv[0].type==INT || argv[0].type==EMPTY) && (argv[1].type==INT || argv[1].type==EMPTY) && (argv[2].type==INT || argv[2].type==EMPTY)) 357 /* result is location of the given position */ /*{{{*/ 358 { 359 result.type=LOCATION; 360 result.u.location[0]=(argv[0].type==INT ? argv[0].u.integer : upd_x); 361 result.u.location[1]=(argv[1].type==INT ? argv[1].u.integer : upd_y); 362 result.u.location[2]=(argv[2].type==INT ? argv[2].u.integer : upd_z); 363 } 364 /*}}}*/ 365 else if (argc==2 && (argv[0].type==INT || argv[0].type==EMPTY) && (argv[1].type==INT || argv[1].type==EMPTY)) 366 /* result is location of the given position in the current z layer */ /*{{{*/ 367 { 368 result.type=LOCATION; 369 result.u.location[0]=(argv[0].type==INT ? argv[0].u.integer : upd_x); 370 result.u.location[1]=(argv[1].type==INT ? argv[1].u.integer : upd_y); 371 result.u.location[2]=upd_z; 372 } 373 /*}}}*/ 374 else if (argc==1 && (argv[0].type==INT || argv[0].type==EMPTY)) 375 /* result is location of the given position in the current y,z layer */ /*{{{*/ 376 { 377 result.type=LOCATION; 378 result.u.location[0]=(argv[0].type==INT ? argv[0].u.integer : upd_x); 379 result.u.location[1]=upd_y; 380 result.u.location[2]=upd_z; 381 } 382 /*}}}*/ 383 else if (argc==0) 384 /* result is location of the current position */ /*{{{*/ 385 { 386 result.type=LOCATION; 387 result.u.location[0]=upd_x; 388 result.u.location[1]=upd_y; 389 result.u.location[2]=upd_z; 390 } 391 /*}}}*/ 392 else 393 /* result is type error */ /*{{{*/ 394 { 395 result.type=EEK; 396 result.u.err=strcpy(malloc(strlen(_("Usage: &([integer x][,[integer y][,[integer z]]])"))+1),_("Usage: &([integer x][,[integer y][,[integer z]]])")); 397 } 398 /*}}}*/ 399 return result; 400 } 401 /*}}}*/ 402 /* x */ /*{{{*/ 403 static Token x_func(int argc, const Token argv[]) 404 { 405 /* variables */ /*{{{*/ 406 Token result; 407 /*}}}*/ 408 409 if (argc==0) 410 /* result is currently updated x position */ /*{{{*/ 411 { 412 result.type=INT; 413 result.u.integer=upd_x; 414 } 415 /*}}}*/ 416 else if (argc==1 && argv[0].type==LOCATION) 417 /* return x component of location */ /*{{{*/ 418 { 419 result.type=INT; 420 result.u.integer=argv[0].u.location[0]; 421 } 422 /*}}}*/ 423 else 424 /* x type error */ /*{{{*/ 425 { 426 result.type=EEK; 427 result.u.err=strcpy(malloc(strlen(_("Usage: x([location])"))+1),_("Usage: x([location])")); 428 } 429 /*}}}*/ 430 return result; 431 } 432 /*}}}*/ 433 /* y */ /*{{{*/ 434 static Token y_func(int argc, const Token argv[]) 435 { 436 /* variables */ /*{{{*/ 437 Token result; 438 /*}}}*/ 439 440 if (argc==0) 441 /* result is currently updated y position */ /*{{{*/ 442 { 443 result.type=INT; 444 result.u.integer=upd_y; 445 } 446 /*}}}*/ 447 else if (argc==1 && argv[0].type==LOCATION) 448 /* return y component of location */ /*{{{*/ 449 { 450 result.type=INT; 451 result.u.integer=argv[0].u.location[1]; 452 } 453 /*}}}*/ 454 else 455 /* y type error */ /*{{{*/ 456 { 457 result.type=EEK; 458 result.u.err=strcpy(malloc(strlen(_("Usage: y([location])"))+1),_("Usage: y([location])")); 459 } 460 /*}}}*/ 461 return result; 462 } 463 /*}}}*/ 464 /* z */ /*{{{*/ 465 static Token z_func(int argc, const Token argv[]) 466 { 467 /* variables */ /*{{{*/ 468 Token result; 469 /*}}}*/ 470 471 if (argc==0) 472 /* result is currently updated z position */ /*{{{*/ 473 { 474 result.type=INT; 475 result.u.integer=upd_z; 476 } 477 /*}}}*/ 478 else if (argc==1 && argv[0].type==LOCATION) 479 /* return z component of location */ /*{{{*/ 480 { 481 result.type=INT; 482 result.u.integer=argv[0].u.location[2]; 483 } 484 /*}}}*/ 485 else 486 /* result is z type error */ /*{{{*/ 487 { 488 result.type=EEK; 489 result.u.err=mystrmalloc(_("Usage: z([location])")); 490 } 491 /*}}}*/ 492 return result; 493 } 494 /*}}}*/ 495 /* e */ /*{{{*/ 496 static Token e_func(int argc, const Token argv[]) 497 { 498 /* variables */ /*{{{*/ 499 Token result; 500 /*}}}*/ 501 502 if (argc==0) /* result is constant e */ /*{{{*/ 503 { 504 result.type=FLOAT; 505 result.u.flt=CONST_E; 506 } 507 /*}}}*/ 508 else /* result is e type error */ /*{{{*/ 509 { 510 result.type=EEK; 511 result.u.err=mystrmalloc(_("Usage: e()")); 512 } 513 /*}}}*/ 514 return result; 515 } 516 /*}}}*/ 517 /* eval */ /*{{{*/ 518 static Token eval_func(int argc, const Token argv[]) 519 { 520 /* variables */ /*{{{*/ 521 Token result; 522 /*}}}*/ 523 524 --max_eval; 525 if (max_eval<0) 526 /* nesting error */ /*{{{*/ 527 { 528 result.type=EEK; 529 result.u.err=mystrmalloc(_("nested eval()")); 530 } 531 /*}}}*/ 532 else if (argc==1 && argv[0].type==LOCATION) 533 /* evaluate expression in cell at given position */ /*{{{*/ 534 { 535 Token **contents; 536 537 contents=getcont(upd_sheet,argv[0].u.location[0],argv[0].u.location[1],argv[0].u.location[2],2); 538 if (contents==(Token**)0) result.type=EMPTY; 539 else result=eval(contents); 540 } 541 /*}}}*/ 542 else 543 /* eval type error */ /*{{{*/ 544 { 545 result.type=EEK; 546 result.u.err=strcpy(malloc(strlen(_("Usage: eval(location)"))+1),_("Usage: eval(location)")); 547 } 548 /*}}}*/ 549 ++max_eval; 550 return result; 551 } 552 /*}}}*/ 553 /* error */ /*{{{*/ 554 static Token error_func(int argc, const Token argv[]) 555 { 556 /* variables */ /*{{{*/ 557 Token result; 558 /*}}}*/ 559 560 /* asserts */ /*{{{*/ 561 assert(argv!=(Token*)0); 562 /*}}}*/ 563 result.type=EEK; 564 if (argc!=1 || argv[0].type!=STRING) 565 /* result is type error */ /*{{{*/ 566 result.u.err=strcpy(malloc(strlen(_("Usage: error(string message)"))+1),_("Usage: error(string message)")); 567 /*}}}*/ 568 else 569 /* result is user defined error */ /*{{{*/ 570 result.u.err=strcpy(malloc(strlen(argv[0].u.string)+1),argv[0].u.string); 571 /*}}}*/ 572 return result; 573 } 574 /*}}}*/ 575 /* string */ /*{{{*/ 576 static Token string_func(int argc, const Token argv[]) 577 { 578 /* variables */ /*{{{*/ 579 Token result; 580 char *buf; 581 size_t size; 582 /*}}}*/ 583 584 if (argc==1 && argv[0].type==LOCATION) /* cell to string */ /*{{{*/ 585 { 586 buf=(char*)0; 587 size=0; 588 do 589 { 590 if (buf!=(char*)0) free(buf); 591 size+=16; 592 buf=malloc(size); 593 printvalue(buf,size,0,0,getscientific(upd_sheet,argv[0].u.location[0],argv[0].u.location[1],argv[0].u.location[2]),getprecision(upd_sheet,argv[0].u.location[0],argv[0].u.location[1],argv[0].u.location[2]),upd_sheet,argv[0].u.location[0],argv[0].u.location[1],argv[0].u.location[2]); 594 } while (strlen(buf)==size-1); 595 result.type=STRING; 596 result.u.string=buf; 597 } 598 /*}}}*/ 599 else if (argc==1 && argv[0].type==FLOAT) /* float to string */ /*{{{*/ 600 { 601 result.u.string=malloc(def_precision+10); 602 sprintf(result.u.string,DEF_SCIENTIFIC ? "%.*e" : "%.*f", def_precision,argv[0].u.flt); 603 result.type=STRING; 604 } 605 /*}}}*/ 606 else if (argc==1 && argv[0].type==INT) /* int to string */ /*{{{*/ 607 { 608 int length=2; 609 int n=argv[0].u.integer; 610 611 while (n!=0) n/=10; 612 result.u.string=malloc(length); 613 sprintf(result.u.string,"%ld",argv[0].u.integer); 614 result.type=STRING; 615 } 616 /*}}}*/ 617 else if (argc==2 && argv[0].type==FLOAT && argv[1].type==INT) /* float to string */ /*{{{*/ 618 { 619 result.u.string=malloc(argv[1].u.integer==-1 ? def_precision+10 : argv[1].u.integer+10); 620 sprintf(result.u.string,DEF_SCIENTIFIC ? "%.*e" : "%.*f",argv[1].u.integer==-1 ? def_precision : (int)(argv[1].u.integer), argv[0].u.flt); 621 result.type=STRING; 622 } 623 /*}}}*/ 624 else if (argc==3 && argv[0].type==FLOAT && (argv[1].type==INT || argv[1].type==EMPTY) && argv[2].type==INT) /* float to string */ /*{{{*/ 625 { 626 result.u.string=malloc((argv[1].type==INT ? argv[1].u.integer : def_precision)+10); 627 sprintf(result.u.string,argv[2].u.integer ? "%.*e" : "%.*f",argv[1].type==INT && argv[1].u.integer>=0 ? (int)argv[1].u.integer : def_precision, argv[0].u.flt); 628 result.type=STRING; 629 } 630 /*}}}*/ 631 else /* return string type error */ /*{{{*/ 632 { 633 result.type=EEK; 634 result.u.err=strcpy(malloc(strlen(_("Usage: string(location) or string(float[,[integer][,integer]])"))+1),_("Usage: string(location) or string(float[,[integer][,integer]])")); 635 return result; 636 } 637 /*}}}*/ 638 return result; 639 } 640 /*}}}*/ 641 /* sum */ /*{{{*/ 642 static Token sum_func(int argc, const Token argv[]) 643 { 644 /* variables */ /*{{{*/ 645 Token result; 646 /*}}}*/ 647 648 if (argc==2 && argv[0].type==LOCATION && argv[1].type==LOCATION) /* result is sum */ /*{{{*/ 649 { 650 /* variables */ /*{{{*/ 651 int x,y,z; 652 int x1,y1,z1; 653 int x2,y2,z2; 654 Token tmp; 655 /*}}}*/ 656 657 x1=argv[0].u.location[0]; x2=argv[1].u.location[0]; posorder(&x1,&x2); 658 y1=argv[0].u.location[1]; y2=argv[1].u.location[1]; posorder(&y1,&y2); 659 z1=argv[0].u.location[2]; z2=argv[1].u.location[2]; posorder(&z1,&z2); 660 result.type=EMPTY; 661 for (x=x1; x<=x2; ++x) 662 for (y=y1; y<=y2; ++y) 663 for (z=z1; z<=z2; ++z) 664 { 665 Token t; 666 667 tmp=tadd(result,t=getvalue(upd_sheet,x,y,z)); 668 tfree(&t); 669 tfree(&result); 670 result=tmp; 671 if (result.type==EEK) return result; 672 } 673 } 674 /*}}}*/ 675 else /* result is sum type error */ /*{{{*/ 676 { 677 result.type=EEK; 678 result.u.err=strcpy(malloc(strlen(_("Usage: sum(location,location)"))+1),_("Usage: sum(location,location)")); 679 } 680 /*}}}*/ 681 return result; 682 } 683 /*}}}*/ 684 /* n */ /*{{{*/ 685 static Token n_func(int argc, const Token argv[]) 686 { 687 /* variables */ /*{{{*/ 688 Token result; 689 /*}}}*/ 690 691 if (argc==2 && argv[0].type==LOCATION && argv[1].type==LOCATION) 692 /* result is number of elements */ /*{{{*/ 693 { 694 /* variables */ /*{{{*/ 695 int x,y,z; 696 int x1,y1,z1; 697 int x2,y2,z2; 698 Token tmp; 699 int n; 700 /*}}}*/ 701 702 x1=argv[0].u.location[0]; x2=argv[1].u.location[0]; posorder(&x1,&x2); 703 y1=argv[0].u.location[1]; y2=argv[1].u.location[1]; posorder(&y1,&y2); 704 z1=argv[0].u.location[2]; z2=argv[1].u.location[2]; posorder(&z1,&z2); 705 n=0; 706 for (x=x1; x<=x2; ++x) 707 for (y=y1; y<=y2; ++y) 708 for (z=z1; z<=z2; ++z) 709 { 710 tmp=getvalue(upd_sheet,x,y,z); 711 if (tmp.type!=EMPTY) ++n; 712 tfree(&tmp); 713 } 714 result.type=INT; 715 result.u.integer=n; 716 } 717 /*}}}*/ 718 else 719 /* result is n type error */ /*{{{*/ 720 { 721 result.type=EEK; 722 result.u.err=strcpy(malloc(strlen(_("Usage: n(location,location)"))+1),_("Usage: n(location,location)")); 723 } 724 /*}}}*/ 725 return result; 726 } 727 /*}}}*/ 728 /* int */ /*{{{*/ 729 static Token int_func(int argc, const Token argv[]) 730 { 731 /* variables */ /*{{{*/ 732 Token result; 733 /*}}}*/ 734 735 if (argc==1 && argv[0].type==FLOAT) 736 /* result is integer with cutoff fractional part */ /*{{{*/ 737 { 738 result.type=INT; 739 result.u.integer=(long)(argv[0].u.flt); 740 } 741 /*}}}*/ 742 else if (argc==3 && argv[0].type==FLOAT && argv[1].type==INT && argv[2].type==INT) 743 /* result is integer with given conversion */ /*{{{*/ 744 { 745 result.type=INT; 746 if (argv[0].u.flt<0) 747 { 748 if (argv[1].u.integer<-1) result.u.integer=(long)floor(argv[0].u.flt); 749 else if (argv[1].u.integer==-1) result.u.integer=(long)(argv[0].u.flt-0.5); 750 else if (argv[1].u.integer==0) result.u.integer=(long)(argv[0].u.flt); 751 else if (argv[1].u.integer==1) result.u.integer=(long)(argv[0].u.flt+0.5); 752 else result.u.integer=(long)ceil(argv[0].u.flt); 753 } 754 else 755 { 756 if (argv[2].u.integer<-1) result.u.integer=(long)floor(argv[0].u.flt); 757 else if (argv[2].u.integer==-1) result.u.integer=(long)(argv[0].u.flt-0.5); 758 else if (argv[2].u.integer==0) result.u.integer=(long)(argv[0].u.flt); 759 else if (argv[2].u.integer==1) result.u.integer=(long)(argv[0].u.flt+0.5); 760 else result.u.integer=(long)ceil(argv[0].u.flt); 761 } 762 } 763 /*}}}*/ 764 else if (argc==1 && argv[0].type==STRING) 765 /* result is integer */ /*{{{*/ 766 { 767 char *s; 768 769 errno=0; 770 result.u.integer=strtol(argv[0].u.string,&s,10); 771 if (s==(char*)0 || *s) 772 { 773 result.type=EEK; 774 result.u.err=mystrmalloc(_("int(string): invalid string")); 775 } 776 else if (errno==ERANGE && (result.u.integer==LONG_MAX || result.u.integer==LONG_MIN)) 777 { 778 result.type=EEK; 779 result.u.err=mystrmalloc(_("int(string): domain error")); 780 } 781 else result.type=INT; 782 } 783 /*}}}*/ 784 else 785 /* result is int type error */ /*{{{*/ 786 { 787 result.type=EEK; 788 result.u.err=strcpy(malloc(strlen(_("Usage: int(float[,integer,integer])"))+1),_("Usage: int(float[,integer,integer])")); 789 } 790 /*}}}*/ 791 return result; 792 } 793 /*}}}*/ 794 /* frac */ /*{{{*/ 795 static Token frac_func(int argc, const Token argv[]) 796 { 797 /* variables */ /*{{{*/ 798 Token result; 799 double foo; 800 /*}}}*/ 801 802 if (argc==1 && argv[0].type==FLOAT) 803 /* result is fractional part */ /*{{{*/ 804 { 805 result.type=FLOAT; 806 result.u.flt=modf(argv[0].u.flt,&foo); 807 } 808 /*}}}*/ 809 else 810 /* result is frac type error */ /*{{{*/ 811 { 812 result.type=EEK; 813 result.u.err=strcpy(malloc(strlen(_("Usage: frac(float)"))+1),_("Usage: frac(float)")); 814 } 815 /*}}}*/ 816 return result; 817 } 818 /*}}}*/ 819 /* len */ /*{{{*/ 820 static Token len_func(int argc, const Token argv[]) 821 { 822 /* variables */ /*{{{*/ 823 Token result; 824 /*}}}*/ 825 826 if (argc==1 && argv[0].type==STRING) 827 /* result is length */ /*{{{*/ 828 { 829 result.type=INT; 830 result.u.integer=strlen(argv[0].u.string); 831 } 832 /*}}}*/ 833 else 834 /* result is frac type error */ /*{{{*/ 835 { 836 result.type=EEK; 837 result.u.err=mystrmalloc(_("Usage: len(string)")); 838 } 839 /*}}}*/ 840 return result; 841 } 842 /*}}}*/ 843 /* log */ /*{{{*/ 844 static Token log_func(int argc, const Token argv[]) 845 { 846 /* variables */ /*{{{*/ 847 double x=-1.0,y=-1.0; 848 Token result; 849 /*}}}*/ 850 851 /* set x and y to first two arguments */ /*{{{*/ 852 if (argc>=1) 853 { 854 if (argv[0].type==FLOAT) x=argv[0].u.flt; 855 else if (argv[0].type==INT) x=(double)argv[0].u.integer; 856 } 857 if (argc==2) 858 { 859 if (argv[1].type==FLOAT) y=argv[1].u.flt; 860 else if (argv[1].type==INT) y=(double)argv[1].u.integer; 861 } 862 /*}}}*/ 863 if (argc==1 && (argv[0].type==FLOAT || argv[0].type==INT)) /* result is ln(x) */ /*{{{*/ 864 { 865 result.type=FLOAT; 866 result.u.flt=log(x); 867 } 868 /*}}}*/ 869 else if (argc==2 && (argv[0].type==FLOAT || argv[0].type==INT) && (argv[1].type==FLOAT || argv[1].type==INT)) /* result is ln(x)/ln(y) */ /*{{{*/ 870 { 871 result.type=FLOAT; 872 if (y==CONST_E) result.u.flt=log(x); 873 else if (y==10.0) result.u.flt=log10(x); 874 else result.u.flt=log(x)/log(y); 875 } 876 /*}}}*/ 877 else /* result is log type error */ /*{{{*/ 878 { 879 result.type=EEK; 880 result.u.err=mystrmalloc(_("Usage: log(float[,float])")); 881 } 882 /*}}}*/ 883 return result; 884 } 885 /*}}}*/ 886 /* minmax */ /*{{{*/ 887 static Token minmax_func(int argc, const Token argv[], int min) 888 { 889 /* variables */ /*{{{*/ 890 Token result; 891 int resultx,resulty,resultz; 892 /*}}}*/ 893 894 if (argc==2 && argv[0].type==LOCATION && argv[1].type==LOCATION) 895 /* result is min/max */ /*{{{*/ 896 { 897 /* variables */ /*{{{*/ 898 int x,y,z; 899 int x1,y1,z1; 900 int x2,y2,z2; 901 Token tmp; 902 /*}}}*/ 903 904 x1=argv[0].u.location[0]; x2=argv[1].u.location[0]; posorder(&x1,&x2); 905 y1=argv[0].u.location[1]; y2=argv[1].u.location[1]; posorder(&y1,&y2); 906 z1=argv[0].u.location[2]; z2=argv[1].u.location[2]; posorder(&z1,&z2); 907 result=getvalue(upd_sheet,x1,y1,z1); 908 resultx=x1; 909 resulty=y1; 910 resultz=z1; 911 for (x=x1; x<=x2; ++x) 912 for (y=y1; y<=y2; ++y) 913 for (z=z1; z<=z2; ++z) 914 { 915 Token t; 916 917 tmp=(min ? tle(result,t=getvalue(upd_sheet,x,y,z)) : tge(result,t=getvalue(upd_sheet,x,y,z))); 918 if (tmp.type==INT) 919 /* successful comparison */ /*{{{*/ 920 { 921 tfree(&tmp); 922 if (tmp.u.integer==0) 923 { 924 tfree(&result); 925 result=t; 926 resultx=x; 927 resulty=y; 928 resultz=z; 929 } 930 else tfree(&t); 931 } 932 /*}}}*/ 933 else 934 /* successless comparison, return with error */ /*{{{*/ 935 { 936 tfree(&result); 937 tfree(&t); 938 return tmp; 939 } 940 /*}}}*/ 941 } 942 tfree(&result); 943 result.type=LOCATION; 944 result.u.location[0]=resultx; 945 result.u.location[1]=resulty; 946 result.u.location[2]=resultz; 947 return result; 948 } 949 /*}}}*/ 950 else 951 /* result is min/max type error */ /*{{{*/ 952 { 953 result.type=EEK; 954 result.u.err=mystrmalloc(min ? _("Usage: min(location,location)") : _("Usage: max(location,location)")); 955 return result; 956 } 957 /*}}}*/ 958 } 959 /*}}}*/ 960 /* min */ /*{{{*/ 961 static Token min_func(int argc, const Token argv[]) 962 { 963 return minmax_func(argc,argv,1); 964 } 965 /*}}}*/ 966 /* max */ /*{{{*/ 967 static Token max_func(int argc, const Token argv[]) 968 { 969 return minmax_func(argc,argv,0); 970 } 971 /*}}}*/ 972 /* abs */ /*{{{*/ 973 static Token abs_func(int argc, const Token argv[]) 974 { 975 /* variables */ /*{{{*/ 976 Token result; 977 /*}}}*/ 978 979 if (argc==1 && argv[0].type==FLOAT) 980 /* result is absolute floating point number */ /*{{{*/ 981 { 982 result.type=FLOAT; 983 result.u.flt=fabs(argv[0].u.flt); 984 } 985 /*}}}*/ 986 else if (argc==1 && argv[0].type==INT) 987 /* result is absolute integer number */ /*{{{*/ 988 { 989 result.type=INT; 990 result.u.integer=(argv[0].u.integer<0 ? -argv[0].u.integer : argv[0].u.integer); 991 } 992 /*}}}*/ 993 else 994 /* result is abs type error */ /*{{{*/ 995 { 996 result.type=EEK; 997 result.u.err=mystrmalloc(_("Usage: abs(float|integer)")); 998 } 999 /*}}}*/ 1000 return result; 1001 } 1002 /*}}}*/ 1003 /* $ */ /*{{{*/ 1004 static Token env_func(int argc, const Token argv[]) 1005 { 1006 /* variables */ /*{{{*/ 1007 Token result; 1008 /*}}}*/ 1009 1010 if (argc==1 && argv[0].type==STRING) 1011 { 1012 const char *e; 1013 1014 if ((e=getenv(argv[0].u.string))==(char*)0) e=""; 1015 result.type=STRING; 1016 result.u.string=mystrmalloc(e); 1017 } 1018 else 1019 { 1020 result.type=EEK; 1021 result.u.err=mystrmalloc(_("Usage: $(string)")); 1022 } 1023 return result; 1024 } 1025 /*}}}*/ 1026 /* float */ /*{{{*/ 1027 static Token float_func(int argc, const Token argv[]) 1028 { 1029 Token result; 1030 1031 if (argc==1 && argv[0].type==STRING) 1032 /* convert string to float */ /*{{{*/ 1033 { 1034 char *p; 1035 1036 result.u.flt=strtod(argv[0].u.string,&p); 1037 if (p!=argv[0].u.string && *p=='\0' && dblfinite(result.u.flt)==(const char*)0) 1038 { 1039 result.type=FLOAT; 1040 } 1041 else 1042 { 1043 result.type=EEK; 1044 result.u.err=mystrmalloc(_("Not a (finite) floating point number")); 1045 } 1046 } 1047 /*}}}*/ 1048 else 1049 /* float type error */ /*{{{*/ 1050 { 1051 result.type=EEK; 1052 result.u.err=mystrmalloc(_("Usage: float(string)")); 1053 } 1054 /*}}}*/ 1055 return result; 1056 } 1057 /*}}}*/ 1058 /* strftime */ /*{{{*/ 1059 static Token strftime_func(int argc, const Token argv[]) 1060 { 1061 /* variables */ /*{{{*/ 1062 Token result; 1063 /*}}}*/ 1064 1065 if (argc==1 && argv[0].type==STRING) /* format and return string */ /*{{{*/ 1066 { 1067 time_t t; 1068 struct tm *tm; 1069 char s[1024]; 1070 1071 t=time((time_t*)0); 1072 tm=localtime(&t); 1073 strftime(s,sizeof(s),argv[0].u.string,tm); 1074 s[sizeof(s)-1]='\0'; 1075 result.u.string=mystrmalloc(s); 1076 result.type=STRING; 1077 } 1078 /*}}}*/ 1079 else if (argc==2 && argv[0].type==STRING && argv[1].type==INT) /* format and return string */ /*{{{*/ 1080 { 1081 time_t t; 1082 struct tm *tm; 1083 char s[1024]; 1084 1085 t=argv[1].u.integer; 1086 tm=localtime(&t); 1087 strftime(s,sizeof(s),argv[0].u.string,tm); 1088 s[sizeof(s)-1]='\0'; 1089 result.u.string=mystrmalloc(s); 1090 result.type=STRING; 1091 } 1092 /*}}}*/ 1093 else /* strftime type error */ /*{{{*/ 1094 { 1095 result.type=EEK; 1096 result.u.err=mystrmalloc(_("Usage: strftime(string[,integer])")); 1097 } 1098 /*}}}*/ 1099 return result; 1100 } 1101 /*}}}*/ 1102 /* clock */ /*{{{*/ 1103 static Token clock_func(int argc, const Token argv[]) 1104 { 1105 /* variables */ /*{{{*/ 1106 Token result; 1107 /*}}}*/ 1108 1109 if (argc==2 && argv[0].type==INT && argv[1].type==LOCATION) /* clock(condition,location) */ /*{{{*/ 1110 { 1111 if (argv[0].u.integer) clk(upd_sheet,argv[1].u.location[0],argv[1].u.location[1],argv[1].u.location[2]); 1112 result.type=EMPTY; 1113 } 1114 /*}}}*/ 1115 else if (argc==3 && argv[0].type==INT && argv[1].type==LOCATION && argv[2].type==LOCATION) /* clock(condition,location,location) */ /*{{{*/ 1116 { 1117 if (argv[0].u.integer) 1118 { 1119 /* variables */ /*{{{*/ 1120 int x,y,z; 1121 int x1,y1,z1; 1122 int x2,y2,z2; 1123 /*}}}*/ 1124 1125 x1=argv[1].u.location[0]; x2=argv[2].u.location[0]; posorder(&x1,&x2); 1126 y1=argv[1].u.location[1]; y2=argv[2].u.location[1]; posorder(&y1,&y2); 1127 z1=argv[1].u.location[2]; z2=argv[2].u.location[2]; posorder(&z1,&z2); 1128 for (x=x1; x<=x2; ++x) 1129 for (y=y1; y<=y2; ++y) 1130 for (z=z1; z<=z2; ++z) clk(upd_sheet,x,y,z); 1131 } 1132 result.type=EMPTY; 1133 } 1134 /*}}}*/ 1135 else /* wrong usage */ /*{{{*/ 1136 { 1137 result.type=EEK; 1138 result.u.err=mystrmalloc(_("Usage: clock(condition,location[,location])")); 1139 } 1140 /*}}}*/ 1141 return result; 1142 } 1143 /*}}}*/ 1144 /* poly */ /*{{{*/ 1145 static Token poly_func(int argc, const Token argv[]) 1146 { 1147 /* variables */ /*{{{*/ 1148 Token result; 1149 int i; 1150 /*}}}*/ 1151 1152 for (i=0; i<argc; ++i) if (argc<2 || (argv[i].type!=INT && argv[i].type!=FLOAT)) /* type error */ /*{{{*/ 1153 { 1154 result.type=EEK; 1155 result.u.err=strcpy(malloc(strlen(_("Usage: poly(float|integer,float|integer,...)"))+1),_("Usage: poly(float|integer,float|integer,...)")); 1156 } 1157 /*}}}*/ 1158 else 1159 { 1160 Token tmp; 1161 1162 result=tcopy(argv[1]); 1163 for (i=2; i<argc; ++i) 1164 { 1165 tmp=tmul(result,argv[0]); 1166 tfree(&result); 1167 result=tmp; 1168 tmp=tadd(result,argv[i]); 1169 tfree(&result); 1170 result=tmp; 1171 if (result.type==EEK) return result; 1172 } 1173 } 1174 return result; 1175 } 1176 /*}}}*/ 1177 /* sin */ /*{{{*/ 1178 static Token sin_func(int argc, const Token argv[]) 1179 { 1180 return sci_func(argc,argv,sin,"sin"); 1181 } 1182 /*}}}*/ 1183 /* cos */ /*{{{*/ 1184 static Token cos_func(int argc, const Token argv[]) 1185 { 1186 return sci_func(argc,argv,cos,"cos"); 1187 } 1188 /*}}}*/ 1189 /* tan */ /*{{{*/ 1190 static Token tan_func(int argc, const Token argv[]) 1191 { 1192 return sci_func(argc,argv,tan,"tan"); 1193 } 1194 /*}}}*/ 1195 /* sinh */ /*{{{*/ 1196 static Token sinh_func(int argc, const Token argv[]) 1197 { 1198 return sci_func(argc,argv,sinh,"sinh"); 1199 } 1200 /*}}}*/ 1201 /* cosh */ /*{{{*/ 1202 static Token cosh_func(int argc, const Token argv[]) 1203 { 1204 return sci_func(argc,argv,cosh,"cosh"); 1205 } 1206 /*}}}*/ 1207 /* tanh */ /*{{{*/ 1208 static Token tanh_func(int argc, const Token argv[]) 1209 { 1210 return sci_func(argc,argv,tanh,"tanh"); 1211 } 1212 /*}}}*/ 1213 /* asin */ /*{{{*/ 1214 static Token asin_func(int argc, const Token argv[]) 1215 { 1216 return sci_func(argc,argv,asin,"asin"); 1217 } 1218 /*}}}*/ 1219 /* acos */ /*{{{*/ 1220 static Token acos_func(int argc, const Token argv[]) 1221 { 1222 return sci_func(argc,argv,acos,"acos"); 1223 } 1224 /*}}}*/ 1225 /* atan */ /*{{{*/ 1226 static Token atan_func(int argc, const Token argv[]) 1227 { 1228 return sci_func(argc,argv,atan,"atan"); 1229 } 1230 /*}}}*/ 1231 /* arsinh */ /*{{{*/ 1232 static Token arsinh_func(int argc, const Token argv[]) 1233 { 1234 return sci_func(argc,argv,arsinh,"arsinh"); 1235 } 1236 /*}}}*/ 1237 /* arcosh */ /*{{{*/ 1238 static Token arcosh_func(int argc, const Token argv[]) 1239 { 1240 return sci_func(argc,argv,arcosh,"arcosh"); 1241 } 1242 /*}}}*/ 1243 /* artanh */ /*{{{*/ 1244 static Token artanh_func(int argc, const Token argv[]) 1245 { 1246 return sci_func(argc,argv,artanh,"artanh"); 1247 } 1248 /*}}}*/ 1249 /* rad2deg */ /*{{{*/ 1250 static Token rad2deg_func(int argc, const Token argv[]) 1251 { 1252 return sci_func(argc,argv,rad2deg,"rad2deg"); 1253 } 1254 /*}}}*/ 1255 /* deg2rad */ /*{{{*/ 1256 static Token deg2rad_func(int argc, const Token argv[]) 1257 { 1258 return sci_func(argc,argv,deg2rad,"deg2rad"); 1259 } 1260 /*}}}*/ 1261 /* rnd */ /*{{{*/ 1262 static Token rnd_func(int argc, const Token argv[]) 1263 { 1264 /* variables */ /*{{{*/ 1265 Token result; 1266 /*}}}*/ 1267 1268 if (argc==0) 1269 { 1270 result.type=FLOAT; 1271 result.u.flt=rand()/((double)RAND_MAX); 1272 } 1273 else 1274 { 1275 result.type=EEK; 1276 result.u.err=mystrmalloc(_("Usage: rnd()")); 1277 } 1278 return result; 1279 } 1280 /*}}}*/ 1281 /* substr */ /*{{{*/ 1282 static Token substr_func(int argc, const Token argv[]) 1283 { 1284 /* variables */ /*{{{*/ 1285 Token result; 1286 /*}}}*/ 1287 1288 if (argc==3 && argv[0].type==STRING && argv[1].type==INT && argv[2].type==INT) 1289 { 1290 char ss[1024]; 1291 int n, l, b, e; 1292 1293 b = argv[1].u.integer; 1294 e = argv[2].u.integer; 1295 l = strlen(argv[0].u.string); 1296 if( b < 0 ) b = 0; 1297 if( b > l ) b = l; 1298 if( e > l ) e = l; 1299 n = e - b + 1; 1300 if( n >= 1024 ) n = 1024 - 1; 1301 if(n > 0) { 1302 ss[n] = '\0'; 1303 strncpy(ss, argv[0].u.string + b, n); 1304 result.type=STRING; 1305 result.u.string=mystrmalloc(ss); 1306 } 1307 else { 1308 result.type=EMPTY; 1309 } 1310 } 1311 else 1312 { 1313 result.type=EEK; 1314 result.u.err=mystrmalloc(_("Usage: substr(string,integer,integer)")); 1315 } 1316 return result; 1317 } 1318 /*}}}*/ 1319 /* strptime */ /*{{{*/ 1320 static Token strptime_func(int argc, const Token argv[]) 1321 { 1322 /* variables */ /*{{{*/ 1323 Token result; 1324 /*}}}*/ 1325 1326 if (argc==2 && argv[0].type==STRING && argv[1].type==STRING) /* format and return string */ /*{{{*/ 1327 { 1328 time_t t; 1329 struct tm tm; 1330 1331 t=time((time_t*)0); 1332 tm=*localtime(&t); 1333 strptime(argv[1].u.string,argv[0].u.string,&tm); 1334 result.u.integer=mktime(&tm); 1335 result.type=INT; 1336 } 1337 /*}}}*/ 1338 else /* strftime type error */ /*{{{*/ 1339 { 1340 result.type=EEK; 1341 result.u.err=mystrmalloc(_("Usage: strptime(string,string)")); 1342 } 1343 /*}}}*/ 1344 return result; 1345 } 1346 /*}}}*/ 1347 /* time */ /*{{{*/ 1348 static Token time_func(int argc, const Token argv[]) 1349 { 1350 Token result; 1351 1352 if (argc==0) 1353 { 1354 result.type=INT; 1355 result.u.integer=time((time_t*)0); 1356 } 1357 else 1358 { 1359 result.type=EEK; 1360 result.u.err=mystrmalloc(_("Usage: time()")); 1361 } 1362 return result; 1363 } 1364 /*}}}*/ 1365 1366 /* table of functions */ /*{{{*/ 1367 /* The order of these entries has no influence on performance, but to stay 1368 compatible, new entries should be appended. */ 1369 Tfunc tfunc[]= 1370 { 1371 { "@", at_func }, 1372 { "&", adr_func }, 1373 { "x", x_func }, 1374 { "y", y_func }, 1375 { "z", z_func }, 1376 { "eval", eval_func }, 1377 { "error", error_func }, 1378 { "string", string_func }, 1379 { "sum", sum_func }, 1380 { "n", n_func }, 1381 { "int", int_func }, 1382 { "frac", frac_func }, 1383 { "len", len_func }, 1384 { "min", min_func }, 1385 { "max", max_func }, 1386 { "abs", abs_func }, 1387 { "$", env_func }, 1388 { "float", float_func }, 1389 { "strftime", strftime_func }, 1390 { "clock", clock_func }, 1391 { "poly", poly_func }, 1392 { "e", e_func }, 1393 { "log", log_func }, 1394 { "sin", sin_func }, 1395 { "cos", cos_func }, 1396 { "tan", tan_func }, 1397 { "sinh", sinh_func }, 1398 { "cosh", cosh_func }, 1399 { "tanh", tanh_func }, 1400 { "asin", asin_func }, 1401 { "acos", acos_func }, 1402 { "atan", atan_func }, 1403 { "arsinh", arsinh_func }, 1404 { "arcosh", arcosh_func }, 1405 { "artanh", artanh_func }, 1406 { "deg2rad", deg2rad_func }, 1407 { "rad2deg", rad2deg_func }, 1408 { "rnd", rnd_func }, 1409 { "substr", substr_func }, 1410 { "strptime", strptime_func }, 1411 { "time", time_func }, 1412 { "", (Token (*)(int, const Token[]))0 } 1413 }; 1414 /*}}}*/