#include <GUIConstantsEx.au3>
#include <EditConstants.au3>
$sAutoItError_Info = WinGetText("[CLASS:#32770; TITLE:AutoIt Error]")
If $sAutoItError_Info == 0 Then $sAutoItError_Info = ""
$sErrorLine = StringRegExpReplace($sAutoItError_Info, "(?ism).*Line (\d+).*", "\1")
$sScriptFile = StringRegExpReplace($sAutoItError_Info, '(?ism).*\(File "(.*)\.exe"\).*', '\1.au3')
$hGUI = GUICreate("AutoIt script Error Finder", 400, 300)
$nScript_Input = GUICtrlCreateInput($sScriptFile, 20, 30, 340, 20)
$nOpenScript_Btn = GUICtrlCreateButton("...", 360, 29, 22, 22)
GUICtrlCreateLabel("Please enter Error Line (shown by compiled script):", 20, 80)
$nErrLine_Input = GUICtrlCreateInput($sErrorLine, 260, 77, 120, 20, BitOR($ES_NUMBER, $ES_CENTER))
$nErrorLine_Edit = GUICtrlCreateEdit("", 20, 120, 360, 140, BitOR($GUI_SS_DEFAULT_EDIT, $ES_READONLY))
$nGetErrorLine_Btn = GUICtrlCreateButton("Get Error Line", 120, 270, 160, 20)
GUISetState(@SW_SHOW, $hGUI)
While 1
$nMsg = GUIGetMsg()
Switch $nMsg
Case $GUI_EVENT_CLOSE
Exit
Case $nOpenScript_Btn
Local $sScript = FileOpenDialog("Open AutoIt Script", "", "AutoIt Script (*.au3)", 0, "", $hGUI)
If @error Then ContinueLoop
GUICtrlSetData($nScript_Input, $sScript)
Case $nGetErrorLine_Btn
$sScriptFile = GUICtrlRead($nScript_Input)
$iErrLine = GUICtrlRead($nErrLine_Input)
If Not FileExists($sScriptFile) Or $iErrLine = "" Then
ContinueLoop
EndIf
$sMergedScript = _AU3_LibMergeAllUDFs($sScriptFile)
$aMergedScript = StringSplit(_AU3_LibStripEmptyLines($sMergedScript), @LF)
GUICtrlSetData($nErrorLine_Edit, $aMergedScript[$iErrLine])
EndSwitch
WEnd
; ===============================================================
; _AU3_LibMergeAllUDFs($sScriptFile, $iIncludeComments=0, $iRemoveIncludes=1)
; ---------------------------------------------------------------
; Смешивает вложенные библиотеки в тело скрипта
; (таким образом преобразовывая один цельный скрипт со всеми функциями и переменными)
; Использован AutoIT v3.2.12.1
;
; $sScriptFile : AutoIT-скрипт для смешивания
; $iIncludeComments : Определяет, нужно ли обрабатывать строки комментариев
; $iIncludeEmptyLines : Определяет, нужно ли обрабатывать пустые строки
; $iRemoveIncludes : Определяет, нужно ли удалять строки #include'ов с исходного скрипта
;
; Автор : G.Sandler (a.k.a CreatoR)
; ===============================================================
Func _AU3_LibMergeAllUDFs($sScriptFile, $iIncludeComments=0, $iIncludeEmptyLines=0, $iRemoveIncludes=1, $iRetData=1)
Local $aGetAllLibs, $aScript_Content, $sRead_SrcScript, $sHeader_Content, $hFOpen, $iIsFuncBody = 0
$sRead_SrcScript = FileRead($sScriptFile)
_AU3_LibGetAllUDFs($sRead_SrcScript, $aGetAllLibs)
If $iRemoveIncludes Then $sRead_SrcScript = StringRegExpReplace($sRead_SrcScript, "(?si)#include.*?[\r\n]+", "")
For $i = $aGetAllLibs[0][0] To 1 Step -1
$iIsFuncBody = 0
$aScript_Content = StringSplit(StringStripCR(StringStripWS(FileRead($aGetAllLibs[$i][1]), 3)), @LF)
For $j = 1 To $aScript_Content[0]
If Not $iIncludeEmptyLines And $aScript_Content[$j] = "" Then
ContinueLoop
EndIf
If Not $iIncludeComments And StringRegExp($aScript_Content[$j], "^(\s+)?;") Then
ContinueLoop
EndIf
If StringRegExp($aScript_Content[$j], "(?i)^(\s+)?#include") Then
ContinueLoop ;We don't need the #includes, right?
ElseIf StringRegExp($aScript_Content[$j], "(?i)^(\s+)?Func") Then
$sRead_SrcScript &= @CRLF
$iIsFuncBody = 1
ElseIf StringRegExp($aScript_Content[$j], "(?i)^(\s+)?EndFunc") Then
$sRead_SrcScript &= $aScript_Content[$j] & @CRLF
$iIsFuncBody = 0
ContinueLoop
EndIf
If Not $iIsFuncBody Then ;Write to the Begining of file (Collecting the variables/constants Header)
$sHeader_Content &= $aScript_Content[$j] & @CRLF
Else ;Write to the End of file (UDF functions)
$sRead_SrcScript &= $aScript_Content[$j] & @CRLF
EndIf
Next
Next
If $sHeader_Content <> "" Then $sRead_SrcScript = $sHeader_Content & @CRLF & $sRead_SrcScript
If $iRetData Then
Return $sRead_SrcScript
Else
$hFOpen = FileOpen(StringTrimRight($sScriptFile, 4) & "_au3lib_merged.au3", 2)
FileWrite($hFOpen, $sRead_SrcScript)
FileClose($hFOpen)
EndIf
EndFunc ; ==> _AU3_LibMergeAllUDFs
; ===============================================================
; _AU3_LibGetAllUDFs($sScript_Content, $aIncludes_Arr)
; ---------------------------------------------------------------
; Возвращает массив всех загруженных UDF и библиотечных файлов
; Использован AutoIT v3.2.12.0
;
; $sScript_Content : текст AutoIT-скрипта
; $aIncludes_Arr : ссылка на переменную для выходного массива,
; по выходу содержит двумерный массив:
; $aIncludes_Arr[0][0] - количество элементов в массиве
; $aIncludes_Arr[$i][0] - тип библиотечного файла
; $aIncludes_Arr[$i][1] - Полный путь библиотечного файла
; $aIncludes_Arr[$i][2] - Только имя библиотечного файла
; $aIncludes_Arr[$i][3] - массив UDF, определенных в файле
;
; Функция рекурсивная, поэтому выход по ошибке не предусмотрен
;
; Автор : amel27
; ===============================================================
Func _AU3_LibGetAllUDFs($sScript_Content, ByRef $aIncludes_Arr)
Local Const $rFile = '(?i)(?:^|[\n\r])[ \t]*#include[ \t]+((?:\<|")[^\n\r\"\>]+(?:\>|"))'
Local Const $rUDFs = '(?i)(?:^|[\n\r])[ \t]*Func[ \t]+([\w\d]+)'
; Инициализация массива при первом входе / сохранение списка UDF
If UBound($aIncludes_Arr, 2) <> 4 Then Dim $aIncludes_Arr[2][4] = [[1, 0, 0], [0, "", 0]]
$aIncludes_Arr[$aIncludes_Arr[0][0]][3] = StringRegExp($sScript_Content, $rUDFs, 3)
; Инициализация переменных / Получение списка библиотечных файлов
Local $sPath, $iType, $sName, $sText
Local $aFile = StringRegExp($sScript_Content, $rFile, 3)
; Пофайловая обработка списка библиотек
If IsArray($aFile) Then
For $i = 0 To UBound($aFile)-1
$sPath = _AU3_LibIncludeToPath($aFile[$i]) ; полное имя файла
If @error Then ContinueLoop ; файл не найден
$iType = @extended ; тип библиотеки
$sName = StringRegExpReplace($sPath, "(?:[^\\]+\\)+", "") ; краткое имя файла
; Исключение повторной обработки / Чтение файла
For $j = 1 To $aIncludes_Arr[0][0]
If $aIncludes_Arr[$j][0] == $iType And $aIncludes_Arr[$j][2] == $sName Then ContinueLoop 2
Next
$sText = FileRead($sPath)
If @error Then ContinueLoop
; При успешном чтении добавляем файл в выходной массив
$aIncludes_Arr[0][0] += 1
ReDim $aIncludes_Arr[$aIncludes_Arr[0][0]+1][4]
$aIncludes_Arr[$aIncludes_Arr[0][0]][0] = $iType
$aIncludes_Arr[$aIncludes_Arr[0][0]][1] = $sPath
$aIncludes_Arr[$aIncludes_Arr[0][0]][2] = $sName
; Рекурсивный вызов на обработку текста библиотеки
_AU3_LibGetAllUDFs($sText, $aIncludes_Arr)
Next
EndIf
EndFunc ; ==> _AU3_LibGetAllUDFs
; ===============================================================
; _AU3_LibIncludeToPath($sInclude)
; ---------------------------------------------------------------
; Возвращает полный путь к библиотечному файлу по строке загрузки
; Использован AutoIT v3.2.12.0
;
; $sInclude : строка загрузки в формате #include, примеры:
; '<array.au3>'
; '"array.au3"'
; '"c:\Program Files\AutoIT3\Include\array.au3"'
;
; При успехе : возвращает полное имя файла, содержащее путь,
; макрос @extended указывает на тип библиотеки:
; 1 - системная библиотека (каталог установки)
; 2 - текущая библиотека (каталог скрипта)
; 3 - пользовательская библиотека (путь из реестра)
; 4 - путь к библиотеке явно указан при загрузке
;
; При неудаче : возвращает пустую строку и устанавливает @error:
; 1 - ошибка формата строки
; 2 - файл не найден
;
; Автор : amel27
; ===============================================================
Func _AU3_LibIncludeToPath($sInclude)
Local $aRegExp = StringRegExp($sInclude, '^(<|"|'')([^>"]+)(?:>|"|'')$', 3)
; Проверка на корректность формата строки
If Not IsArray($aRegExp) Then Return SetError(1, 0, "")
$sInclude = $aRegExp[1]
If StringInStr($sInclude, "\") = 0 Then
Local $sSYS, $sUDL, $aUDL, $sAU3 = @ScriptDir & "\" & $sInclude
; Определение каталога системных библиотек
$sSYS = StringRegExpReplace(@AutoItExe, "\\[^\\]+$", "")
$sSYS &= "\Include\"& $sInclude
; Чтение списка каталогов пользовательских библиотек
$sUDL = RegRead("HKCU\Software\AutoIt v3\AutoIt", "Include")
$aUDL = StringRegExp($sUDL, "([^;]+)(?:;|$)", 3)
; Проверка типов 1 и 2 (до пользовательских библиотек)
If $aRegExp[0] == '<' Then
If FileExists($sSYS) Then Return SetError(0, 1, $sSYS)
ElseIf $aRegExp[0] == '"' Then
If FileExists($sAU3) Then Return SetError(0, 2, $sAU3)
EndIf
; Проверка типа 3 (поиск среди пользовательских библиотек)
If IsArray($aUDL) Then
For $i = 0 To UBound($aUDL)-1
$aUDL[$i] &= "\" & $sInclude
If FileExists($aUDL[$i]) Then Return SetError(0, 3, $aUDL[$i])
Next
EndIf
; Проверка типов 1 и 2 (после пользовательских библиотек)
If $aRegExp[0] == '<' Then
If FileExists($sAU3) Then Return SetError(0, 2, $sAU3)
ElseIf $aRegExp[0] == '"' Then
If FileExists($sSYS) Then Return SetError(0, 1, $sSYS)
EndIf
Else
; Проверка типа 4 (файл с указанием полного пути)
If FileExists($sInclude) Then Return SetError(0, 4, $sInclude)
EndIf
; ОШИБКА: файл не найден
Return SetError(2, 0, "")
EndFunc ; ==> _AU3_LibIncludeToPath
Func _AU3_LibStripEmptyLines($sFileContent)
If FileExists($sFileContent) Then
$sFileContent = FileRead($sFileContent)
EndIf
$sFileContent = StringRegExpReplace($sFileContent, "(?i)#include-once", "")
$sFileContent = StringRegExpReplace($sFileContent, "[\r?\n]{2,}", @CRLF)
$sFileContent = StringRegExpReplace($sFileContent, "\r?\n\s*;.*?", "")
Return $sFileContent
EndFunc