LCOV - code coverage report
Current view: top level - root/contrail/src/contrail-analytics/contrail-collector/ruleparser - ruleutil.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 0 199 0.0 %
Date: 2026-11-09 02:10:49 Functions: 0 16 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  * Copyright Contributors to the OpenSDN project
       4             :  */
       5             : 
       6             : #include <cassert>
       7             : #include <stdlib.h>
       8             : #include <stdio.h>
       9             : #include <stdarg.h>
      10             : #include <time.h>
      11             : #include <string.h>
      12             : #include <algorithm>
      13             : #include <sys/types.h>
      14             : #include <sys/stat.h>
      15             : #include <errno.h>
      16             : #include <limits.h>
      17             : 
      18             : // Careful: must include globals first for extern definitions
      19             : #include "ruleparserl.h"
      20             : #include "ruleutil.h"
      21             : #include "t_ruleparser.h"
      22             : 
      23             : std::string t_ruleaction::RuleActionEchoResult;
      24             : 
      25             : /**
      26             :  * Globals
      27             :  */
      28             : t_rulelist* g_rulelist;
      29             : 
      30             : /**
      31             :  * Parsing pass
      32             :  */
      33             : PARSE_MODE g_parse_mode;
      34             : 
      35             : /**
      36             :  * Current directory of file being parsed
      37             :  */
      38             : std::string g_curdir;
      39             : 
      40             : /**
      41             :  * Current file being parsed
      42             :  */
      43             : std::string g_curpath;
      44             : 
      45             : /**
      46             :  * Search path for inclusions
      47             :  */
      48             : std::vector<std::string> g_incl_searchpath;
      49             : 
      50             : /**
      51             :  * Global debug state
      52             :  */
      53             : int g_debug = 0;
      54             : 
      55             : /**
      56             :  * Strictness level
      57             :  */
      58             : int g_strict = 127;
      59             : 
      60             : /**
      61             :  * Warning level
      62             :  */
      63             : int g_warn = 1;
      64             : 
      65             : /**
      66             :  * Verbose output
      67             :  */
      68             : int g_verbose = 0;
      69             : 
      70             : /**
      71             :  * The last parsed doctext comment.
      72             :  */
      73             : char* g_doctext;
      74             : 
      75             : /**
      76             :  * The location of the last parsed doctext comment.
      77             :  */
      78             : int g_doctext_lineno;
      79             : 
      80             : /**
      81             :  * Converts a string filename into a thrift program name
      82             :  */
      83           0 : std::string program_name(std::string filename) {
      84           0 :     std::string::size_type slash = filename.rfind("/");
      85           0 :   if (slash != std::string::npos) {
      86           0 :     filename = filename.substr(slash+1);
      87             :   }
      88           0 :   std::string::size_type dot = filename.rfind(".");
      89           0 :   if (dot != std::string::npos) {
      90           0 :     filename = filename.substr(0, dot);
      91             :   }
      92           0 :   return filename;
      93             : }
      94             : 
      95             : /**
      96             :  * MinGW doesn't have realpath, so use fallback implementation in that case,
      97             :  * otherwise this just calls through to realpath
      98             :  */
      99           0 : char *saferealpath(const char *path, char *resolved_path) {
     100           0 :     return realpath(path, resolved_path);
     101             : }
     102             : 
     103             : 
     104             : /**
     105             :  * Report an error to the user. This is called yyerror for historical
     106             :  * reasons (lex and yacc expect the error reporting routine to be called
     107             :  * this). Call this function to report any errors to the user.
     108             :  * yyerror takes printf style arguments.
     109             :  *
     110             :  * @param fmt C format string followed by additional arguments
     111             :  */
     112           0 : void yyerror(const char* fmt, ...) {
     113             :     va_list args;
     114           0 :     fprintf(stderr,
     115             :             "[ERROR:%s:%d] (last token was '%s')\n",
     116             :             g_curpath.c_str(),
     117             :             yylineno,
     118             :             yytext);
     119             : 
     120           0 :     va_start(args, fmt);
     121           0 :     vfprintf(stderr, fmt, args);
     122           0 :     va_end(args);
     123             : 
     124           0 :     fprintf(stderr, "\n");
     125           0 : }
     126             : 
     127             : /**
     128             :  * Prints a debug message from the parser.
     129             :  *
     130             :  * @param fmt C format string followed by additional arguments
     131             :  */
     132           0 : void pdebug(const char* fmt, ...) {
     133           0 :     if (g_debug == 0) {
     134           0 :         return;
     135             :     }
     136             :     va_list args;
     137           0 :     printf("[PARSE:%d] ", yylineno);
     138           0 :     va_start(args, fmt);
     139           0 :     vprintf(fmt, args);
     140           0 :     va_end(args);
     141           0 :     printf("\n");
     142             : }
     143             : 
     144             : /**
     145             :  * Prints a verbose output mode message
     146             :  *
     147             :  * @param fmt C format string followed by additional arguments
     148             :  */
     149           0 : void pverbose(const char* fmt, ...) {
     150           0 :     if (g_verbose == 0) {
     151           0 :         return;
     152             :     }
     153             :     va_list args;
     154           0 :     va_start(args, fmt);
     155           0 :     vprintf(fmt, args);
     156           0 :     va_end(args);
     157             : }
     158             : 
     159             : /**
     160             :  * Prints a warning message
     161             :  *
     162             :  * @param fmt C format string followed by additional arguments
     163             :  */
     164           0 : void pwarning(int level, const char* fmt, ...) {
     165           0 :     if (g_warn < level) {
     166           0 :         return;
     167             :     }
     168             :     va_list args;
     169           0 :     printf("[WARNING:%s:%d] ", g_curpath.c_str(), yylineno);
     170           0 :     va_start(args, fmt);
     171           0 :     vprintf(fmt, args);
     172           0 :     va_end(args);
     173           0 :     printf("\n");
     174             : }
     175             : 
     176             : /**
     177             :  * Prints a failure message and exits
     178             :  *
     179             :  * @param fmt C format string followed by additional arguments
     180             :  */
     181           0 : void failure(const char* fmt, ...) {
     182             :     va_list args;
     183           0 :     fprintf(stderr, "[FAILURE:%s:%d] ", g_curpath.c_str(), yylineno);
     184           0 :     va_start(args, fmt);
     185           0 :     vfprintf(stderr, fmt, args);
     186           0 :     va_end(args);
     187           0 :     printf("\n");
     188             :     //exit(1);
     189           0 : }
     190             : 
     191             : /**
     192             :  * Gets the directory path of a filename
     193             :  */
     194           0 : std::string directory_name(std::string filename) {
     195           0 :     std::string::size_type slash = filename.rfind("/");
     196             :     // No slash, just use the current directory
     197           0 :     if (slash == std::string::npos) {
     198           0 :         return ".";
     199             :     }
     200           0 :     return filename.substr(0, slash);
     201             : }
     202             : 
     203             : /**
     204             :  * Finds the appropriate file path for the given filename
     205             :  */
     206           0 : std::string include_file(std::string filename) {
     207             :     // Absolute path? Just try that
     208           0 :     if (filename[0] == '/') {
     209             :         // Realpath!
     210             :         char rp[PATH_MAX];
     211           0 :         if (saferealpath(filename.c_str(), rp) == NULL) {
     212           0 :             pwarning(0, "Cannot open include file %s\n", filename.c_str());
     213           0 :             return std::string();
     214             :         }
     215             : 
     216             :         // Stat this file
     217             :         struct stat finfo;
     218           0 :         if (stat(rp, &finfo) == 0) {
     219           0 :             return rp;
     220             :         }
     221             :     } else { // relative path, start searching
     222             :         // new search path with current dir global
     223           0 :         std::vector<std::string> sp = g_incl_searchpath;
     224           0 :         sp.insert(sp.begin(), g_curdir);
     225             : 
     226             :         // iterate through paths
     227           0 :         std::vector<std::string>::iterator it;
     228           0 :         for (it = sp.begin(); it != sp.end(); it++) {
     229           0 :             std::string sfilename = *(it) + "/" + filename;
     230             : 
     231             :             // Realpath!
     232             :             char rp[PATH_MAX];
     233           0 :             if (saferealpath(sfilename.c_str(), rp) == NULL) {
     234           0 :                 continue;
     235             :             }
     236             : 
     237             :             // Stat this files
     238             :             struct stat finfo;
     239           0 :             if (stat(rp, &finfo) == 0) {
     240           0 :                 return rp;
     241             :             }
     242           0 :         }
     243           0 :     }
     244             : 
     245             :     // Uh oh
     246           0 :     pwarning(0, "Could not find include file %s\n", filename.c_str());
     247           0 :     return std::string();
     248             : }
     249             : 
     250             : /**
     251             :  * Clears any previously stored doctext string.
     252             :  * Also prints a warning if we are discarding information.
     253             :  */
     254           0 : void clear_doctext() {
     255           0 :     if (g_doctext != NULL) {
     256           0 :         pwarning(2, "Uncaptured doctext at on line %d.", g_doctext_lineno);
     257             :     }
     258           0 :     free(g_doctext);
     259           0 :     g_doctext = NULL;
     260           0 : }
     261             : 
     262             : /**
     263             :  * Cleans up text commonly found in doxygen-like comments
     264             :  *
     265             :  * Warning: if you mix tabs and spaces in a non-uniform way,
     266             :  * you will get what you deserve.
     267             :  */
     268           0 : char* clean_up_doctext(char* doctext) {
     269             :     // Convert to C++ string, and remove Windows's carriage returns.
     270           0 :     std::string docstring = doctext;
     271           0 :     docstring.erase(
     272           0 :             remove(docstring.begin(), docstring.end(), '\r'),
     273           0 :             docstring.end());
     274             : 
     275             :     // Separate into lines.
     276           0 :     std::vector<std::string> lines;
     277           0 :     std::string::size_type pos = std::string::npos;
     278             :     std::string::size_type last;
     279             :     while (true) {
     280           0 :         last = (pos == std::string::npos) ? 0 : pos+1;
     281           0 :         pos = docstring.find('\n', last);
     282           0 :         if (pos == std::string::npos) {
     283             :             // First bit of cleaning.  If the last line is only whitespace, drop it.
     284           0 :             std::string::size_type nonwhite = docstring.find_first_not_of(" \t", last);
     285           0 :             if (nonwhite != std::string::npos) {
     286           0 :                 lines.push_back(docstring.substr(last));
     287             :             }
     288           0 :             break;
     289             :         }
     290           0 :         lines.push_back(docstring.substr(last, pos-last));
     291           0 :     }
     292             : 
     293             :     // A very profound docstring.
     294           0 :     if (lines.empty()) {
     295           0 :         return NULL;
     296             :     }
     297             : 
     298             :     // Clear leading whitespace from the first line.
     299           0 :     pos = lines.front().find_first_not_of(" \t");
     300           0 :     lines.front().erase(0, pos);
     301             : 
     302             :     // If every nonblank line after the first has the same number of spaces/tabs,
     303             :     // then a star, remove them.
     304           0 :     bool have_prefix = true;
     305           0 :     bool found_prefix = false;
     306           0 :     std::string::size_type prefix_len = 0;
     307           0 :     std::vector<std::string>::iterator l_iter;
     308           0 :     for (l_iter = lines.begin()+1; l_iter != lines.end(); ++l_iter) {
     309           0 :         if (l_iter->empty()) {
     310           0 :             continue;
     311             :         }
     312             : 
     313           0 :         pos = l_iter->find_first_not_of(" \t");
     314           0 :         if (!found_prefix) {
     315           0 :             if (pos != std::string::npos) {
     316           0 :                 if (l_iter->at(pos) == '*') {
     317           0 :                     found_prefix = true;
     318           0 :                     prefix_len = pos;
     319             :                 } else {
     320           0 :                     have_prefix = false;
     321           0 :                     break;
     322             :                 }
     323             :             } else {
     324             :                 // Whitespace-only line.  Truncate it.
     325           0 :                 l_iter->clear();
     326             :             }
     327           0 :         } else if (l_iter->size() > pos
     328           0 :                 && l_iter->at(pos) == '*'
     329           0 :                 && pos == prefix_len) {
     330             :             // Business as usual.
     331           0 :         } else if (pos == std::string::npos) {
     332             :             // Whitespace-only line.  Let's truncate it for them.
     333           0 :             l_iter->clear();
     334             :         } else {
     335             :             // The pattern has been broken.
     336           0 :             have_prefix = false;
     337           0 :             break;
     338             :         }
     339             :     }
     340             : 
     341             :     // If our prefix survived, delete it from every line.
     342           0 :     if (have_prefix) {
     343             :         // Get the star too.
     344           0 :         prefix_len++;
     345           0 :         for (l_iter = lines.begin()+1; l_iter != lines.end(); ++l_iter) {
     346           0 :             l_iter->erase(0, prefix_len);
     347             :         }
     348             :     }
     349             : 
     350             :     // Now delete the minimum amount of leading whitespace from each line.
     351           0 :     prefix_len = std::string::npos;
     352           0 :     for (l_iter = lines.begin()+1; l_iter != lines.end(); ++l_iter) {
     353           0 :         if (l_iter->empty()) {
     354           0 :             continue;
     355             :         }
     356           0 :         pos = l_iter->find_first_not_of(" \t");
     357           0 :         if (pos != std::string::npos
     358           0 :                 && (prefix_len == std::string::npos || pos < prefix_len)) {
     359           0 :             prefix_len = pos;
     360             :         }
     361             :     }
     362             : 
     363             :     // If our prefix survived, delete it from every line.
     364           0 :     if (prefix_len != std::string::npos) {
     365           0 :         for (l_iter = lines.begin()+1; l_iter != lines.end(); ++l_iter) {
     366           0 :             l_iter->erase(0, prefix_len);
     367             :         }
     368             :     }
     369             : 
     370             :     // Remove trailing whitespace from every line.
     371           0 :     for (l_iter = lines.begin(); l_iter != lines.end(); ++l_iter) {
     372           0 :         pos = l_iter->find_last_not_of(" \t");
     373           0 :         if (pos != std::string::npos && pos != l_iter->length()-1) {
     374           0 :             l_iter->erase(pos+1);
     375             :         }
     376             :     }
     377             : 
     378             :     // If the first line is empty, remove it.
     379             :     // Don't do this earlier because a lot of steps skip the first line.
     380           0 :     if (lines.front().empty()) {
     381           0 :         lines.erase(lines.begin());
     382             :     }
     383             : 
     384             :     // Now rejoin the lines and copy them back into doctext.
     385           0 :     docstring.clear();
     386           0 :     for (l_iter = lines.begin(); l_iter != lines.end(); ++l_iter) {
     387           0 :         docstring += *l_iter;
     388           0 :         docstring += '\n';
     389             :     }
     390             : 
     391           0 :     assert(docstring.length() <= strlen(doctext));
     392           0 :     strcpy(doctext, docstring.c_str());
     393           0 :     return doctext;
     394           0 : }
     395             : 
     396           0 : void post_parse_cleanup() {
     397           0 :     yylex_destroy();
     398           0 : }
     399             : 
     400             : /**
     401             :  * Parses a program
     402             :  */
     403           0 : void parse(t_rulelist *rulelist, std::string file) {
     404           0 :     yyin = fopen(file.c_str(), "r");
     405           0 :     if (yyin == 0) {
     406           0 :         failure("Could not open input file: \"%s\"", file.c_str());
     407             :     }
     408           0 :     pverbose("Parsing %s for types\n", file.c_str());
     409           0 :     yylineno = 1;
     410           0 :     g_parse_mode = PROGRAM;
     411           0 :     g_rulelist = rulelist;
     412             : 
     413           0 :     if (yyparse() != 0) {
     414           0 :         failure("Parser error.");
     415             :     }
     416           0 :     fclose(yyin);
     417             : 
     418           0 :     post_parse_cleanup();
     419           0 : }
     420             : 
     421             : /**
     422             :  * Parses a program from memory in place with no copy
     423             :  */
     424           0 : void parse(t_rulelist *rulelist, char *base, size_t sz) {
     425           0 :     if (yy_scan_buffer(base, sz) == NULL) {
     426           0 :         failure("yy_scan_buffer...");
     427             :     }
     428             : 
     429           0 :     yylineno = 1;
     430           0 :     g_parse_mode = PROGRAM;
     431           0 :     g_rulelist = rulelist;
     432             : 
     433           0 :     if (yyparse() != 0) {
     434           0 :         failure("Parser error.");
     435             :     }
     436           0 :     post_parse_cleanup();
     437           0 : }
     438             : 
     439             : /**
     440             :  * Parses a program from memory with copy
     441             :  */
     442           0 : void parse(t_rulelist *rulelist, const char *bytes, int len) {
     443           0 :     if (yy_scan_bytes(bytes, len) == NULL) {
     444           0 :         failure("yy_scan_buffer...");
     445             :     }
     446             : 
     447           0 :     yylineno = 1;
     448           0 :     g_parse_mode = PROGRAM;
     449           0 :     g_rulelist = rulelist;
     450             : 
     451           0 :     if (yyparse() != 0) {
     452           0 :         failure("Parser error.");
     453             :     }
     454           0 :     post_parse_cleanup();
     455           0 : }
     456             : 
     457             : /**
     458             :  * parse function to verify the rulefile format
     459             :  */
     460           0 : int check_rulebuf(const char *bytes, int len) {
     461           0 :     t_rulelist *rulelist = new t_rulelist;
     462             : 
     463           0 :     if (yy_scan_bytes(bytes, len) == NULL) {
     464           0 :         failure("yy_scan_buffer...");
     465           0 :         return -1;
     466             :     }
     467             : 
     468           0 :     yylineno = 1;
     469           0 :     g_parse_mode = PROGRAM;
     470           0 :     g_rulelist = rulelist;
     471             : 
     472           0 :     if (yyparse() != 0) {
     473           0 :         failure("Parser error.");
     474           0 :         return -1;
     475             :     }
     476             : 
     477           0 :     free(rulelist);
     478           0 :     post_parse_cleanup();
     479             : 
     480           0 :     return 0;
     481             : }

Generated by: LCOV version 1.14