LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/ods - ods_formula.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 142 128 90.1 %
Date: 2012-12-26 Functions: 4 4 100.0 %

       1                 : /******************************************************************************
       2                 :  * $Id: ods_formula.cpp 23831 2012-01-30 23:12:23Z rouault $
       3                 :  *
       4                 :  * Component: ODS formula Engine
       5                 :  * Purpose:
       6                 :  * Author: Even Rouault <even dot rouault at mines dash paris dot org>
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (C) 2010 Frank Warmerdam <warmerdam@pobox.com>
      10                 :  * Copyright (c) 2012, Even Rouault <even dot rouault at mines dash paris dot org>
      11                 :  *
      12                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      13                 :  * copy of this software and associated documentation files (the "Software"),
      14                 :  * to deal in the Software without restriction, including without limitation
      15                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      16                 :  * and/or sell copies of the Software, and to permit persons to whom the
      17                 :  * Software is furnished to do so, subject to the following conditions:
      18                 :  *
      19                 :  * The above copyright notice and this permission notice shall be included
      20                 :  * in all copies or substantial portions of the Software.
      21                 :  *
      22                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      23                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      24                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      25                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      26                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      27                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      28                 :  * DEALINGS IN THE SOFTWARE.
      29                 :  ****************************************************************************/
      30                 : 
      31                 : #include <ctype.h>
      32                 : #include <math.h>
      33                 : 
      34                 : #include "cpl_conv.h"
      35                 : #include "ods_formula.h"
      36                 : #include "ods_formula_parser.hpp"
      37                 : 
      38                 : #define YYSTYPE  ods_formula_node*
      39                 : 
      40                 : static const SingleOpStruct apsSingleOp[] =
      41                 : {
      42                 :     { "ABS", ODS_ABS, fabs },
      43                 :     { "SQRT", ODS_SQRT, sqrt },
      44                 :     { "COS", ODS_COS, cos },
      45                 :     { "SIN", ODS_SIN, sin },
      46                 :     { "TAN", ODS_TAN, tan },
      47                 :     { "ACOS", ODS_ACOS, acos },
      48                 :     { "ASIN", ODS_ASIN, asin },
      49                 :     { "ATAN", ODS_ATAN, atan },
      50                 :     { "EXP", ODS_EXP, exp },
      51                 :     { "LN", ODS_LN, log },
      52                 :     { "LOG", ODS_LOG, log10 },
      53                 :     { "LOG10", ODS_LOG, log10 },
      54                 : };
      55                 : 
      56              49 : const SingleOpStruct* ODSGetSingleOpEntry(const char* pszName)
      57                 : {
      58             570 :     for(size_t i = 0; i < sizeof(apsSingleOp) / sizeof(apsSingleOp[0]); i++)
      59                 :     {
      60             530 :         if (EQUAL(pszName, apsSingleOp[i].pszName))
      61               9 :             return &apsSingleOp[i];
      62                 :     }
      63              40 :     return NULL;
      64                 : }
      65                 : 
      66               9 : const SingleOpStruct* ODSGetSingleOpEntry(ods_formula_op eOp)
      67                 : {
      68              50 :     for(size_t i = 0; i < sizeof(apsSingleOp) / sizeof(apsSingleOp[0]); i++)
      69                 :     {
      70              50 :         if (eOp == apsSingleOp[i].eOp)
      71               9 :             return &apsSingleOp[i];
      72                 :     }
      73               0 :     return NULL;
      74                 : }
      75                 : 
      76                 : /************************************************************************/
      77                 : /*                               swqlex()                               */
      78                 : /*                                                                      */
      79                 : /*      Read back a token from the input.                               */
      80                 : /************************************************************************/
      81                 : 
      82             818 : int ods_formulalex( YYSTYPE *ppNode, ods_formula_parse_context *context )
      83                 : {
      84             818 :     const char *pszInput = context->pszNext;
      85                 : 
      86             818 :     *ppNode = NULL;
      87                 : 
      88                 : /* -------------------------------------------------------------------- */
      89                 : /*      Do we have a start symbol to return?                            */
      90                 : /* -------------------------------------------------------------------- */
      91             818 :     if( context->nStartToken != 0 )
      92                 :     {
      93             116 :         int nRet = context->nStartToken;
      94             116 :         context->nStartToken = 0;
      95             116 :         return nRet;
      96                 :     }
      97                 : 
      98                 : /* -------------------------------------------------------------------- */
      99                 : /*      Skip white space.                                               */
     100                 : /* -------------------------------------------------------------------- */
     101            1404 :     while( *pszInput == ' ' || *pszInput == '\t'
     102                 :            || *pszInput == 10 || *pszInput == 13 )
     103               0 :         pszInput++;
     104                 : 
     105             702 :     if( *pszInput == '\0' )
     106                 :     {
     107             116 :         context->pszNext = pszInput;
     108             116 :         return EOF; 
     109                 :     }
     110                 : 
     111                 : /* -------------------------------------------------------------------- */
     112                 : /*      Handle string constants.                                        */
     113                 : /* -------------------------------------------------------------------- */
     114             586 :     if( *pszInput == '"' )
     115                 :     {
     116                 :         char *token;
     117                 :         int i_token;
     118                 : 
     119              34 :         pszInput++;
     120                 : 
     121              34 :         token = (char *) CPLMalloc(strlen(pszInput)+1);
     122              34 :         i_token = 0;
     123                 : 
     124             102 :         while( *pszInput != '\0' )
     125                 :         {
     126              68 :             if( *pszInput == '\\' && pszInput[1] == '"' )
     127               0 :                 pszInput++;
     128              68 :             else if( *pszInput == '\\' && pszInput[1] == '\'' )
     129               0 :                 pszInput++;
     130              68 :             else if( *pszInput == '\'' && pszInput[1] == '\'' )
     131               0 :                 pszInput++;
     132              68 :             else if( *pszInput == '"' )
     133                 :             {
     134              34 :                 pszInput++;
     135              34 :                 break;
     136                 :             }
     137              34 :             else if( *pszInput == '\'' )
     138                 :             {
     139               0 :                 pszInput++;
     140               0 :                 break;
     141                 :             }
     142                 :             
     143              34 :             token[i_token++] = *(pszInput++);
     144                 :         }
     145              34 :         token[i_token] = '\0';
     146                 : 
     147              34 :         *ppNode = new ods_formula_node( token );
     148              34 :         CPLFree( token );
     149                 : 
     150              34 :         context->pszNext = pszInput;
     151                 : 
     152              34 :         return ODST_STRING;
     153                 :     }
     154                 : 
     155                 : /* -------------------------------------------------------------------- */
     156                 : /*      Handle numbers.                                                 */
     157                 : /* -------------------------------------------------------------------- */
     158             552 :     else if( *pszInput >= '0' && *pszInput <= '9' )
     159                 :     {
     160             137 :         CPLString osToken;
     161             137 :         const char *pszNext = pszInput + 1;
     162                 : 
     163             137 :         osToken += *pszInput;
     164                 : 
     165                 :         // collect non-decimal part of number
     166             278 :         while( *pszNext >= '0' && *pszNext <= '9' )
     167               4 :             osToken += *(pszNext++);
     168                 : 
     169                 :         // collect decimal places.
     170             137 :         if( *pszNext == '.' )
     171                 :         {
     172              48 :             osToken += *(pszNext++);
     173             144 :             while( *pszNext >= '0' && *pszNext <= '9' )
     174              48 :                 osToken += *(pszNext++);
     175                 :         }
     176                 : 
     177                 :         // collect exponent
     178             137 :         if( *pszNext == 'e' || *pszNext == 'E' )
     179                 :         {
     180               0 :             osToken += *(pszNext++);
     181               0 :             if( *pszNext == '-' || *pszNext == '+' )
     182               0 :                 osToken += *(pszNext++);
     183               0 :             while( *pszNext >= '0' && *pszNext <= '9' )
     184               0 :                 osToken += *(pszNext++);
     185                 :         }
     186                 : 
     187             137 :         context->pszNext = pszNext;
     188                 : 
     189             137 :         if( strstr(osToken,".") 
     190                 :             || strstr(osToken,"e") 
     191                 :             || strstr(osToken,"E") )
     192                 :         {
     193              48 :             *ppNode = new ods_formula_node( CPLAtof(osToken) );
     194                 :         }
     195                 :         else
     196                 :         {
     197              89 :             *ppNode = new ods_formula_node( atoi(osToken) );
     198                 :         }
     199                 : 
     200             137 :         return ODST_NUMBER;
     201                 :     }
     202                 : 
     203                 : /* -------------------------------------------------------------------- */
     204                 : /*      Handle alpha-numerics.                                          */
     205                 : /* -------------------------------------------------------------------- */
     206             415 :     else if( *pszInput == '.' || isalnum( *pszInput ) )
     207                 :     {
     208             106 :         int nReturn = ODST_IDENTIFIER;
     209             106 :         CPLString osToken;
     210             106 :         const char *pszNext = pszInput + 1;
     211                 : 
     212             106 :         osToken += *pszInput;
     213                 : 
     214                 :         // collect text characters
     215             466 :         while( isalnum( *pszNext ) || *pszNext == '_' 
     216                 :                || ((unsigned char) *pszNext) > 127 )
     217             254 :             osToken += *(pszNext++);
     218                 : 
     219             106 :         context->pszNext = pszNext;
     220                 : 
     221                 :         /* Constants */
     222             106 :         if( EQUAL(osToken,"TRUE") )
     223                 :         {
     224              10 :             *ppNode = new ods_formula_node( 1 );
     225              10 :             return ODST_NUMBER;
     226                 :         }
     227              96 :         else if( EQUAL(osToken,"FALSE") )
     228                 :         {
     229              10 :             *ppNode = new ods_formula_node( 0 );
     230              10 :             return ODST_NUMBER;
     231                 :         }
     232                 : 
     233              86 :         else if( EQUAL(osToken,"NOT") )
     234               2 :             nReturn = ODST_NOT;
     235              84 :         else if( EQUAL(osToken,"AND") )
     236               4 :             nReturn = ODST_AND;
     237              80 :         else if( EQUAL(osToken,"OR") )
     238               4 :             nReturn = ODST_OR;
     239              76 :         else if( EQUAL(osToken,"IF") )
     240               4 :             nReturn = ODST_IF;
     241                 : 
     242                 :         /* No-arg functions */
     243              72 :         else if( EQUAL(osToken,"PI") )
     244                 :         {
     245               1 :             *ppNode = new ods_formula_node( ODS_PI );
     246               1 :             return ODST_FUNCTION_NO_ARG;
     247                 :         }
     248                 : 
     249                 :         /* Single-arg functions */
     250              71 :         else if( EQUAL(osToken,"LEN") )
     251                 :         {
     252               1 :             *ppNode = new ods_formula_node( ODS_LEN );
     253               1 :             return ODST_FUNCTION_SINGLE_ARG;
     254                 :         }
     255                 :         /*
     256                 :         else if( EQUAL(osToken,"T") )
     257                 :         {
     258                 :             *ppNode = new ods_formula_node( ODS_T );
     259                 :             return ODST_FUNCTION_SINGLE_ARG;
     260                 :         }*/
     261                 :         
     262                 :         /* Tow-arg functions */
     263              70 :         else if( EQUAL(osToken,"MOD") )
     264                 :         {
     265               1 :             *ppNode = new ods_formula_node( ODS_MODULUS );
     266               1 :             return ODST_FUNCTION_TWO_ARG;
     267                 :         }
     268              69 :         else if( EQUAL(osToken,"LEFT") )
     269                 :         {
     270               3 :             *ppNode = new ods_formula_node( ODS_LEFT );
     271               3 :             return ODST_FUNCTION_TWO_ARG;
     272                 :         }
     273              66 :         else if( EQUAL(osToken,"RIGHT") )
     274                 :         {
     275               3 :             *ppNode = new ods_formula_node( ODS_RIGHT );
     276               3 :             return ODST_FUNCTION_TWO_ARG;
     277                 :         }
     278                 : 
     279                 :         /* Three-arg functions */
     280              63 :         else if( EQUAL(osToken,"MID") )
     281                 :         {
     282               8 :             *ppNode = new ods_formula_node( ODS_MID );
     283               8 :             return ODST_FUNCTION_THREE_ARG;
     284                 :         }
     285                 : 
     286                 :         /* Multiple-arg functions */
     287              55 :         else if( EQUAL(osToken,"SUM") )
     288                 :         {
     289               1 :             *ppNode = new ods_formula_node( ODS_SUM );
     290               1 :             nReturn = ODST_FUNCTION_ARG_LIST;
     291                 :         }
     292              54 :         else if( EQUAL(osToken,"AVERAGE") )
     293                 :         {
     294               1 :             *ppNode = new ods_formula_node( ODS_AVERAGE );
     295               1 :             nReturn = ODST_FUNCTION_ARG_LIST;
     296                 :         }
     297              53 :         else if( EQUAL(osToken,"MIN") )
     298                 :         {
     299               1 :             *ppNode = new ods_formula_node( ODS_MIN );
     300               1 :             nReturn = ODST_FUNCTION_ARG_LIST;
     301                 :         }
     302              52 :         else if( EQUAL(osToken,"MAX") )
     303                 :         {
     304               1 :             *ppNode = new ods_formula_node( ODS_MAX );
     305               1 :             nReturn = ODST_FUNCTION_ARG_LIST;
     306                 :         }
     307              51 :         else if( EQUAL(osToken,"COUNT") )
     308                 :         {
     309               1 :             *ppNode = new ods_formula_node( ODS_COUNT );
     310               1 :             nReturn = ODST_FUNCTION_ARG_LIST;
     311                 :         }
     312              50 :         else if( EQUAL(osToken,"COUNTA") )
     313                 :         {
     314               1 :             *ppNode = new ods_formula_node( ODS_COUNTA );
     315               1 :             nReturn = ODST_FUNCTION_ARG_LIST;
     316                 :         }
     317                 : 
     318                 :         else
     319                 :         {
     320              49 :             const SingleOpStruct* psSingleOp = ODSGetSingleOpEntry(osToken);
     321              49 :             if (psSingleOp != NULL)
     322                 :             {
     323               9 :                 *ppNode = new ods_formula_node( psSingleOp->eOp );
     324               9 :                 nReturn = ODST_FUNCTION_SINGLE_ARG;
     325                 :             }
     326                 :             else
     327                 :             {
     328              40 :                 *ppNode = new ods_formula_node( osToken );
     329              40 :                 nReturn = ODST_IDENTIFIER;
     330                 :             }
     331                 :         }
     332                 : 
     333              69 :         return nReturn;
     334                 :     }
     335                 : 
     336                 : /* -------------------------------------------------------------------- */
     337                 : /*      Handle special tokens.                                          */
     338                 : /* -------------------------------------------------------------------- */
     339                 :     else
     340                 :     {
     341             309 :         context->pszNext = pszInput+1;
     342             309 :         return *pszInput;
     343                 :     }
     344                 : }
     345                 : 
     346                 : /************************************************************************/
     347                 : /*                        ods_formula_compile()                         */
     348                 : /************************************************************************/
     349                 : 
     350             116 : ods_formula_node* ods_formula_compile( const char *expr )
     351                 : 
     352                 : {
     353             116 :     ods_formula_parse_context context;
     354                 : 
     355             116 :     context.pszInput = expr;
     356             116 :     context.pszNext = expr;
     357             116 :     context.nStartToken = ODST_START;
     358                 : 
     359             116 :     if( ods_formulaparse( &context ) == 0 )
     360                 :     {
     361             116 :         return context.poRoot;
     362                 :     }
     363                 :     else
     364                 :     {
     365               0 :         delete context.poRoot;
     366               0 :         return NULL;
     367                 :     }
     368                 : }

Generated by: LCOV version 1.7