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

Generated by: LCOV version 1.14