2019年1月18日 星期五

A tool to Modify #define Macro value in c/c++ file (implement in Python)

This article is an implement of:

an exe(windows application)/scripts to
1.search for an #define Macro 
2.change the value (type: number, string, regular expression...etc)

finally, it will be like this:

Steps to Use it:
-1 open the file you want to modify.


-2 type keyword(a few character is OK), then press"start" to search for this Macro.
(show Exception message if not exist!!)


-3 type in the Macro value, then press"save the change in Macro Value".




-4 if open the file, you can see the change result.


the fallowing sections describe how to implement:

0.Project configuration:

Python Interpreter Settings:
- python 3.6
- PyQT5 5.11.2
- PyInstaller 3.1.0



Install Package in Python 3.6:

from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *

from ui_textReader_ver1 import Ui_Form

import sys
from shutil import copyfile
import datetime

1. Graphic User Interface Source Code (create by Qt version 5.9.1)

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'ui_textReader.ui'
#
# Created by: PyQt5 UI code generator 5.11.2
#
# WARNING! All changes made in this file will be lost!

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_Form(object):
    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.resize(703, 559)
        self.groupBox_2 = QtWidgets.QGroupBox(Form)
        self.groupBox_2.setGeometry(QtCore.QRect(0, 10, 691, 531))
        self.groupBox_2.setObjectName("groupBox_2")
        self.verticalLayoutWidget = QtWidgets.QWidget(self.groupBox_2)
        self.verticalLayoutWidget.setGeometry(QtCore.QRect(20, 20, 651, 501))
        self.verticalLayoutWidget.setObjectName("verticalLayoutWidget")
        self.verticalLayout = QtWidgets.QVBoxLayout(self.verticalLayoutWidget)
        self.verticalLayout.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout.setObjectName("verticalLayout")
        self.gridLayout_2 = QtWidgets.QGridLayout()
        self.gridLayout_2.setObjectName("gridLayout_2")
        self.s1_bt_1 = QtWidgets.QPushButton(self.verticalLayoutWidget)
        self.s1_bt_1.setObjectName("s1_bt_1")
        self.gridLayout_2.addWidget(self.s1_bt_1, 0, 1, 1, 1)
        self.s1_text_1 = QtWidgets.QLineEdit(self.verticalLayoutWidget)
        self.s1_text_1.setObjectName("s1_text_1")
        self.gridLayout_2.addWidget(self.s1_text_1, 5, 1, 1, 3)
        self.s1_text_2 = QtWidgets.QLineEdit(self.verticalLayoutWidget)
        self.s1_text_2.setObjectName("s1_text_2")
        self.gridLayout_2.addWidget(self.s1_text_2, 0, 3, 1, 1)
        self.s1_lb_2 = QtWidgets.QLabel(self.verticalLayoutWidget)
        self.s1_lb_2.setObjectName("s1_lb_2")
        self.gridLayout_2.addWidget(self.s1_lb_2, 5, 0, 1, 1)
        self.s1_lb_3 = QtWidgets.QLabel(self.verticalLayoutWidget)
        self.s1_lb_3.setObjectName("s1_lb_3")
        self.gridLayout_2.addWidget(self.s1_lb_3, 0, 2, 1, 1)
        self.s1_lb_1 = QtWidgets.QLabel(self.verticalLayoutWidget)
        self.s1_lb_1.setObjectName("s1_lb_1")
        self.gridLayout_2.addWidget(self.s1_lb_1, 0, 0, 1, 1)
        self.s1_lb_6 = QtWidgets.QLabel(self.verticalLayoutWidget)
        self.s1_lb_6.setObjectName("s1_lb_6")
        self.gridLayout_2.addWidget(self.s1_lb_6, 8, 0, 1, 1)
        self.s1_lb_7 = QtWidgets.QLabel(self.verticalLayoutWidget)
        self.s1_lb_7.setObjectName("s1_lb_7")
        self.gridLayout_2.addWidget(self.s1_lb_7, 9, 0, 1, 1)
        self.s1_text_3 = QtWidgets.QLineEdit(self.verticalLayoutWidget)
        self.s1_text_3.setObjectName("s1_text_3")
        self.gridLayout_2.addWidget(self.s1_text_3, 8, 1, 1, 3)
        self.s1_lb_4 = QtWidgets.QLabel(self.verticalLayoutWidget)
        self.s1_lb_4.setObjectName("s1_lb_4")
        self.gridLayout_2.addWidget(self.s1_lb_4, 10, 0, 1, 1)
        self.s1_bt_2 = QtWidgets.QPushButton(self.verticalLayoutWidget)
        self.s1_bt_2.setObjectName("s1_bt_2")
        self.gridLayout_2.addWidget(self.s1_bt_2, 10, 1, 1, 1)
        self.s1_text_4 = QtWidgets.QLineEdit(self.verticalLayoutWidget)
        self.s1_text_4.setObjectName("s1_text_4")
        self.gridLayout_2.addWidget(self.s1_text_4, 9, 1, 1, 3)
        self.verticalLayout.addLayout(self.gridLayout_2)
        self.s1_bt_3 = QtWidgets.QPushButton(self.verticalLayoutWidget)
        self.s1_bt_3.setObjectName("s1_bt_3")
        self.verticalLayout.addWidget(self.s1_bt_3)
        self.s1_lb_5 = QtWidgets.QLabel(self.verticalLayoutWidget)
        self.s1_lb_5.setObjectName("s1_lb_5")
        self.verticalLayout.addWidget(self.s1_lb_5)
        self.textBrowser = QtWidgets.QTextBrowser(self.verticalLayoutWidget)
        self.textBrowser.setObjectName("textBrowser")
        self.verticalLayout.addWidget(self.textBrowser)
        self.gridLayout = QtWidgets.QGridLayout()
        self.gridLayout.setObjectName("gridLayout")
        self.verticalLayout.addLayout(self.gridLayout)

        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)

    def retranslateUi(self, Form):
        _translate = QtCore.QCoreApplication.translate
        Form.setWindowTitle(_translate("Form", "Form"))
        self.groupBox_2.setTitle(_translate("Form", "Content"))
        self.s1_bt_1.setText(_translate("Form", "open"))
        self.s1_text_1.setText(_translate("Form", "config.h"))
        self.s1_lb_2.setText(_translate("Form", "File Path"))
        self.s1_lb_3.setText(_translate("Form", "System Time"))
        self.s1_lb_1.setText(_translate("Form", "File"))
        self.s1_lb_6.setText(_translate("Form", "Define Macro"))
        self.s1_lb_7.setText(_translate("Form", "MacroValue"))
        self.s1_lb_4.setText(_translate("Form", "Search in File"))
        self.s1_bt_2.setText(_translate("Form", "start"))
        self.s1_bt_3.setText(_translate("Form", "save the change in Macro Value"))
        self.s1_lb_5.setText(_translate("Form", "Status"))

2. Functions and Main

#這就是blogger: c 語言宏修改小工具 by Alex Kuan 的EXAMPLE CODE @2019/1/18

from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *

from ui_textReader_ver1 import Ui_Form

import sys
from shutil import copyfile
import datetime

class textReader_MainWindow(QMainWindow, Ui_Form):
    def __init__(self, parent=None):
        super(textReader_MainWindow, self).__init__(parent)
        self.setupUi(self)

        self.setWindowTitle("C++ define Modifier by Alex Kuan")
        self.setWindowIcon(QIcon("./image/alex2.jpg"))
        self.time_format = 0

        self.parameter_change = ''
        self.parameter_loc = 0xff
        self.parameter_find = False
        self.f_line = 0

        self.filenames = 0

        self.func_init()

    def func_init(self):
        self.real_time_stamp()

        self.s1_bt_1.clicked.connect(self.open_file)
        self.s1_bt_2.clicked.connect(self.check_parameter)
        self.s1_bt_3.clicked.connect(self.change_parameter)


    def real_time_stamp(self):
        self.sys_timer = QTimer(self)
        self.sys_timer.timeout.connect(self.real_time_update)
        self.sys_timer.start(1000)

    def real_time_update(self):
        self.time_format = datetime.datetime.now().strftime("%Y-%m-%d_%H:%M:%S")
        self.s1_text_2.setText(str(self.time_format))

    def open_file(self):
        fname = QFileDialog()
        fname.setFileMode(QFileDialog.AnyFile)
        fname.setFilter(QDir.Files)

        if fname.exec_():
            self.filenames = fname.selectedFiles()
            copyfile(self.filenames[0],"./config_file.txt")
            self.s1_text_1.setText(self.filenames[0])

            f = open(self.filenames[0], 'r')
            self.f_line = f.readlines()

            for i in range(0, len(self.f_line)):
                self.textBrowser_print(2,self.f_line[i])

    def check_parameter(self):
        self.parameter_change = self.s1_text_3.text()
        self.parameter_loc = 0xff
        self.parameter_find = False
        line_cnt = 0


        for li in self.f_line:
            if self.parameter_change in li:
                self.parameter_find = True
                self.parameter_loc = line_cnt
            else:
                line_cnt = line_cnt+1

        if False == self.parameter_find:
            QMessageBox.critical(self, "Config Error", "This Parameter not exist!")
        else:
            self.textBrowser.clear()
            self.textBrowser_print(1,"find %s at line %d\r\n"%(self.f_line[self.parameter_loc],
                                                           self.parameter_loc))

    def change_parameter(self):
        if False != self.parameter_find:
            print(self.filenames[0])
            f_write = open(self.filenames[0], 'w+')
            self.f_line[int(self.parameter_loc)] = '#define '+self.parameter_change+' ('+self.s1_text_4.text()+')\n'

            f_write.writelines(self.f_line)

            f_write.close()
        else:
            QMessageBox.critical(self, "Config Error", "can't find this parameter!")



    def textBrowser_print(self, msg_type, char):
        if 0 == msg_type:
            char_add = "[app]:" + char

        elif 1 == msg_type:
            char_add = "[data]:" + char
        else:
            char_add = char

        self.textBrowser.insertPlainText(char_add)
        textCursor = self.textBrowser.textCursor()
        textCursor.movePosition(textCursor.End)
        self.textBrowser.setTextCursor(textCursor)


if __name__ == "__main__":
    print("system start")
    app = QApplication(sys.argv)
    ui = textReader_MainWindow()
    ui.show()
    sys.exit(app.exec())


3.Project file
image and path 
the "config_file.txt" is a copy of your file before it modified.
change its name to recover if you need older version.

the bellow folders is optional:
./image
./check_file
./save_photo

the bellow folders are made by Pyinstaller, not programmer:
./dist
./build
./idea

4.Compile as Windows Application

python pyinstaller -F ./text_reader_v1_main.py 


6.Note & Reference
- pyqt5:https://www.books.com.tw/products/0010787989
- https://medium.com/pyladies-taiwan/python-%E5%B0%87python%E6%89%93%E5%8C%85%E6%88%90exe%E6%AA%94-32a4bacbe351