#!/usr/bin/env python3
# Copyright (c) 2017-2018 The PIVX developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.

import os, sys
from subprocess import check_output

def countRelevantCommas(line):
    openParensPosStack = []
    openParensPos = 0
    charCounter = 0
    numRelevantCommas = 0
    firstOpenParensIndex = line.find("(")

    for char in line:
        if char == '(':
            openParensPosStack.append(charCounter)

        if char == ')':
            openParensPosStack.pop()

        if char == "," and openParensPosStack[-1] == firstOpenParensIndex:
            numRelevantCommas += 1
        charCounter += 1

    return numRelevantCommas

if __name__ == "__main__":
    out = check_output("git rev-parse --show-toplevel", shell=True, universal_newlines=True)
    srcDir = out.rstrip() + "/src/"

    filelist = [os.path.join(dp, f) for dp, dn, filenames in os.walk(srcDir) for f in filenames if os.path.splitext(f)[1] == '.cpp' or os.path.splitext(f)[1] == '.h' ]
    incorrectInstanceCounter = 0

    for file in filelist:
        f = open(file,"r", encoding="utf-8")
        data = f.read()
        rows = data.split("\n")
        count = 0
        full_data = []
        lineCounter = 1

        tempLine = ""
        tempCount = 0

        for row in rows:
            # Collapse multiple lines into one
            tempLine += row

            # Line contains LogPrint or LogPrintf
            if tempLine.find("LogPrint") != -1:
                if tempLine.count("(") == tempLine.count(")"):
                    havePercents = tempLine.count('%') > 0

                    if havePercents:
                        # This line of code has a format specifier that requires checking number of associated arguments
                        # Determine the number of arguments provided, see if that matches the number of format specifiers
                        # Count the number of commas after the format specifier string.  Check to see if it matches the number of format specifiers.
                        # Assumes quotes are not escaped in the specifier string and there are no percent signs when specifying the debug level.

                        # First, determine the position of the comma after the format specifier section, named commaAfterEndSpecifierStringIndex
                        firstSpecifierIndex = tempLine.find('%')
                        startSpecifierStringIndex = tempLine.rfind('"',firstSpecifierIndex)
                        endSpecifierStringIndex = tempLine.find('"',firstSpecifierIndex)
                        commaAfterEndSpecifierStringIndex = tempLine.find(',',endSpecifierStringIndex)

                        # Count the number of commas after the specifier string
                        line = "(" + tempLine[commaAfterEndSpecifierStringIndex:-1]
                        numCommas = countRelevantCommas(line)

                        # Determine number of extra percents after specifier string
                        numExtraPercents = tempLine.count('%', commaAfterEndSpecifierStringIndex)

                        # Subtract extra from total count.  This is the number of expected specifiers
                        # ignore %%
                        numPercents = tempLine.count('%') - numExtraPercents - 2*tempLine.count('%%')

                        if numPercents != numCommas:
                            print("Incorrect number of arguments for LogPrint(f) statement found.")
                            print(str(file) + ":" + str(lineCounter - tempCount))
                            print("Line = " + tempLine)
                            print("numRelevantCommas = " + str(numCommas) + ", numRelevantPercents = " + str(numPercents))
                            print("")

                            incorrectInstanceCounter += 1

                    # Done with this multiline, clear tempLine
                    tempLine = ""
                    tempCount = 0
                else:
                    tempCount += 1
            else:
                # No LogPrint, clear tempLine
                tempLine = ""
                tempCount = 0

            lineCounter += 1

    print("# of incorrect instances: " + str(incorrectInstanceCounter))

    sys.exit(incorrectInstanceCounter)

@@ -547,32 +547,36 @@
 ')':%0A           
+ x =
  openParensPosSt
@@ -584,16 +584,99 @@
 ck.pop()
+%0A            if x == firstOpenParensIndex:%0A                return numRelevantCommas
 %0A%0A      
@@ -1569,19 +1569,17 @@
 LogPrint
- or
+,
  LogPrin
@@ -1580,16 +1580,25 @@
 ogPrintf
+ or error
 %0A       
@@ -1633,16 +1633,166 @@
 int%22) !=
+ -1 or %5C%0A                    (tempLine.find(%22error(%22) != -1 and tempLine.find(%22_error%22) == -1)  or %5C%0A                    tempLine.find(%22strprintf%22) !=
  -1:%0A   
@@ -2724,13 +2724,11 @@
     
-start
+end
 Spec
@@ -2755,17 +2755,16 @@
 empLine.
-r
 find('%22'
@@ -2777,32 +2777,160 @@
 SpecifierIndex)%0A
+%0A
+                        # Skip escaped quotes%0A                        while tempLine%5BendSpecifierStringIndex - 1%5D == '%5C%5C':%0A    
                 
@@ -2973,37 +2973,36 @@
 mpLine.find('%22',
-first
+ end
 SpecifierIndex)%0A
@@ -2994,22 +2994,33 @@
 pecifier
-Index)
+StringIndex + 1)%0A
 %0A       
@@ -3900,16 +3900,32 @@
 Print(f)
+/error/strprintf
  stateme

include error() and strprintf() in logprint-scanner tool