2019-07-22 20:32:33 +00:00
/* #includes */ /*{{{C}}}*/ /*{{{*/
# ifndef NO_POSIX_SOURCE
# undef _POSIX_SOURCE
# define _POSIX_SOURCE 1
# undef _POSIX_C_SOURCE
# define _POSIX_C_SOURCE 2
# endif
# define _XOPEN_SOURCE /* glibc2 needs this */
# ifdef DMALLOC
# include "dmalloc.h"
# endif
# include <assert.h>
# include <errno.h>
# include <limits.h>
# include <math.h>
# include <stdlib.h>
extern double strtod ( const char * nptr , char * * endptr ) ; /* SunOS 4 hack */
# include <stdio.h>
# include <string.h>
# include <time.h>
# include "default.h"
# include "eval.h"
# include "func.h"
# include "main.h"
# include "misc.h"
# include "parser.h"
# include "scanner.h"
# include "sheet.h"
/*}}}*/
/* #defines */ /*{{{*/
/* There is a BSD extensions, but they are possibly more exact. */
# ifdef M_E
# define CONST_E M_E
# else
# define CONST_E ((double)2.7182818284590452354)
# endif
# ifdef M_PI
# define CONST_PI M_PI
# else
# define CONST_PI ((double)3.14159265358979323846)
# endif
/*}}}*/
# ifdef WIN32
// This strptime implementation Copyright 2009 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Implement strptime under windows
static const char * kWeekFull [ ] = {
" Sunday " , " Monday " , " Tuesday " , " Wednesday " ,
" Thursday " , " Friday " , " Saturday "
} ;
static const char * kWeekAbbr [ ] = {
" Sun " , " Mon " , " Tue " , " Wed " ,
" Thu " , " Fri " , " Sat "
} ;
static const char * kMonthFull [ ] = {
" January " , " February " , " March " , " April " , " May " , " June " ,
" July " , " August " , " September " , " October " , " November " , " December "
} ;
static const char * kMonthAbbr [ ] = {
" Jan " , " Feb " , " Mar " , " Apr " , " May " , " Jun " ,
" Jul " , " Aug " , " Sep " , " Oct " , " Nov " , " Dec "
} ;
static const char * _parse_num ( const char * s , int low , int high , int * value ) {
const char * p = s ;
for ( * value = 0 ; * p & & isdigit ( * p ) ; + + p ) {
* value = ( * value ) * 10 + * p - ' 0 ' ;
}
if ( p = = s | | * value < low | | * value > high ) return NULL ;
return p ;
}
static char * _strptime ( const char * s , const char * format , struct tm * tm ) {
int i , len ;
while ( * format & & * s ) {
if ( * format ! = ' % ' ) {
if ( * s ! = * format ) return NULL ;
+ + format ;
+ + s ;
continue ;
}
+ + format ;
len = 0 ;
switch ( * format ) {
// weekday name.
case ' a ' :
case ' A ' :
tm - > tm_wday = - 1 ;
for ( i = 0 ; i < 7 ; + + i ) {
len = strlen ( kWeekAbbr [ i ] ) ;
if ( strnicmp ( kWeekAbbr [ i ] , s , len ) = = 0 ) {
tm - > tm_wday = i ;
break ;
}
len = strlen ( kWeekFull [ i ] ) ;
if ( strnicmp ( kWeekFull [ i ] , s , len ) = = 0 ) {
tm - > tm_wday = i ;
break ;
}
}
if ( tm - > tm_wday = = - 1 ) return NULL ;
s + = len ;
break ;
// month name.
case ' b ' :
case ' B ' :
case ' h ' :
tm - > tm_mon = - 1 ;
for ( i = 0 ; i < 12 ; + + i ) {
len = strlen ( kMonthAbbr [ i ] ) ;
if ( strnicmp ( kMonthAbbr [ i ] , s , len ) = = 0 ) {
tm - > tm_mon = i ;
break ;
}
len = strlen ( kMonthFull [ i ] ) ;
if ( strnicmp ( kMonthFull [ i ] , s , len ) = = 0 ) {
tm - > tm_mon = i ;
break ;
}
}
if ( tm - > tm_mon = = - 1 ) return NULL ;
s + = len ;
break ;
// month [1, 12].
case ' m ' :
s = _parse_num ( s , 1 , 12 , & tm - > tm_mon ) ;
if ( s = = NULL ) return NULL ;
- - tm - > tm_mon ;
break ;
// day [1, 31].
case ' d ' :
case ' e ' :
s = _parse_num ( s , 1 , 31 , & tm - > tm_mday ) ;
if ( s = = NULL ) return NULL ;
break ;
// hour [0, 23].
case ' H ' :
s = _parse_num ( s , 0 , 23 , & tm - > tm_hour ) ;
if ( s = = NULL ) return NULL ;
break ;
// minute [0, 59]
case ' M ' :
s = _parse_num ( s , 0 , 59 , & tm - > tm_min ) ;
if ( s = = NULL ) return NULL ;
break ;
// seconds [0, 60]. 60 is for leap year.
case ' S ' :
s = _parse_num ( s , 0 , 60 , & tm - > tm_sec ) ;
if ( s = = NULL ) return NULL ;
break ;
// year [1900, 9999].
case ' Y ' :
s = _parse_num ( s , 1900 , 9999 , & tm - > tm_year ) ;
if ( s = = NULL ) return NULL ;
tm - > tm_year - = 1900 ;
break ;
// year [0, 99].
case ' y ' :
s = _parse_num ( s , 0 , 99 , & tm - > tm_year ) ;
if ( s = = NULL ) return NULL ;
if ( tm - > tm_year < = 68 ) {
tm - > tm_year + = 100 ;
}
break ;
// arbitray whitespace.
case ' t ' :
case ' n ' :
while ( isspace ( * s ) ) + + s ;
break ;
// '%'.
case ' % ' :
if ( * s ! = ' % ' ) return NULL ;
+ + s ;
break ;
// All the other format are not supported.
default :
return NULL ;
}
+ + format ;
}
if ( * format ) {
return NULL ;
} else {
return ( char * ) s ;
}
}
char * strptime ( const char * buf , const char * fmt , struct tm * tm ) {
return _strptime ( buf , fmt , tm ) ;
}
# endif
/* sci_func -- map a double to a double */ /*{{{*/
static Token sci_func ( int argc , const Token argv [ ] , double ( * func ) ( double ) , const char * func_name )
{
Token result ;
if ( argc = = 1 & & argv [ 0 ] . type = = FLOAT )
{
result . type = FLOAT ;
errno = 0 ;
result . u . flt = ( func ) ( argv [ 0 ] . u . flt ) ;
if ( errno )
{
result . type = EEK ;
result . u . err = malloc ( strlen ( func_name ) + 2 + strlen ( strerror ( errno ) ) + 1 ) ;
sprintf ( result . u . err , " %s: %s " , func_name , strerror ( errno ) ) ;
}
}
else
{
if ( argc = = 1 & & argv [ 0 ] . type = = INT )
{
result . type = FLOAT ;
errno = 0 ;
result . u . flt = ( func ) ( ( double ) argv [ 0 ] . u . integer ) ;
if ( errno )
{
result . type = EEK ;
result . u . err = malloc ( strlen ( func_name ) + 2 + strlen ( strerror ( errno ) ) + 1 ) ;
sprintf ( result . u . err , " %s: %s " , func_name , strerror ( errno ) ) ;
}
}
else
{
result . type = EEK ;
/* This is actually too much, but always enough for %s formats. */
result . u . err = malloc ( strlen ( _ ( " Usage: %s(float) " ) ) + strlen ( func_name ) + 1 ) ;
sprintf ( result . u . err , _ ( " Usage: %s(float) " ) , func_name ) ;
}
}
return result ;
}
/*}}}*/
/* arsinh */ /*{{{*/
static double arsinh ( double x )
{
return log ( x + sqrt ( x * x + 1.0 ) ) ;
}
/*}}}*/
/* arcosh */ /*{{{*/
static double arcosh ( double x )
{
if ( x > = 1.0 ) return log ( x + sqrt ( x * x - 1.0 ) ) ;
else { errno = EDOM ; return 0.0 ; }
}
/*}}}*/
/* artanh */ /*{{{*/
static double artanh ( double x )
{
if ( x > - 1.0 & & x < 1.0 ) return 0.5 * log ( ( 1.0 + x ) / ( 1.0 - x ) ) ;
else { errno = EDOM ; return 0.0 ; }
}
/*}}}*/
/* rad2deg */ /*{{{*/
static double rad2deg ( double x )
{
return ( 360.0 / ( 2.0 * CONST_PI ) ) * x ;
}
/*}}}*/
/* deg2rad */ /*{{{*/
static double deg2rad ( double x )
{
return ( 2.0 * CONST_PI / 360.0 ) * x ;
}
/*}}}*/
2019-07-27 04:14:26 +00:00
# define INTPATIBLE(t) (t.type == INT || t.type == EMPTY)
2019-07-22 20:32:33 +00:00
/* @ */ /*{{{*/
static Token at_func ( int argc , const Token argv [ ] )
{
/* variables */ /*{{{*/
Token result ;
2019-07-27 04:14:26 +00:00
Location tmp ;
Dimensions dim ;
2019-07-22 20:32:33 +00:00
/*}}}*/
/* asserts */ /*{{{*/
assert ( argv ! = ( Token * ) 0 ) ;
/*}}}*/
if ( argc = = 0 )
/* return value at current location */ /*{{{*/
2019-07-27 04:14:26 +00:00
return ( getvalue ( upd_sheet , upd_l ) ) ;
2019-07-22 20:32:33 +00:00
/*}}}*/
if ( argc = = 1 & & argv [ 0 ] . type = = LOCATION )
/* return value at location pointed to by argument */ /*{{{*/
2019-07-27 04:14:26 +00:00
return ( getvalue ( upd_sheet , argv [ 0 ] . u . location ) ) ;
2019-07-22 20:32:33 +00:00
/*}}}*/
2019-07-27 04:14:26 +00:00
LOCATION_GETS ( tmp , upd_l ) ;
if ( argc = = 1 & & ( argv [ 0 ] . type = = INT | | argv [ 0 ] . type = = EMPTY ) )
2019-07-22 20:32:33 +00:00
/* return value at x on current y,z */ /*{{{*/
2019-07-27 04:14:26 +00:00
{
if ( argv [ 0 ] . type = = INT ) tmp [ X ] = argv [ 0 ] . u . integer ;
return getvalue ( upd_sheet , tmp ) ;
}
2019-07-22 20:32:33 +00:00
/*}}}*/
2019-07-27 04:14:26 +00:00
if ( argc = = 2 & & INTPATIBLE ( argv [ 0 ] ) & & INTPATIBLE ( argv [ 1 ] ) )
2019-07-22 20:32:33 +00:00
/* return value at x,y on current z */ /*{{{*/
2019-07-27 04:14:26 +00:00
{
if ( argv [ 0 ] . type = = INT ) tmp [ X ] = argv [ 0 ] . u . integer ;
if ( argv [ 1 ] . type = = INT ) tmp [ Y ] = argv [ 1 ] . u . integer ;
return getvalue ( upd_sheet , tmp ) ;
}
2019-07-22 20:32:33 +00:00
/*}}}*/
2019-07-27 04:14:26 +00:00
if ( argc = = 3 & & INTPATIBLE ( argv [ 0 ] ) & & INTPATIBLE ( argv [ 1 ] ) & &
INTPATIBLE ( argv [ 2 ] ) )
2019-07-22 20:32:33 +00:00
/* return value at x,y,z */ /*{{{*/
2019-07-27 04:14:26 +00:00
{
for ( dim = X ; dim < HYPER ; + + dim )
if ( argv [ dim ] . type = = INT ) tmp [ dim ] = argv [ dim ] . u . integer ;
return getvalue ( upd_sheet , tmp ) ;
}
2019-07-22 20:32:33 +00:00
/*}}}*/
else
/* return error */ /*{{{*/
{
result . type = EEK ;
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) " ) ) ;
return result ;
}
/*}}}*/
}
/*}}}*/
2019-07-27 04:14:26 +00:00
2019-07-22 20:32:33 +00:00
/* & */ /*{{{*/
static Token adr_func ( int argc , const Token argv [ ] )
{
/* variables */ /*{{{*/
Token result ;
2019-07-27 04:14:26 +00:00
Dimensions dim ;
2019-07-22 20:32:33 +00:00
/*}}}*/
/* asserts */ /*{{{*/
2019-07-27 04:14:26 +00:00
assert ( argv ! = ( Token * ) 0 ) ;
2019-07-22 20:32:33 +00:00
/*}}}*/
2019-07-27 04:14:26 +00:00
LOCATION_GETS ( result . u . location , upd_l ) ;
if ( argc = = 3 & & INTPATIBLE ( argv [ 0 ] ) & & INTPATIBLE ( argv [ 1 ] ) & &
INTPATIBLE ( argv [ 2 ] ) )
2019-07-22 20:32:33 +00:00
/* result is location of the given position */ /*{{{*/
{
result . type = LOCATION ;
2019-07-27 04:14:26 +00:00
for ( dim = X ; dim < HYPER ; + + dim )
if ( argv [ dim ] . type = = INT ) result . u . location [ dim ] = argv [ dim ] . u . integer ;
2019-07-22 20:32:33 +00:00
}
/*}}}*/
2019-07-27 04:14:26 +00:00
else if ( argc = = 2 & & INTPATIBLE ( argv [ 0 ] ) & & INTPATIBLE ( argv [ 1 ] ) )
2019-07-22 20:32:33 +00:00
/* result is location of the given position in the current z layer */ /*{{{*/
{
result . type = LOCATION ;
2019-07-27 04:14:26 +00:00
for ( dim = X ; dim < = Y ; + + dim )
if ( argv [ dim ] . type = = INT ) result . u . location [ dim ] = argv [ dim ] . u . integer ;
2019-07-22 20:32:33 +00:00
}
/*}}}*/
2019-07-27 04:14:26 +00:00
else if ( argc = = 1 & & INTPATIBLE ( argv [ 0 ] ) )
2019-07-22 20:32:33 +00:00
/* result is location of the given position in the current y,z layer */ /*{{{*/
{
result . type = LOCATION ;
2019-07-27 04:14:26 +00:00
if ( argv [ 0 ] . type = = INT ) result . u . location [ X ] = argv [ 0 ] . u . integer ;
2019-07-22 20:32:33 +00:00
}
/*}}}*/
else if ( argc = = 0 )
/* result is location of the current position */ /*{{{*/
{
result . type = LOCATION ;
}
/*}}}*/
else
/* result is type error */ /*{{{*/
{
result . type = EEK ;
result . u . err = strcpy ( malloc ( strlen ( _ ( " Usage: &([integer x][,[integer y][,[integer z]]]) " ) ) + 1 ) , _ ( " Usage: &([integer x][,[integer y][,[integer z]]]) " ) ) ;
}
/*}}}*/
return result ;
}
/*}}}*/
2019-07-27 04:14:26 +00:00
2019-07-22 20:32:33 +00:00
/* x */ /*{{{*/
static Token x_func ( int argc , const Token argv [ ] )
{
/* variables */ /*{{{*/
Token result ;
/*}}}*/
if ( argc = = 0 )
/* result is currently updated x position */ /*{{{*/
{
2019-07-27 04:14:26 +00:00
result . type = INT ;
result . u . integer = upd_l [ X ] ;
2019-07-22 20:32:33 +00:00
}
/*}}}*/
else if ( argc = = 1 & & argv [ 0 ] . type = = LOCATION )
/* return x component of location */ /*{{{*/
{
2019-07-27 04:14:26 +00:00
result . type = INT ;
result . u . integer = argv [ 0 ] . u . location [ X ] ;
2019-07-22 20:32:33 +00:00
}
/*}}}*/
else
/* x type error */ /*{{{*/
{
result . type = EEK ;
result . u . err = strcpy ( malloc ( strlen ( _ ( " Usage: x([location]) " ) ) + 1 ) , _ ( " Usage: x([location]) " ) ) ;
}
/*}}}*/
return result ;
}
/*}}}*/
2019-07-27 04:14:26 +00:00
2019-07-22 20:32:33 +00:00
/* y */ /*{{{*/
static Token y_func ( int argc , const Token argv [ ] )
{
/* variables */ /*{{{*/
Token result ;
/*}}}*/
if ( argc = = 0 )
/* result is currently updated y position */ /*{{{*/
{
2019-07-27 04:14:26 +00:00
result . type = INT ;
result . u . integer = upd_l [ Y ] ;
2019-07-22 20:32:33 +00:00
}
/*}}}*/
else if ( argc = = 1 & & argv [ 0 ] . type = = LOCATION )
/* return y component of location */ /*{{{*/
{
2019-07-27 04:14:26 +00:00
result . type = INT ;
result . u . integer = argv [ 0 ] . u . location [ Y ] ;
2019-07-22 20:32:33 +00:00
}
/*}}}*/
else
/* y type error */ /*{{{*/
{
result . type = EEK ;
result . u . err = strcpy ( malloc ( strlen ( _ ( " Usage: y([location]) " ) ) + 1 ) , _ ( " Usage: y([location]) " ) ) ;
}
/*}}}*/
return result ;
}
/*}}}*/
2019-07-27 04:14:26 +00:00
2019-07-22 20:32:33 +00:00
/* z */ /*{{{*/
static Token z_func ( int argc , const Token argv [ ] )
{
/* variables */ /*{{{*/
Token result ;
/*}}}*/
if ( argc = = 0 )
/* result is currently updated z position */ /*{{{*/
{
2019-07-27 04:14:26 +00:00
result . type = INT ;
result . u . integer = upd_l [ Z ] ;
2019-07-22 20:32:33 +00:00
}
/*}}}*/
2019-07-27 04:14:26 +00:00
else if ( argc = = 1 & & argv [ 0 ] . type = = LOCATION )
2019-07-22 20:32:33 +00:00
/* return z component of location */ /*{{{*/
{
2019-07-27 04:14:26 +00:00
result . type = INT ;
result . u . integer = argv [ 0 ] . u . location [ Z ] ;
2019-07-22 20:32:33 +00:00
}
/*}}}*/
else
/* result is z type error */ /*{{{*/
{
result . type = EEK ;
result . u . err = mystrmalloc ( _ ( " Usage: z([location]) " ) ) ;
}
/*}}}*/
return result ;
}
/*}}}*/
2019-07-27 04:14:26 +00:00
2019-07-29 17:22:15 +00:00
typedef enum { LOG_AND , LOG_OR } LogicalFunction ;
static Token bitwise_func ( int argc , const Token argv [ ] , LogicalFunction lop )
{
Token result ;
int accum ;
if ( lop = = LOG_AND ) accum = - 1 ;
else accum = 0 ;
for ( size_t i = 0 ; i < argc ; + + i ) {
if ( ! INTPATIBLE ( argv [ i ] ) )
{
result . type = EEK ;
result . u . err =
mystrmalloc ( _ ( " Bitwise functions operate only on integers. " ) ) ;
return result ;
}
int val = 0 ;
if ( argv [ i ] . type = = INT ) val = argv [ i ] . u . integer ;
if ( lop = = LOG_AND ) accum = accum & val ;
else accum = accum | val ;
}
result . type = INT ;
result . u . integer = accum ;
return result ;
}
static Token bitand_func ( int argc , const Token argv [ ] )
{
return bitwise_func ( argc , argv , LOG_AND ) ;
}
static Token bitor_func ( int argc , const Token argv [ ] )
{
return bitwise_func ( argc , argv , LOG_OR ) ;
}
2019-07-22 20:32:33 +00:00
/* e */ /*{{{*/
static Token e_func ( int argc , const Token argv [ ] )
{
/* variables */ /*{{{*/
Token result ;
/*}}}*/
if ( argc = = 0 ) /* result is constant e */ /*{{{*/
{
result . type = FLOAT ;
result . u . flt = CONST_E ;
}
/*}}}*/
else /* result is e type error */ /*{{{*/
{
result . type = EEK ;
result . u . err = mystrmalloc ( _ ( " Usage: e() " ) ) ;
}
/*}}}*/
return result ;
}
/*}}}*/
/* eval */ /*{{{*/
static Token eval_func ( int argc , const Token argv [ ] )
{
/* variables */ /*{{{*/
Token result ;
/*}}}*/
- - max_eval ;
if ( max_eval < 0 )
/* nesting error */ /*{{{*/
{
result . type = EEK ;
result . u . err = mystrmalloc ( _ ( " nested eval() " ) ) ;
}
/*}}}*/
else if ( argc = = 1 & & argv [ 0 ] . type = = LOCATION )
/* evaluate expression in cell at given position */ /*{{{*/
{
Token * * contents ;
2019-07-27 04:14:26 +00:00
contents = EMPTY_TVEC ;
if ( LOC_WITHIN ( upd_sheet , argv [ 0 ] . u . location ) )
contents = getcont ( CELL_AT ( upd_sheet , argv [ 0 ] . u . location ) , CONTINGENT ) ;
if ( contents = = EMPTY_TVEC ) result . type = EMPTY ;
2019-07-22 20:32:33 +00:00
else result = eval ( contents ) ;
}
/*}}}*/
else
/* eval type error */ /*{{{*/
{
result . type = EEK ;
result . u . err = strcpy ( malloc ( strlen ( _ ( " Usage: eval(location) " ) ) + 1 ) , _ ( " Usage: eval(location) " ) ) ;
}
/*}}}*/
+ + max_eval ;
return result ;
}
/*}}}*/
2019-07-27 04:14:26 +00:00
2019-07-22 20:32:33 +00:00
/* error */ /*{{{*/
static Token error_func ( int argc , const Token argv [ ] )
{
/* variables */ /*{{{*/
Token result ;
/*}}}*/
/* asserts */ /*{{{*/
assert ( argv ! = ( Token * ) 0 ) ;
/*}}}*/
result . type = EEK ;
if ( argc ! = 1 | | argv [ 0 ] . type ! = STRING )
/* result is type error */ /*{{{*/
result . u . err = strcpy ( malloc ( strlen ( _ ( " Usage: error(string message) " ) ) + 1 ) , _ ( " Usage: error(string message) " ) ) ;
/*}}}*/
else
/* result is user defined error */ /*{{{*/
result . u . err = strcpy ( malloc ( strlen ( argv [ 0 ] . u . string ) + 1 ) , argv [ 0 ] . u . string ) ;
/*}}}*/
return result ;
}
/*}}}*/
/* string */ /*{{{*/
static Token string_func ( int argc , const Token argv [ ] )
{
/* variables */ /*{{{*/
Token result ;
2019-07-27 04:14:26 +00:00
Cell * cell ;
2019-07-22 20:32:33 +00:00
char * buf ;
2019-07-27 04:14:26 +00:00
char staticbuf [ 4096 ] ;
2019-07-22 20:32:33 +00:00
size_t size ;
/*}}}*/
if ( argc = = 1 & & argv [ 0 ] . type = = LOCATION ) /* cell to string */ /*{{{*/
{
result . type = STRING ;
2019-07-27 04:14:26 +00:00
if ( LOC_WITHIN ( upd_sheet , argv [ 0 ] . u . location ) )
{
cell = CELL_AT ( upd_sheet , argv [ 0 ] . u . location ) ;
printvalue ( staticbuf , sizeof ( staticbuf ) , 0 , 0 , getscientific ( cell ) ,
getprecision ( cell ) , upd_sheet , argv [ 0 ] . u . location ) ;
result . u . string = malloc ( strlen ( staticbuf ) + 1 ) ;
strcpy ( result . u . string , staticbuf ) ;
}
else
{
result . u . string = malloc ( 1 ) ;
result . u . string [ 0 ] = ' \0 ' ;
}
2019-07-22 20:32:33 +00:00
}
/*}}}*/
else if ( argc = = 1 & & argv [ 0 ] . type = = FLOAT ) /* float to string */ /* { { { */
{
result . u . string = malloc ( def_precision + 10 ) ;
sprintf ( result . u . string , DEF_SCIENTIFIC ? " %.*e " : " %.*f " , def_precision , argv [ 0 ] . u . flt ) ;
result . type = STRING ;
}
/*}}}*/
else if ( argc = = 1 & & argv [ 0 ] . type = = INT ) /* int to string */ /* { { { */
{
int length = 2 ;
int n = argv [ 0 ] . u . integer ;
while ( n ! = 0 ) n / = 10 ;
result . u . string = malloc ( length ) ;
sprintf ( result . u . string , " %ld " , argv [ 0 ] . u . integer ) ;
result . type = STRING ;
}
/*}}}*/
else if ( argc = = 2 & & argv [ 0 ] . type = = FLOAT & & argv [ 1 ] . type = = INT ) /* float to string */ /* { { { */
{
result . u . string = malloc ( argv [ 1 ] . u . integer = = - 1 ? def_precision + 10 : argv [ 1 ] . u . integer + 10 ) ;
sprintf ( result . u . string , DEF_SCIENTIFIC ? " %.*e " : " %.*f " , argv [ 1 ] . u . integer = = - 1 ? def_precision : ( int ) ( argv [ 1 ] . u . integer ) , argv [ 0 ] . u . flt ) ;
result . type = STRING ;
}
/*}}}*/
else if ( argc = = 3 & & argv [ 0 ] . type = = FLOAT & & ( argv [ 1 ] . type = = INT | | argv [ 1 ] . type = = EMPTY ) & & argv [ 2 ] . type = = INT ) /* float to string */ /* { { { */
{
result . u . string = malloc ( ( argv [ 1 ] . type = = INT ? argv [ 1 ] . u . integer : def_precision ) + 10 ) ;
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 ) ;
result . type = STRING ;
}
/*}}}*/
else /* return string type error */ /*{{{*/
{
result . type = EEK ;
result . u . err = strcpy ( malloc ( strlen ( _ ( " Usage: string(location) or string(float[,[integer][,integer]]) " ) ) + 1 ) , _ ( " Usage: string(location) or string(float[,[integer][,integer]]) " ) ) ;
return result ;
}
/*}}}*/
return result ;
}
/*}}}*/
/* sum */ /*{{{*/
static Token sum_func ( int argc , const Token argv [ ] )
{
/* variables */ /*{{{*/
Token result ;
/*}}}*/
if ( argc = = 2 & & argv [ 0 ] . type = = LOCATION & & argv [ 1 ] . type = = LOCATION ) /* result is sum */ /*{{{*/
{
/* variables */ /*{{{*/
2019-07-27 04:14:26 +00:00
Location w ;
2019-07-22 20:32:33 +00:00
int x1 , y1 , z1 ;
int x2 , y2 , z2 ;
Token tmp ;
/*}}}*/
x1 = argv [ 0 ] . u . location [ 0 ] ; x2 = argv [ 1 ] . u . location [ 0 ] ; posorder ( & x1 , & x2 ) ;
y1 = argv [ 0 ] . u . location [ 1 ] ; y2 = argv [ 1 ] . u . location [ 1 ] ; posorder ( & y1 , & y2 ) ;
z1 = argv [ 0 ] . u . location [ 2 ] ; z2 = argv [ 1 ] . u . location [ 2 ] ; posorder ( & z1 , & z2 ) ;
result . type = EMPTY ;
2019-07-27 04:14:26 +00:00
for ( w [ X ] = x1 ; w [ X ] < = x2 ; + + ( w [ X ] ) )
for ( w [ Y ] = y1 ; w [ Y ] < = y2 ; + + ( w [ Y ] ) )
for ( w [ Z ] = z1 ; w [ Z ] < = z2 ; + + ( w [ Z ] ) )
2019-07-22 20:32:33 +00:00
{
Token t ;
2019-07-27 04:14:26 +00:00
tmp = tadd ( result , t = getvalue ( upd_sheet , w ) ) ;
2019-07-22 20:32:33 +00:00
tfree ( & t ) ;
tfree ( & result ) ;
result = tmp ;
if ( result . type = = EEK ) return result ;
}
}
/*}}}*/
else /* result is sum type error */ /*{{{*/
{
result . type = EEK ;
result . u . err = strcpy ( malloc ( strlen ( _ ( " Usage: sum(location,location) " ) ) + 1 ) , _ ( " Usage: sum(location,location) " ) ) ;
}
/*}}}*/
return result ;
}
/*}}}*/
/* n */ /*{{{*/
static Token n_func ( int argc , const Token argv [ ] )
{
/* variables */ /*{{{*/
Token result ;
/*}}}*/
if ( argc = = 2 & & argv [ 0 ] . type = = LOCATION & & argv [ 1 ] . type = = LOCATION )
/* result is number of elements */ /*{{{*/
{
/* variables */ /*{{{*/
2019-07-27 04:14:26 +00:00
Location w ;
2019-07-22 20:32:33 +00:00
int x1 , y1 , z1 ;
int x2 , y2 , z2 ;
Token tmp ;
int n ;
/*}}}*/
x1 = argv [ 0 ] . u . location [ 0 ] ; x2 = argv [ 1 ] . u . location [ 0 ] ; posorder ( & x1 , & x2 ) ;
y1 = argv [ 0 ] . u . location [ 1 ] ; y2 = argv [ 1 ] . u . location [ 1 ] ; posorder ( & y1 , & y2 ) ;
z1 = argv [ 0 ] . u . location [ 2 ] ; z2 = argv [ 1 ] . u . location [ 2 ] ; posorder ( & z1 , & z2 ) ;
n = 0 ;
2019-07-27 04:14:26 +00:00
for ( w [ X ] = x1 ; w [ X ] < = x2 ; + + ( w [ X ] ) )
for ( w [ Y ] = y1 ; w [ Y ] < = y2 ; + + ( w [ Y ] ) )
for ( w [ Z ] = z1 ; w [ Z ] < = z2 ; + + ( w [ Z ] ) )
2019-07-22 20:32:33 +00:00
{
2019-07-27 04:14:26 +00:00
tmp = getvalue ( upd_sheet , w ) ;
if ( tmp . type ! = EMPTY ) + + n ;
2019-07-22 20:32:33 +00:00
tfree ( & tmp ) ;
}
2019-07-27 04:14:26 +00:00
result . type = INT ;
result . u . integer = n ;
2019-07-22 20:32:33 +00:00
}
/*}}}*/
else
/* result is n type error */ /*{{{*/
{
result . type = EEK ;
result . u . err = strcpy ( malloc ( strlen ( _ ( " Usage: n(location,location) " ) ) + 1 ) , _ ( " Usage: n(location,location) " ) ) ;
}
/*}}}*/
return result ;
}
/*}}}*/
2019-07-27 04:14:26 +00:00
2019-07-22 20:32:33 +00:00
/* int */ /*{{{*/
static Token int_func ( int argc , const Token argv [ ] )
{
/* variables */ /*{{{*/
Token result ;
/*}}}*/
if ( argc = = 1 & & argv [ 0 ] . type = = FLOAT )
/* result is integer with cutoff fractional part */ /*{{{*/
{
result . type = INT ;
result . u . integer = ( long ) ( argv [ 0 ] . u . flt ) ;
}
/*}}}*/
else if ( argc = = 3 & & argv [ 0 ] . type = = FLOAT & & argv [ 1 ] . type = = INT & & argv [ 2 ] . type = = INT )
/* result is integer with given conversion */ /*{{{*/
{
result . type = INT ;
if ( argv [ 0 ] . u . flt < 0 )
{
if ( argv [ 1 ] . u . integer < - 1 ) result . u . integer = ( long ) floor ( argv [ 0 ] . u . flt ) ;
else if ( argv [ 1 ] . u . integer = = - 1 ) result . u . integer = ( long ) ( argv [ 0 ] . u . flt - 0.5 ) ;
else if ( argv [ 1 ] . u . integer = = 0 ) result . u . integer = ( long ) ( argv [ 0 ] . u . flt ) ;
else if ( argv [ 1 ] . u . integer = = 1 ) result . u . integer = ( long ) ( argv [ 0 ] . u . flt + 0.5 ) ;
else result . u . integer = ( long ) ceil ( argv [ 0 ] . u . flt ) ;
}
else
{
if ( argv [ 2 ] . u . integer < - 1 ) result . u . integer = ( long ) floor ( argv [ 0 ] . u . flt ) ;
else if ( argv [ 2 ] . u . integer = = - 1 ) result . u . integer = ( long ) ( argv [ 0 ] . u . flt - 0.5 ) ;
else if ( argv [ 2 ] . u . integer = = 0 ) result . u . integer = ( long ) ( argv [ 0 ] . u . flt ) ;
else if ( argv [ 2 ] . u . integer = = 1 ) result . u . integer = ( long ) ( argv [ 0 ] . u . flt + 0.5 ) ;
else result . u . integer = ( long ) ceil ( argv [ 0 ] . u . flt ) ;
}
}
/*}}}*/
else if ( argc = = 1 & & argv [ 0 ] . type = = STRING )
/* result is integer */ /*{{{*/
{
char * s ;
errno = 0 ;
result . u . integer = strtol ( argv [ 0 ] . u . string , & s , 10 ) ;
if ( s = = ( char * ) 0 | | * s )
{
result . type = EEK ;
result . u . err = mystrmalloc ( _ ( " int(string): invalid string " ) ) ;
}
else if ( errno = = ERANGE & & ( result . u . integer = = LONG_MAX | | result . u . integer = = LONG_MIN ) )
{
result . type = EEK ;
result . u . err = mystrmalloc ( _ ( " int(string): domain error " ) ) ;
}
else result . type = INT ;
}
/*}}}*/
else
/* result is int type error */ /*{{{*/
{
result . type = EEK ;
result . u . err = strcpy ( malloc ( strlen ( _ ( " Usage: int(float[,integer,integer]) " ) ) + 1 ) , _ ( " Usage: int(float[,integer,integer]) " ) ) ;
}
/*}}}*/
return result ;
}
/*}}}*/
/* frac */ /*{{{*/
static Token frac_func ( int argc , const Token argv [ ] )
{
/* variables */ /*{{{*/
Token result ;
double foo ;
/*}}}*/
if ( argc = = 1 & & argv [ 0 ] . type = = FLOAT )
/* result is fractional part */ /*{{{*/
{
result . type = FLOAT ;
result . u . flt = modf ( argv [ 0 ] . u . flt , & foo ) ;
}
/*}}}*/
else
/* result is frac type error */ /*{{{*/
{
result . type = EEK ;
result . u . err = strcpy ( malloc ( strlen ( _ ( " Usage: frac(float) " ) ) + 1 ) , _ ( " Usage: frac(float) " ) ) ;
}
/*}}}*/
return result ;
}
/*}}}*/
/* len */ /*{{{*/
static Token len_func ( int argc , const Token argv [ ] )
{
/* variables */ /*{{{*/
Token result ;
/*}}}*/
if ( argc = = 1 & & argv [ 0 ] . type = = STRING )
/* result is length */ /*{{{*/
{
result . type = INT ;
result . u . integer = strlen ( argv [ 0 ] . u . string ) ;
}
/*}}}*/
else
/* result is frac type error */ /*{{{*/
{
result . type = EEK ;
result . u . err = mystrmalloc ( _ ( " Usage: len(string) " ) ) ;
}
/*}}}*/
return result ;
}
/*}}}*/
/* log */ /*{{{*/
static Token log_func ( int argc , const Token argv [ ] )
{
/* variables */ /*{{{*/
double x = - 1.0 , y = - 1.0 ;
Token result ;
/*}}}*/
/* set x and y to first two arguments */ /*{{{*/
if ( argc > = 1 )
{
if ( argv [ 0 ] . type = = FLOAT ) x = argv [ 0 ] . u . flt ;
else if ( argv [ 0 ] . type = = INT ) x = ( double ) argv [ 0 ] . u . integer ;
}
if ( argc = = 2 )
{
if ( argv [ 1 ] . type = = FLOAT ) y = argv [ 1 ] . u . flt ;
else if ( argv [ 1 ] . type = = INT ) y = ( double ) argv [ 1 ] . u . integer ;
}
/*}}}*/
if ( argc = = 1 & & ( argv [ 0 ] . type = = FLOAT | | argv [ 0 ] . type = = INT ) ) /* result is ln(x) */ /*{{{*/
{
result . type = FLOAT ;
result . u . flt = log ( x ) ;
}
/*}}}*/
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) */ /* { { { */
{
result . type = FLOAT ;
if ( y = = CONST_E ) result . u . flt = log ( x ) ;
else if ( y = = 10.0 ) result . u . flt = log10 ( x ) ;
else result . u . flt = log ( x ) / log ( y ) ;
}
/*}}}*/
else /* result is log type error */ /*{{{*/
{
result . type = EEK ;
result . u . err = mystrmalloc ( _ ( " Usage: log(float[,float]) " ) ) ;
}
/*}}}*/
return result ;
}
/*}}}*/
/* minmax */ /*{{{*/
static Token minmax_func ( int argc , const Token argv [ ] , int min )
{
/* variables */ /*{{{*/
2019-07-29 16:42:51 +00:00
Token result , tmp ;
2019-07-27 04:14:26 +00:00
Location minloc ;
2019-07-22 20:32:33 +00:00
/*}}}*/
if ( argc = = 2 & & argv [ 0 ] . type = = LOCATION & & argv [ 1 ] . type = = LOCATION )
/* result is min/max */ /*{{{*/
{
/* variables */ /*{{{*/
2019-07-27 04:14:26 +00:00
Location w ;
2019-07-22 20:32:33 +00:00
int x1 , y1 , z1 ;
int x2 , y2 , z2 ;
/*}}}*/
x1 = argv [ 0 ] . u . location [ 0 ] ; x2 = argv [ 1 ] . u . location [ 0 ] ; posorder ( & x1 , & x2 ) ;
y1 = argv [ 0 ] . u . location [ 1 ] ; y2 = argv [ 1 ] . u . location [ 1 ] ; posorder ( & y1 , & y2 ) ;
z1 = argv [ 0 ] . u . location [ 2 ] ; z2 = argv [ 1 ] . u . location [ 2 ] ; posorder ( & z1 , & z2 ) ;
2019-07-27 04:14:26 +00:00
minloc [ X ] = x1 ; minloc [ Y ] = y1 ; minloc [ Z ] = z1 ;
result = getvalue ( upd_sheet , minloc ) ;
for ( w [ X ] = x1 ; w [ X ] < = x2 ; + + ( w [ X ] ) )
for ( w [ Y ] = y1 ; w [ Y ] < = y2 ; + + ( w [ Y ] ) )
for ( w [ Z ] = z1 ; w [ Z ] < = z2 ; + + ( w [ Z ] ) )
2019-07-22 20:32:33 +00:00
{
Token t ;
2019-07-27 04:14:26 +00:00
t = getvalue ( upd_sheet , w ) ;
tmp = ( min ? tle ( result , t ) : tge ( result , t ) ) ;
2019-07-22 20:32:33 +00:00
if ( tmp . type = = INT )
/* successful comparison */ /*{{{*/
{
tfree ( & tmp ) ;
2019-07-27 04:14:26 +00:00
if ( tmp . u . integer = = 0 )
2019-07-22 20:32:33 +00:00
{
tfree ( & result ) ;
result = t ;
2019-07-27 04:14:26 +00:00
LOCATION_GETS ( minloc , w ) ;
2019-07-22 20:32:33 +00:00
}
else tfree ( & t ) ;
}
/*}}}*/
else
/* successless comparison, return with error */ /*{{{*/
{
tfree ( & result ) ;
tfree ( & t ) ;
return tmp ;
}
/*}}}*/
}
tfree ( & result ) ;
result . type = LOCATION ;
2019-07-27 04:14:26 +00:00
LOCATION_GETS ( result . u . location , minloc ) ;
2019-07-22 20:32:33 +00:00
return result ;
}
/*}}}*/
2019-07-29 16:42:51 +00:00
else if ( argc > 0 ) /* try to take min/max of all arguments */
{
size_t i , mini ;
mini = 0 ;
for ( i = 1 ; i < argc ; + + i ) {
tmp = ( min ? tlt ( argv [ i ] , argv [ mini ] ) : tgt ( argv [ i ] , argv [ mini ] ) ) ;
if ( tmp . type = = INT ) /* comparison succeeded */
{
if ( tmp . u . integer ) mini = i ;
tfree ( & tmp ) ;
}
else /* failed comparison, return the error */
return tmp ;
}
return argv [ mini ] ;
}
2019-07-22 20:32:33 +00:00
else
/* result is min/max type error */ /*{{{*/
{
result . type = EEK ;
2019-07-29 16:42:51 +00:00
result . u . err = mystrmalloc ( min ? _ ( " Usage: min(location,location) or min(val1, val2,...) " ) : _ ( " Usage: max(location,location) or max(val1,val2,...) " ) ) ;
2019-07-22 20:32:33 +00:00
return result ;
}
/*}}}*/
}
/*}}}*/
/* min */ /*{{{*/
static Token min_func ( int argc , const Token argv [ ] )
{
return minmax_func ( argc , argv , 1 ) ;
}
/*}}}*/
/* max */ /*{{{*/
static Token max_func ( int argc , const Token argv [ ] )
{
return minmax_func ( argc , argv , 0 ) ;
}
/*}}}*/
/* abs */ /*{{{*/
static Token abs_func ( int argc , const Token argv [ ] )
{
/* variables */ /*{{{*/
Token result ;
/*}}}*/
if ( argc = = 1 & & argv [ 0 ] . type = = FLOAT )
/* result is absolute floating point number */ /*{{{*/
{
result . type = FLOAT ;
result . u . flt = fabs ( argv [ 0 ] . u . flt ) ;
}
/*}}}*/
else if ( argc = = 1 & & argv [ 0 ] . type = = INT )
/* result is absolute integer number */ /*{{{*/
{
result . type = INT ;
result . u . integer = ( argv [ 0 ] . u . integer < 0 ? - argv [ 0 ] . u . integer : argv [ 0 ] . u . integer ) ;
}
/*}}}*/
else
/* result is abs type error */ /*{{{*/
{
result . type = EEK ;
result . u . err = mystrmalloc ( _ ( " Usage: abs(float|integer) " ) ) ;
}
/*}}}*/
return result ;
}
/*}}}*/
/* $ */ /*{{{*/
static Token env_func ( int argc , const Token argv [ ] )
{
/* variables */ /*{{{*/
Token result ;
/*}}}*/
if ( argc = = 1 & & argv [ 0 ] . type = = STRING )
{
const char * e ;
if ( ( e = getenv ( argv [ 0 ] . u . string ) ) = = ( char * ) 0 ) e = " " ;
result . type = STRING ;
result . u . string = mystrmalloc ( e ) ;
}
else
{
result . type = EEK ;
result . u . err = mystrmalloc ( _ ( " Usage: $(string) " ) ) ;
}
return result ;
}
/*}}}*/
/* float */ /*{{{*/
static Token float_func ( int argc , const Token argv [ ] )
{
Token result ;
if ( argc = = 1 & & argv [ 0 ] . type = = STRING )
/* convert string to float */ /*{{{*/
{
char * p ;
result . u . flt = strtod ( argv [ 0 ] . u . string , & p ) ;
if ( p ! = argv [ 0 ] . u . string & & * p = = ' \0 ' & & dblfinite ( result . u . flt ) = = ( const char * ) 0 )
{
result . type = FLOAT ;
}
else
{
result . type = EEK ;
result . u . err = mystrmalloc ( _ ( " Not a (finite) floating point number " ) ) ;
}
}
/*}}}*/
else
/* float type error */ /*{{{*/
{
result . type = EEK ;
result . u . err = mystrmalloc ( _ ( " Usage: float(string) " ) ) ;
}
/*}}}*/
return result ;
}
/*}}}*/
/* strftime */ /*{{{*/
static Token strftime_func ( int argc , const Token argv [ ] )
{
/* variables */ /*{{{*/
Token result ;
/*}}}*/
if ( argc = = 1 & & argv [ 0 ] . type = = STRING ) /* format and return string */ /*{{{*/
{
time_t t ;
struct tm * tm ;
char s [ 1024 ] ;
t = time ( ( time_t * ) 0 ) ;
tm = localtime ( & t ) ;
strftime ( s , sizeof ( s ) , argv [ 0 ] . u . string , tm ) ;
s [ sizeof ( s ) - 1 ] = ' \0 ' ;
result . u . string = mystrmalloc ( s ) ;
result . type = STRING ;
}
/*}}}*/
else if ( argc = = 2 & & argv [ 0 ] . type = = STRING & & argv [ 1 ] . type = = INT ) /* format and return string */ /* { { { */
{
time_t t ;
struct tm * tm ;
char s [ 1024 ] ;
t = argv [ 1 ] . u . integer ;
tm = localtime ( & t ) ;
strftime ( s , sizeof ( s ) , argv [ 0 ] . u . string , tm ) ;
s [ sizeof ( s ) - 1 ] = ' \0 ' ;
result . u . string = mystrmalloc ( s ) ;
result . type = STRING ;
}
/*}}}*/
else /* strftime type error */ /*{{{*/
{
result . type = EEK ;
result . u . err = mystrmalloc ( _ ( " Usage: strftime(string[,integer]) " ) ) ;
}
/*}}}*/
return result ;
}
/*}}}*/
/* clock */ /*{{{*/
static Token clock_func ( int argc , const Token argv [ ] )
{
/* variables */ /*{{{*/
Token result ;
/*}}}*/
if ( argc = = 2 & & argv [ 0 ] . type = = INT & & argv [ 1 ] . type = = LOCATION ) /* clock(condition,location) */ /*{{{*/
{
2019-07-27 04:14:26 +00:00
if ( argv [ 0 ] . u . integer ) clk ( upd_sheet , argv [ 1 ] . u . location ) ;
2019-07-22 20:32:33 +00:00
result . type = EMPTY ;
}
/*}}}*/
else if ( argc = = 3 & & argv [ 0 ] . type = = INT & & argv [ 1 ] . type = = LOCATION & & argv [ 2 ] . type = = LOCATION ) /* clock(condition,location,location) */ /* { { { */
{
if ( argv [ 0 ] . u . integer )
{
/* variables */ /*{{{*/
2019-07-27 04:14:26 +00:00
Location w ;
2019-07-22 20:32:33 +00:00
int x1 , y1 , z1 ;
int x2 , y2 , z2 ;
/*}}}*/
x1 = argv [ 1 ] . u . location [ 0 ] ; x2 = argv [ 2 ] . u . location [ 0 ] ; posorder ( & x1 , & x2 ) ;
y1 = argv [ 1 ] . u . location [ 1 ] ; y2 = argv [ 2 ] . u . location [ 1 ] ; posorder ( & y1 , & y2 ) ;
z1 = argv [ 1 ] . u . location [ 2 ] ; z2 = argv [ 2 ] . u . location [ 2 ] ; posorder ( & z1 , & z2 ) ;
2019-07-27 04:14:26 +00:00
for ( w [ X ] = x1 ; w [ X ] < = x2 ; + + ( w [ X ] ) )
for ( w [ Y ] = y1 ; w [ Y ] < = y2 ; + + ( w [ Y ] ) )
for ( w [ Z ] = z1 ; w [ Z ] < = z2 ; + + ( w [ Z ] ) )
clk ( upd_sheet , w ) ;
2019-07-22 20:32:33 +00:00
}
result . type = EMPTY ;
}
/*}}}*/
else /* wrong usage */ /*{{{*/
{
result . type = EEK ;
result . u . err = mystrmalloc ( _ ( " Usage: clock(condition,location[,location]) " ) ) ;
}
/*}}}*/
return result ;
}
/*}}}*/
/* poly */ /*{{{*/
static Token poly_func ( int argc , const Token argv [ ] )
{
/* variables */ /*{{{*/
Token result ;
int i ;
/*}}}*/
for ( i = 0 ; i < argc ; + + i ) if ( argc < 2 | | ( argv [ i ] . type ! = INT & & argv [ i ] . type ! = FLOAT ) ) /* type error */ /*{{{*/
{
result . type = EEK ;
result . u . err = strcpy ( malloc ( strlen ( _ ( " Usage: poly(float|integer,float|integer,...) " ) ) + 1 ) , _ ( " Usage: poly(float|integer,float|integer,...) " ) ) ;
}
/*}}}*/
else
{
Token tmp ;
result = tcopy ( argv [ 1 ] ) ;
for ( i = 2 ; i < argc ; + + i )
{
tmp = tmul ( result , argv [ 0 ] ) ;
tfree ( & result ) ;
result = tmp ;
tmp = tadd ( result , argv [ i ] ) ;
tfree ( & result ) ;
result = tmp ;
if ( result . type = = EEK ) return result ;
}
}
return result ;
}
/*}}}*/
/* sin */ /*{{{*/
static Token sin_func ( int argc , const Token argv [ ] )
{
return sci_func ( argc , argv , sin , " sin " ) ;
}
/*}}}*/
/* cos */ /*{{{*/
static Token cos_func ( int argc , const Token argv [ ] )
{
return sci_func ( argc , argv , cos , " cos " ) ;
}
/*}}}*/
/* tan */ /*{{{*/
static Token tan_func ( int argc , const Token argv [ ] )
{
return sci_func ( argc , argv , tan , " tan " ) ;
}
/*}}}*/
/* sinh */ /*{{{*/
static Token sinh_func ( int argc , const Token argv [ ] )
{
return sci_func ( argc , argv , sinh , " sinh " ) ;
}
/*}}}*/
/* cosh */ /*{{{*/
static Token cosh_func ( int argc , const Token argv [ ] )
{
return sci_func ( argc , argv , cosh , " cosh " ) ;
}
/*}}}*/
/* tanh */ /*{{{*/
static Token tanh_func ( int argc , const Token argv [ ] )
{
return sci_func ( argc , argv , tanh , " tanh " ) ;
}
/*}}}*/
/* asin */ /*{{{*/
static Token asin_func ( int argc , const Token argv [ ] )
{
return sci_func ( argc , argv , asin , " asin " ) ;
}
/*}}}*/
/* acos */ /*{{{*/
static Token acos_func ( int argc , const Token argv [ ] )
{
return sci_func ( argc , argv , acos , " acos " ) ;
}
/*}}}*/
/* atan */ /*{{{*/
static Token atan_func ( int argc , const Token argv [ ] )
{
return sci_func ( argc , argv , atan , " atan " ) ;
}
/*}}}*/
/* arsinh */ /*{{{*/
static Token arsinh_func ( int argc , const Token argv [ ] )
{
return sci_func ( argc , argv , arsinh , " arsinh " ) ;
}
/*}}}*/
/* arcosh */ /*{{{*/
static Token arcosh_func ( int argc , const Token argv [ ] )
{
return sci_func ( argc , argv , arcosh , " arcosh " ) ;
}
/*}}}*/
/* artanh */ /*{{{*/
static Token artanh_func ( int argc , const Token argv [ ] )
{
return sci_func ( argc , argv , artanh , " artanh " ) ;
}
/*}}}*/
/* rad2deg */ /*{{{*/
static Token rad2deg_func ( int argc , const Token argv [ ] )
{
return sci_func ( argc , argv , rad2deg , " rad2deg " ) ;
}
/*}}}*/
/* deg2rad */ /*{{{*/
static Token deg2rad_func ( int argc , const Token argv [ ] )
{
return sci_func ( argc , argv , deg2rad , " deg2rad " ) ;
}
/*}}}*/
/* rnd */ /*{{{*/
static Token rnd_func ( int argc , const Token argv [ ] )
{
/* variables */ /*{{{*/
Token result ;
/*}}}*/
if ( argc = = 0 )
{
result . type = FLOAT ;
result . u . flt = rand ( ) / ( ( double ) RAND_MAX ) ;
}
else
{
result . type = EEK ;
result . u . err = mystrmalloc ( _ ( " Usage: rnd() " ) ) ;
}
return result ;
}
/*}}}*/
/* substr */ /*{{{*/
static Token substr_func ( int argc , const Token argv [ ] )
{
/* variables */ /*{{{*/
Token result ;
/*}}}*/
if ( argc = = 3 & & argv [ 0 ] . type = = STRING & & argv [ 1 ] . type = = INT & & argv [ 2 ] . type = = INT )
{
char ss [ 1024 ] ;
int n , l , b , e ;
b = argv [ 1 ] . u . integer ;
e = argv [ 2 ] . u . integer ;
l = strlen ( argv [ 0 ] . u . string ) ;
if ( b < 0 ) b = 0 ;
if ( b > l ) b = l ;
if ( e > l ) e = l ;
n = e - b + 1 ;
if ( n > = 1024 ) n = 1024 - 1 ;
if ( n > 0 ) {
ss [ n ] = ' \0 ' ;
strncpy ( ss , argv [ 0 ] . u . string + b , n ) ;
result . type = STRING ;
result . u . string = mystrmalloc ( ss ) ;
}
else {
result . type = EMPTY ;
}
}
else
{
result . type = EEK ;
result . u . err = mystrmalloc ( _ ( " Usage: substr(string,integer,integer) " ) ) ;
}
return result ;
}
/*}}}*/
/* strptime */ /*{{{*/
static Token strptime_func ( int argc , const Token argv [ ] )
{
/* variables */ /*{{{*/
Token result ;
/*}}}*/
if ( argc = = 2 & & argv [ 0 ] . type = = STRING & & argv [ 1 ] . type = = STRING ) /* format and return string */ /*{{{*/
{
time_t t ;
struct tm tm ;
t = time ( ( time_t * ) 0 ) ;
tm = * localtime ( & t ) ;
strptime ( argv [ 1 ] . u . string , argv [ 0 ] . u . string , & tm ) ;
result . u . integer = mktime ( & tm ) ;
result . type = INT ;
}
/*}}}*/
else /* strftime type error */ /*{{{*/
{
result . type = EEK ;
result . u . err = mystrmalloc ( _ ( " Usage: strptime(string,string) " ) ) ;
}
/*}}}*/
return result ;
}
/*}}}*/
/* time */ /*{{{*/
static Token time_func ( int argc , const Token argv [ ] )
{
Token result ;
if ( argc = = 0 )
{
result . type = INT ;
result . u . integer = time ( ( time_t * ) 0 ) ;
}
else
{
result . type = EEK ;
result . u . err = mystrmalloc ( _ ( " Usage: time() " ) ) ;
}
return result ;
}
/*}}}*/
/* table of functions */ /*{{{*/
/* The order of these entries has no influence on performance, but to stay
compatible , new entries should be appended . */
Tfunc tfunc [ ] =
{
{ " @ " , at_func } ,
{ " & " , adr_func } ,
{ " x " , x_func } ,
{ " y " , y_func } ,
{ " z " , z_func } ,
{ " eval " , eval_func } ,
{ " error " , error_func } ,
{ " string " , string_func } ,
{ " sum " , sum_func } ,
{ " n " , n_func } ,
{ " int " , int_func } ,
{ " frac " , frac_func } ,
{ " len " , len_func } ,
{ " min " , min_func } ,
{ " max " , max_func } ,
{ " abs " , abs_func } ,
{ " $ " , env_func } ,
{ " float " , float_func } ,
{ " strftime " , strftime_func } ,
{ " clock " , clock_func } ,
{ " poly " , poly_func } ,
{ " e " , e_func } ,
{ " log " , log_func } ,
{ " sin " , sin_func } ,
{ " cos " , cos_func } ,
{ " tan " , tan_func } ,
{ " sinh " , sinh_func } ,
{ " cosh " , cosh_func } ,
{ " tanh " , tanh_func } ,
{ " asin " , asin_func } ,
{ " acos " , acos_func } ,
{ " atan " , atan_func } ,
{ " arsinh " , arsinh_func } ,
{ " arcosh " , arcosh_func } ,
{ " artanh " , artanh_func } ,
{ " deg2rad " , deg2rad_func } ,
{ " rad2deg " , rad2deg_func } ,
{ " rnd " , rnd_func } ,
{ " substr " , substr_func } ,
{ " strptime " , strptime_func } ,
{ " time " , time_func } ,
2019-07-29 17:22:15 +00:00
{ " bitand " , bitand_func } ,
{ " bitor " , bitor_func } ,
2019-07-22 20:32:33 +00:00
{ " " , ( Token ( * ) ( int , const Token [ ] ) ) 0 }
} ;
/*}}}*/