@aryacode/dsh-engineering 0.0.0-stage → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +128 -0
- package/LICENSE +21 -0
- package/README.md +230 -2
- package/cordis.patch.yml +123 -0
- package/lib/client.js +3448 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +9 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +94 -3
- package/vendor/ftview/README.md +55 -0
- package/vendor/ftview/SKILL.md +74 -0
- package/vendor/ftview/lib/checks.d.ts +27 -0
- package/vendor/ftview/lib/checks.js +39 -0
- package/vendor/ftview/lib/core.d.ts +208 -0
- package/vendor/ftview/lib/core.js +160 -0
- package/vendor/ftview/lib/edit/drafts.d.ts +49 -0
- package/vendor/ftview/lib/edit/drafts.js +84 -0
- package/vendor/ftview/lib/edit/operations.d.ts +62 -0
- package/vendor/ftview/lib/edit/operations.js +126 -0
- package/vendor/ftview/lib/edit/prepare.d.ts +38 -0
- package/vendor/ftview/lib/edit/prepare.js +133 -0
- package/vendor/ftview/lib/edit/tools.d.ts +25 -0
- package/vendor/ftview/lib/edit/tools.js +198 -0
- package/vendor/ftview/lib/edit.d.ts +30 -0
- package/vendor/ftview/lib/edit.js +38 -0
- package/vendor/ftview/lib/index.d.ts +31 -0
- package/vendor/ftview/lib/index.js +36 -0
- package/vendor/ftview/lib/model.d.ts +80 -0
- package/vendor/ftview/lib/model.js +267 -0
- package/vendor/ftview/lib/session.d.ts +48 -0
- package/vendor/ftview/lib/session.js +98 -0
- package/vendor/ftview/lib/skill.d.ts +29 -0
- package/vendor/ftview/lib/skill.js +43 -0
- package/vendor/ftview/lib/studio/discover.d.ts +36 -0
- package/vendor/ftview/lib/studio/discover.js +87 -0
- package/vendor/ftview/lib/studio/preflight.d.ts +51 -0
- package/vendor/ftview/lib/studio/preflight.js +64 -0
- package/vendor/ftview/lib/studio/tools.d.ts +15 -0
- package/vendor/ftview/lib/studio/tools.js +83 -0
- package/vendor/ftview/lib/studio.d.ts +30 -0
- package/vendor/ftview/lib/studio.js +37 -0
- package/vendor/ftview/lib/tools.d.ts +14 -0
- package/vendor/ftview/lib/tools.js +202 -0
- package/vendor/l5x/README.md +62 -0
- package/vendor/l5x/SKILL.md +81 -0
- package/vendor/l5x/lib/approvals.d.ts +50 -0
- package/vendor/l5x/lib/approvals.js +93 -0
- package/vendor/l5x/lib/client.js +412 -0
- package/vendor/l5x/lib/client.js.map +1 -0
- package/vendor/l5x/lib/core/errors.d.ts +38 -0
- package/vendor/l5x/lib/core/errors.js +48 -0
- package/vendor/l5x/lib/core/params.d.ts +49 -0
- package/vendor/l5x/lib/core/params.js +39 -0
- package/vendor/l5x/lib/core/result.d.ts +46 -0
- package/vendor/l5x/lib/core/result.js +21 -0
- package/vendor/l5x/lib/core/tool.d.ts +102 -0
- package/vendor/l5x/lib/core/tool.js +19 -0
- package/vendor/l5x/lib/drafts.d.ts +66 -0
- package/vendor/l5x/lib/drafts.js +98 -0
- package/vendor/l5x/lib/editing.d.ts +30 -0
- package/vendor/l5x/lib/editing.js +42 -0
- package/vendor/l5x/lib/engine/acd-edit.d.ts +13 -0
- package/vendor/l5x/lib/engine/acd-edit.js +115 -0
- package/vendor/l5x/lib/engine/analysis.d.ts +22 -0
- package/vendor/l5x/lib/engine/analysis.js +258 -0
- package/vendor/l5x/lib/engine/capabilities.d.ts +9 -0
- package/vendor/l5x/lib/engine/capabilities.js +40 -0
- package/vendor/l5x/lib/engine/change-set.d.ts +122 -0
- package/vendor/l5x/lib/engine/change-set.js +446 -0
- package/vendor/l5x/lib/engine/configuration.d.ts +21 -0
- package/vendor/l5x/lib/engine/configuration.js +42 -0
- package/vendor/l5x/lib/engine/details.d.ts +47 -0
- package/vendor/l5x/lib/engine/details.js +173 -0
- package/vendor/l5x/lib/engine/direct-polling.d.ts +91 -0
- package/vendor/l5x/lib/engine/direct-polling.js +193 -0
- package/vendor/l5x/lib/engine/download-review.d.ts +15 -0
- package/vendor/l5x/lib/engine/download-review.js +63 -0
- package/vendor/l5x/lib/engine/logic-syntax.d.ts +60 -0
- package/vendor/l5x/lib/engine/logic-syntax.js +237 -0
- package/vendor/l5x/lib/engine/observations.d.ts +41 -0
- package/vendor/l5x/lib/engine/observations.js +67 -0
- package/vendor/l5x/lib/engine/project-analysis.d.ts +131 -0
- package/vendor/l5x/lib/engine/project-analysis.js +314 -0
- package/vendor/l5x/lib/engine/review-evidence.d.ts +8 -0
- package/vendor/l5x/lib/engine/review-evidence.js +49 -0
- package/vendor/l5x/lib/engine/review.d.ts +18 -0
- package/vendor/l5x/lib/engine/review.js +123 -0
- package/vendor/l5x/lib/engine/studio-sdk.d.ts +101 -0
- package/vendor/l5x/lib/engine/studio-sdk.js +571 -0
- package/vendor/l5x/lib/engine/tag-resolution.d.ts +20 -0
- package/vendor/l5x/lib/engine/tag-resolution.js +169 -0
- package/vendor/l5x/lib/engine/usage.d.ts +16 -0
- package/vendor/l5x/lib/engine/usage.js +92 -0
- package/vendor/l5x/lib/engine/xml-regions.d.ts +23 -0
- package/vendor/l5x/lib/engine/xml-regions.js +77 -0
- package/vendor/l5x/lib/fs.d.ts +17 -0
- package/vendor/l5x/lib/fs.js +36 -0
- package/vendor/l5x/lib/index.d.ts +36 -0
- package/vendor/l5x/lib/index.js +42 -0
- package/vendor/l5x/lib/live.d.ts +48 -0
- package/vendor/l5x/lib/live.js +48 -0
- package/vendor/l5x/lib/model/aois.d.ts +39 -0
- package/vendor/l5x/lib/model/aois.js +112 -0
- package/vendor/l5x/lib/model/errors.d.ts +15 -0
- package/vendor/l5x/lib/model/errors.js +18 -0
- package/vendor/l5x/lib/model/index.d.ts +20 -0
- package/vendor/l5x/lib/model/index.js +19 -0
- package/vendor/l5x/lib/model/module.d.ts +37 -0
- package/vendor/l5x/lib/model/module.js +54 -0
- package/vendor/l5x/lib/model/modules.d.ts +24 -0
- package/vendor/l5x/lib/model/modules.js +55 -0
- package/vendor/l5x/lib/model/parse.d.ts +32 -0
- package/vendor/l5x/lib/model/parse.js +116 -0
- package/vendor/l5x/lib/model/project.d.ts +15 -0
- package/vendor/l5x/lib/model/project.js +31 -0
- package/vendor/l5x/lib/model/routines.d.ts +71 -0
- package/vendor/l5x/lib/model/routines.js +183 -0
- package/vendor/l5x/lib/model/tags.d.ts +51 -0
- package/vendor/l5x/lib/model/tags.js +119 -0
- package/vendor/l5x/lib/model/types.d.ts +304 -0
- package/vendor/l5x/lib/model/types.js +12 -0
- package/vendor/l5x/lib/model/udts.d.ts +34 -0
- package/vendor/l5x/lib/model/udts.js +81 -0
- package/vendor/l5x/lib/model/xml.d.ts +139 -0
- package/vendor/l5x/lib/model/xml.js +291 -0
- package/vendor/l5x/lib/model/xref.d.ts +28 -0
- package/vendor/l5x/lib/model/xref.js +154 -0
- package/vendor/l5x/lib/session.d.ts +119 -0
- package/vendor/l5x/lib/session.js +236 -0
- package/vendor/l5x/lib/skill.d.ts +30 -0
- package/vendor/l5x/lib/skill.js +44 -0
- package/vendor/l5x/lib/studio-state.d.ts +77 -0
- package/vendor/l5x/lib/studio-state.js +79 -0
- package/vendor/l5x/lib/studio.d.ts +29 -0
- package/vendor/l5x/lib/studio.js +40 -0
- package/vendor/l5x/lib/tools/checks.d.ts +19 -0
- package/vendor/l5x/lib/tools/checks.js +140 -0
- package/vendor/l5x/lib/tools/common.d.ts +41 -0
- package/vendor/l5x/lib/tools/common.js +84 -0
- package/vendor/l5x/lib/tools/controller.d.ts +21 -0
- package/vendor/l5x/lib/tools/controller.js +170 -0
- package/vendor/l5x/lib/tools/drafts.d.ts +23 -0
- package/vendor/l5x/lib/tools/drafts.js +270 -0
- package/vendor/l5x/lib/tools/live.d.ts +21 -0
- package/vendor/l5x/lib/tools/live.js +175 -0
- package/vendor/l5x/lib/tools/read.d.ts +19 -0
- package/vendor/l5x/lib/tools/read.js +245 -0
- package/vendor/l5x/lib/tools/references.d.ts +20 -0
- package/vendor/l5x/lib/tools/references.js +269 -0
- package/vendor/l5x/lib/tools/studio.d.ts +21 -0
- package/vendor/l5x/lib/tools/studio.js +193 -0
- package/vendor/l5x/poll-worker.mjs +77 -0
- package/vendor/l5x/studio-bridge/NuGet.Config +1 -0
- package/vendor/l5x/studio-bridge/Program.cs +304 -0
- package/vendor/l5x/studio-bridge/StudioBridge.csproj +11 -0
- package/vendor/mwi/README.md +60 -0
- package/vendor/mwi/SKILL.md +87 -0
- package/vendor/mwi/bridge/README.md +8 -0
- package/vendor/mwi/bridge/mw_bridge.ps1 +2763 -0
- package/vendor/mwi/bridge/sdk-interop-importer.cs +30 -0
- package/vendor/mwi/bridge/sdk-variable-reader.cs +22 -0
- package/vendor/mwi/bridge/start_bridge.cmd +21 -0
- package/vendor/mwi/bridge/watch_dialogs.cmd +13 -0
- package/vendor/mwi/bridge/watch_dialogs.ps1 +153 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__init__.py +14 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/__init__.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/block_interfaces.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/cfb.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/datatypes.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/declarations.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/errors.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/graphical_listing.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/grid.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/knowledge.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/mwt_bind.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/navigation.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/program_checks.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/project.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/staging.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/structure.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/task_bindings.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/tasks.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/tree.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/validation.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/variable_edit.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/variables.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/workflow.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/block_interfaces.py +275 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/build.py +339 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/capture.py +448 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/cfb.py +765 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/com.py +268 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/datatypes.py +204 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/declarations.py +399 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/descriptions.py +30 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/eip.py +292 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/errors.py +36 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/graphical_listing.py +208 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/grid.py +227 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/ide.py +317 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/iec.py +317 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/installed_help.py +151 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/knowledge.py +218 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/libraries.py +250 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/manuals.py +520 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/mwt_bind.py +133 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/navigation.py +44 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/pou_writer.py +1547 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/program_checks.py +360 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/project.py +704 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/reference_data/catalog.json +672 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/reference_data/patterns.json +86 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/restore.py +208 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/server.py +1913 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/snapshot.py +138 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/st_comments.py +25 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/staging.py +179 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/stlint.py +676 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/structure.py +98 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/task_bindings.py +68 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/tasks.py +162 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/transaction.py +157 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/tree.py +563 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/tree_writer.py +790 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/uia.py +465 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/validation.py +41 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/variable_edit.py +183 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/variables.py +472 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/workflow.py +130 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/writer.py +666 -0
- package/vendor/mwi/code/mw_code.py +1258 -0
- package/vendor/mwi/legacy/edit-session.js +50 -0
- package/vendor/mwi/legacy/fb-insertion.js +74 -0
- package/vendor/mwi/legacy/native-code.js +83 -0
- package/vendor/mwi/legacy/native-groups.js +75 -0
- package/vendor/mwi/legacy/native-structure.js +143 -0
- package/vendor/mwi/legacy/native-variables.js +77 -0
- package/vendor/mwi/legacy/pou-conversion.js +47 -0
- package/vendor/mwi/legacy/pou-package.js +66 -0
- package/vendor/mwi/lib/core/bridge.d.ts +71 -0
- package/vendor/mwi/lib/core/bridge.js +53 -0
- package/vendor/mwi/lib/core/code-engine.d.ts +47 -0
- package/vendor/mwi/lib/core/code-engine.js +109 -0
- package/vendor/mwi/lib/core/errors.d.ts +37 -0
- package/vendor/mwi/lib/core/errors.js +47 -0
- package/vendor/mwi/lib/core/params.d.ts +52 -0
- package/vendor/mwi/lib/core/params.js +46 -0
- package/vendor/mwi/lib/core/ps-bridge.d.ts +62 -0
- package/vendor/mwi/lib/core/ps-bridge.js +127 -0
- package/vendor/mwi/lib/core/result.d.ts +45 -0
- package/vendor/mwi/lib/core/result.js +20 -0
- package/vendor/mwi/lib/core/tool.d.ts +80 -0
- package/vendor/mwi/lib/core/tool.js +55 -0
- package/vendor/mwi/lib/edit/compare.d.ts +33 -0
- package/vendor/mwi/lib/edit/compare.js +70 -0
- package/vendor/mwi/lib/edit.d.ts +20 -0
- package/vendor/mwi/lib/edit.js +32 -0
- package/vendor/mwi/lib/index.d.ts +21 -0
- package/vendor/mwi/lib/index.js +33 -0
- package/vendor/mwi/lib/read/service.d.ts +117 -0
- package/vendor/mwi/lib/read/service.js +229 -0
- package/vendor/mwi/lib/read.d.ts +21 -0
- package/vendor/mwi/lib/read.js +33 -0
- package/vendor/mwi/lib/session/project.d.ts +34 -0
- package/vendor/mwi/lib/session/project.js +54 -0
- package/vendor/mwi/lib/session/service.d.ts +167 -0
- package/vendor/mwi/lib/session/service.js +566 -0
- package/vendor/mwi/lib/session/stage.d.ts +84 -0
- package/vendor/mwi/lib/session/stage.js +187 -0
- package/vendor/mwi/lib/session/workspace.d.ts +52 -0
- package/vendor/mwi/lib/session/workspace.js +90 -0
- package/vendor/mwi/lib/skill.d.ts +36 -0
- package/vendor/mwi/lib/skill.js +56 -0
- package/vendor/mwi/lib/tools/edit.d.ts +20 -0
- package/vendor/mwi/lib/tools/edit.js +286 -0
- package/vendor/mwi/lib/tools/read.d.ts +19 -0
- package/vendor/mwi/lib/tools/read.js +161 -0
- package/vendor/mwi/lib/tools/session.d.ts +20 -0
- package/vendor/mwi/lib/tools/session.js +166 -0
- package/vendor/mwi/lib/tools/verify.d.ts +19 -0
- package/vendor/mwi/lib/tools/verify.js +85 -0
- package/vendor/mwi/lib/verify.d.ts +17 -0
- package/vendor/mwi/lib/verify.js +29 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
using System; using System.IO; using System.Reflection; using System.Reflection.Emit;
|
|
2
|
+
using System.Runtime.InteropServices; using System.Runtime.InteropServices.ComTypes;
|
|
3
|
+
using System.Collections.Generic;
|
|
4
|
+
public class MwSdkInteropImporter : ITypeLibImporterNotifySink {
|
|
5
|
+
[DllImport("oleaut32.dll",CharSet=CharSet.Unicode)] static extern int LoadTypeLibEx(string file,int kind,out ITypeLib lib);
|
|
6
|
+
readonly string directory; readonly Dictionary<string,Assembly> imports=new Dictionary<string,Assembly>();
|
|
7
|
+
public readonly List<string> Notices=new List<string>();
|
|
8
|
+
public MwSdkInteropImporter(string dir){directory=dir;}
|
|
9
|
+
public void ReportEvent(ImporterEventKind kind,int code,string text){if(kind!=ImporterEventKind.NOTIF_TYPECONVERTED)Notices.Add(kind+":"+code+":"+text);}
|
|
10
|
+
public Assembly ResolveRef(object lib){throw new InvalidOperationException("Untested SDK assembly reference");}
|
|
11
|
+
public Assembly Import(ITypeLib lib,string ns){
|
|
12
|
+
string name,doc,helpFile;int help;lib.GetDocumentation(-1,out name,out doc,out help,out helpFile);
|
|
13
|
+
name=System.Text.RegularExpressions.Regex.Replace(name,"[^A-Za-z0-9_]","_");
|
|
14
|
+
Assembly found;if(imports.TryGetValue(name,out found))return found;
|
|
15
|
+
var file=Path.Combine(directory,name+".dll");
|
|
16
|
+
if(File.Exists(file))throw new InvalidOperationException("Refusing existing generated assembly "+file);
|
|
17
|
+
var assembly=new TypeLibConverter().ConvertTypeLibToAssembly(lib,file,TypeLibImporterFlags.ImportAsX86,this,null,null,ns,null);
|
|
18
|
+
assembly.Save(Path.GetFileName(file));imports.Add(name,assembly);return assembly;
|
|
19
|
+
}
|
|
20
|
+
public static string[] Generate(string tlb,string directory){
|
|
21
|
+
ITypeLib lib;Marshal.ThrowExceptionForHR(LoadTypeLibEx(tlb,2,out lib));
|
|
22
|
+
var importer=new MwSdkInteropImporter(directory);var assembly=importer.Import(lib,"MwAdeGenerated");
|
|
23
|
+
var results=new List<string>();
|
|
24
|
+
foreach(var type in assembly.GetTypes())if(type.Name=="_Variables"||type.Name=="_Variable"){
|
|
25
|
+
results.Add(type.FullName+" GUID="+type.GUID);
|
|
26
|
+
foreach(var method in type.GetMethods())results.Add(method.ToString());
|
|
27
|
+
}
|
|
28
|
+
results.AddRange(importer.Notices);return results.ToArray();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
using System;
|
|
2
|
+
using System.Collections.Generic;
|
|
3
|
+
using MwAdeGenerated;
|
|
4
|
+
public static class MwSdkVariableReader {
|
|
5
|
+
static object Optional(string value){return String.IsNullOrEmpty(value)?null:value;}
|
|
6
|
+
public static Dictionary<string,object>[] Read(object source){
|
|
7
|
+
var vars=(_Variables)source;int count=vars.Count;
|
|
8
|
+
var result=new List<Dictionary<string,object>>();
|
|
9
|
+
var sections=new Dictionary<int,string>{{1,"VAR"},{2,"VAR_INPUT"},{3,"VAR_OUTPUT"},{4,"VAR_IN_OUT"},{5,"VAR_EXTERNAL"},{6,"VAR_GLOBAL"}};
|
|
10
|
+
for(int n=1;n<=count;n++){
|
|
11
|
+
var v=(_Variable)vars.Item(n);string section;
|
|
12
|
+
if(!sections.TryGetValue((int)v.BlockType,out section))throw new InvalidOperationException("Unsupported native declaration usage");
|
|
13
|
+
result.Add(new Dictionary<string,object>{
|
|
14
|
+
{"name",v.Name},{"type",v.DataType},{"section",section},{"group",v.Group.Name},
|
|
15
|
+
{"address",Optional(v.IecAddress)},{"initial_value",Optional(v.InitialValue)},{"description",Optional(v.Comment)},
|
|
16
|
+
{"retain",v.Retain},{"pdd",v.PDD},{"opc",v.OPC},{"disabled",v.Disabled},{"not_on_plc",v.NotOnPlc},{"redundant",v.Redundant}
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
if(vars.Count!=count)throw new InvalidOperationException("Native declaration count changed during inspection");
|
|
20
|
+
return result.ToArray();
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
@echo off
|
|
2
|
+
rem Launches the MotionWorks Use COM bridge under 32-bit Windows PowerShell.
|
|
3
|
+
rem
|
|
4
|
+
rem WHY A .cmd WRAPPER
|
|
5
|
+
rem ------------------
|
|
6
|
+
rem Mwt.exe is a 32-bit LocalServer32, so a 64-bit client cannot create its COM
|
|
7
|
+
rem objects at all - the bitness here is load-bearing.
|
|
8
|
+
rem
|
|
9
|
+
rem The plugin spawns THIS file rather than invoking powershell.exe directly,
|
|
10
|
+
rem because Node's Windows argument quoting mangles the
|
|
11
|
+
rem -Command "& '<path>'"
|
|
12
|
+
rem form: the child starts and exits 0 without ever running the script. Passing a
|
|
13
|
+
rem single launcher path to cmd.exe is unambiguous.
|
|
14
|
+
rem
|
|
15
|
+
rem %~dp0 already ends with a backslash, so '%~dp0mw_bridge.ps1' resolves to the
|
|
16
|
+
rem sibling script.
|
|
17
|
+
rem
|
|
18
|
+
rem -WindowStyle Hidden matters: without it, powershell.exe creates its OWN
|
|
19
|
+
rem visible console window. That console then sits on top of the IDE, and because
|
|
20
|
+
rem mw_ide_screenshot captures a screen region it appeared inside the capture.
|
|
21
|
+
"%SystemRoot%\SysWOW64\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -Command "& '%~dp0mw_bridge.ps1'"
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
@echo off
|
|
2
|
+
rem Launches the MotionWorks Use modal-dialog watcher, hidden and detached.
|
|
3
|
+
rem
|
|
4
|
+
rem The bridge starts this immediately before OpenProject, because that COM call
|
|
5
|
+
rem blocks for as long as MotionWorks keeps a prompt on screen - so the prompt can
|
|
6
|
+
rem only be answered from another process. It is killed once OpenProject returns
|
|
7
|
+
rem or the bridge gives up.
|
|
8
|
+
rem
|
|
9
|
+
rem Takes the lifetime in seconds as %1, so the bridge controls the budget.
|
|
10
|
+
rem
|
|
11
|
+
rem -WindowStyle Hidden for the same reason start_bridge.cmd needs it: a visible
|
|
12
|
+
rem console would sit on top of the IDE and end up inside any screenshot.
|
|
13
|
+
"%SystemRoot%\SysWOW64\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -Command "& '%~dp0watch_dialogs.ps1' -Seconds %1"
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
<#
|
|
2
|
+
MotionWorks Use - modal-dialog watcher.
|
|
3
|
+
|
|
4
|
+
WHY THIS IS A SEPARATE PROCESS
|
|
5
|
+
------------------------------
|
|
6
|
+
OpenProject is a synchronous out-of-process COM call. When MotionWorks raises a
|
|
7
|
+
prompt *during* the load - "this project was not closed cleanly, load anyway?",
|
|
8
|
+
"defragment?" - the server enters a modal loop and the call does not return until
|
|
9
|
+
that prompt is answered. The bridge thread is therefore BLOCKED by definition and
|
|
10
|
+
cannot answer it; no retry, no timeout, no catch. Measured: an open call sat for
|
|
11
|
+
minutes with the request logged and no response.
|
|
12
|
+
|
|
13
|
+
So the answering has to happen on another thread, and in PowerShell that means
|
|
14
|
+
another process. The bridge starts this watcher immediately before OpenProject and
|
|
15
|
+
kills it afterwards; in between it presses the obvious answer on any known prompt.
|
|
16
|
+
|
|
17
|
+
SAFETY
|
|
18
|
+
------
|
|
19
|
+
Only ever touches prompts raised by the MotionWorks IDE process, and only presses
|
|
20
|
+
buttons from a fixed list of obviously-safe answers about a STAGED COPY - the
|
|
21
|
+
plugin never opens the user's original project. Anything unrecognised is left
|
|
22
|
+
completely alone.
|
|
23
|
+
#>
|
|
24
|
+
param(
|
|
25
|
+
[int]$Seconds = 150,
|
|
26
|
+
[int]$PollMs = 400
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
$ErrorActionPreference = 'Continue'
|
|
30
|
+
|
|
31
|
+
Add-Type -TypeDefinition @'
|
|
32
|
+
using System; using System.Text; using System.Runtime.InteropServices;
|
|
33
|
+
public class WDW {
|
|
34
|
+
[DllImport("user32.dll")] public static extern bool EnumWindows(EnumWindowsProc cb, IntPtr l);
|
|
35
|
+
[DllImport("user32.dll")] public static extern bool EnumChildWindows(IntPtr p, EnumWindowsProc cb, IntPtr l);
|
|
36
|
+
public delegate bool EnumWindowsProc(IntPtr h, IntPtr l);
|
|
37
|
+
[DllImport("user32.dll",CharSet=CharSet.Unicode)] public static extern int GetClassNameW(IntPtr h, StringBuilder s, int n);
|
|
38
|
+
[DllImport("user32.dll",CharSet=CharSet.Unicode)] public static extern int GetWindowTextW(IntPtr h, StringBuilder s, int n);
|
|
39
|
+
[DllImport("user32.dll")] public static extern bool IsWindowVisible(IntPtr h);
|
|
40
|
+
[DllImport("user32.dll")] public static extern int GetDlgCtrlID(IntPtr h);
|
|
41
|
+
[DllImport("user32.dll")] public static extern uint GetWindowThreadProcessId(IntPtr h, out uint p);
|
|
42
|
+
[DllImport("user32.dll", EntryPoint="SendMessageTimeoutW", CharSet=CharSet.Unicode)]
|
|
43
|
+
public static extern IntPtr SendTimeoutStr(IntPtr h, uint msg, IntPtr wp, StringBuilder lp, uint flags, uint ms, out IntPtr res);
|
|
44
|
+
[DllImport("user32.dll", EntryPoint="SendMessageTimeoutW", CharSet=CharSet.Unicode)]
|
|
45
|
+
public static extern IntPtr SendTimeoutInt(IntPtr h, uint msg, IntPtr wp, IntPtr lp, uint flags, uint ms, out IntPtr res);
|
|
46
|
+
|
|
47
|
+
const uint SMTO_ABORTIFHUNG = 0x0002;
|
|
48
|
+
|
|
49
|
+
public static string ReadText(IntPtr h) {
|
|
50
|
+
IntPtr r;
|
|
51
|
+
if (SendTimeoutInt(h, 0x000E, IntPtr.Zero, IntPtr.Zero, SMTO_ABORTIFHUNG, 150, out r) == IntPtr.Zero) return "";
|
|
52
|
+
int n = r.ToInt32(); if (n <= 0) return ""; if (n > 32768) n = 32768;
|
|
53
|
+
StringBuilder sb = new StringBuilder(n + 2);
|
|
54
|
+
if (SendTimeoutStr(h, 0x000D, (IntPtr)(n + 1), sb, SMTO_ABORTIFHUNG, 150, out r) == IntPtr.Zero) return "";
|
|
55
|
+
return sb.ToString();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
public static bool Click(IntPtr h) {
|
|
59
|
+
IntPtr r;
|
|
60
|
+
return SendTimeoutInt(h, 0x00F5, IntPtr.Zero, IntPtr.Zero, SMTO_ABORTIFHUNG, 1500, out r) != IntPtr.Zero;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
'@
|
|
64
|
+
|
|
65
|
+
# Prompts with one obviously-safe answer. These are questions about a staged COPY,
|
|
66
|
+
# so the answer cannot endanger real work. Anything absent from this table is left
|
|
67
|
+
# strictly alone - the watcher never guesses.
|
|
68
|
+
$known = @(
|
|
69
|
+
@{ match = 'defragment'; button = 'No' },
|
|
70
|
+
@{ match = 'would you like to load the project anyway'; button = 'Yes' },
|
|
71
|
+
@{ match = 'currently loaded by'; button = 'Yes' },
|
|
72
|
+
@{ match = 'abnormal termination'; button = 'Yes' },
|
|
73
|
+
@{ match = 'disabled/enabled by software key'; button = 'OK' },
|
|
74
|
+
@{ match = 'project is currently loaded'; button = 'Yes' }
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
$deadline = (Get-Date).AddSeconds($Seconds)
|
|
78
|
+
$answeredCount = 0
|
|
79
|
+
|
|
80
|
+
while ((Get-Date) -lt $deadline) {
|
|
81
|
+
Start-Sleep -Milliseconds $PollMs
|
|
82
|
+
|
|
83
|
+
# IDE pid, taken from the IDE window (never from a process-name lookup).
|
|
84
|
+
$script:idePid = 0
|
|
85
|
+
$cbIde = [WDW+EnumWindowsProc]{
|
|
86
|
+
param($h, $l)
|
|
87
|
+
$t = New-Object System.Text.StringBuilder 256
|
|
88
|
+
[void][WDW]::GetWindowTextW($h, $t, 256)
|
|
89
|
+
$title = $t.ToString()
|
|
90
|
+
if ([WDW]::IsWindowVisible($h) -and ($title -like 'MotionWorks IEC 3 Pro*' -or $title -like 'MULTIPROG*')) {
|
|
91
|
+
$p = [uint32]0; [void][WDW]::GetWindowThreadProcessId($h, [ref]$p)
|
|
92
|
+
$script:idePid = [int]$p
|
|
93
|
+
}
|
|
94
|
+
return $true
|
|
95
|
+
}
|
|
96
|
+
[void][WDW]::EnumWindows($cbIde, [IntPtr]::Zero)
|
|
97
|
+
if ($script:idePid -eq 0) { continue }
|
|
98
|
+
|
|
99
|
+
$script:hits = New-Object System.Collections.ArrayList
|
|
100
|
+
$cbDlg = [WDW+EnumWindowsProc]{
|
|
101
|
+
param($h, $l)
|
|
102
|
+
if (-not [WDW]::IsWindowVisible($h)) { return $true }
|
|
103
|
+
$p = [uint32]0; [void][WDW]::GetWindowThreadProcessId($h, [ref]$p)
|
|
104
|
+
if ([int]$p -ne $script:idePid) { return $true }
|
|
105
|
+
$c = New-Object System.Text.StringBuilder 64
|
|
106
|
+
[void][WDW]::GetClassNameW($h, $c, 64)
|
|
107
|
+
if ($c.ToString() -ne '#32770') { return $true }
|
|
108
|
+
|
|
109
|
+
$script:btnHandles = @{}
|
|
110
|
+
$texts = New-Object System.Collections.ArrayList
|
|
111
|
+
$cbKid = [WDW+EnumWindowsProc]{
|
|
112
|
+
param($k, $l2)
|
|
113
|
+
if (-not [WDW]::IsWindowVisible($k)) { return $true }
|
|
114
|
+
$kc = New-Object System.Text.StringBuilder 64
|
|
115
|
+
[void][WDW]::GetClassNameW($k, $kc, 64)
|
|
116
|
+
$cn = $kc.ToString()
|
|
117
|
+
if ($cn -ne 'Button' -and $cn -ne 'Static') { return $true }
|
|
118
|
+
$txt = [WDW]::ReadText($k)
|
|
119
|
+
if (-not $txt) { return $true }
|
|
120
|
+
if ($cn -eq 'Button') {
|
|
121
|
+
# Strip the accelerator marker to get the plain label. NB: a named
|
|
122
|
+
# regex group does NOT become a variable in PowerShell - it lives in
|
|
123
|
+
# $Matches - so the earlier `-match '^(?<lbl>.+)$'` form silently
|
|
124
|
+
# keyed every button on the empty string, the lookup never matched,
|
|
125
|
+
# and the watcher sat there answering nothing while the IDE stayed
|
|
126
|
+
# blocked. Verified by instrumenting it: message read fine, buttons
|
|
127
|
+
# dictionary empty.
|
|
128
|
+
$label = ($txt.Trim() -replace '&', '')
|
|
129
|
+
if ($label) { $script:btnHandles[$label] = $k }
|
|
130
|
+
} else { [void]$texts.Add($txt.Trim()) }
|
|
131
|
+
return $true
|
|
132
|
+
}
|
|
133
|
+
[void][WDW]::EnumChildWindows($h, $cbKid, [IntPtr]::Zero)
|
|
134
|
+
[void]$script:hits.Add([pscustomobject]@{
|
|
135
|
+
HWND = $h
|
|
136
|
+
Message = (($texts | Select-Object -Unique) -join "`n")
|
|
137
|
+
Buttons = $script:btnHandles
|
|
138
|
+
})
|
|
139
|
+
return $true
|
|
140
|
+
}
|
|
141
|
+
[void][WDW]::EnumWindows($cbDlg, [IntPtr]::Zero)
|
|
142
|
+
|
|
143
|
+
foreach ($d in $script:hits) {
|
|
144
|
+
$hay = $d.Message.ToLower()
|
|
145
|
+
foreach ($k in $known) {
|
|
146
|
+
if ($hay -notlike "*$($k.match)*") { continue }
|
|
147
|
+
$target = $null
|
|
148
|
+
foreach ($lbl in $d.Buttons.Keys) { if ($lbl -ieq $k.button) { $target = $d.Buttons[$lbl]; break } }
|
|
149
|
+
if ($target -and [WDW]::Click($target)) { $answeredCount++ }
|
|
150
|
+
break
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""File engine behind the MotionWorks plugin.
|
|
2
|
+
|
|
3
|
+
The package is layered so that the dangerous parts stay in one place:
|
|
4
|
+
|
|
5
|
+
cfb - OLE/CFB reader + writer primitives (no MotionWorks knowledge)
|
|
6
|
+
project - project/expanded-directory resolution and inventory
|
|
7
|
+
variables - merged view of the .VB text and .VGR binary variable stores
|
|
8
|
+
errors - typed failures that surface as readable tool errors
|
|
9
|
+
staging - refuses anything that is not a proven staged copy
|
|
10
|
+
|
|
11
|
+
The plugin in index.js is the tool surface. Writes go through mw_code.py.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
__version__ = "0.1.0"
|
|
Binary file
|
package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/block_interfaces.cpython-312.pyc
ADDED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/graphical_listing.cpython-312.pyc
ADDED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
"""Read block interfaces from the project's bound, installed libraries.
|
|
2
|
+
|
|
3
|
+
Firmware .PT parameter tables explicitly encode direction/type. User library
|
|
4
|
+
interfaces come from declaration streams, never from compiled identifier heaps.
|
|
5
|
+
Unsupported worksheets can expose independently counted, explicit cache
|
|
6
|
+
declarations as diagnostic evidence only, with insertion eligibility false.
|
|
7
|
+
This module only reads; no library is opened for editing or copied into a POU.
|
|
8
|
+
"""
|
|
9
|
+
import hashlib
|
|
10
|
+
import re
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from .cfb import CompoundFile
|
|
13
|
+
from .project import Project
|
|
14
|
+
from .tree import parse_document
|
|
15
|
+
from .variables import decode_declarations,read_grid_variable_count,cross_check,parse_declarations,CompressedStreamError
|
|
16
|
+
from .graphical_listing import DEPENDENCY_DECLARATION,identity as compiler_identity
|
|
17
|
+
|
|
18
|
+
SECTIONS={'VAR_INPUT':'input','VAR_OUTPUT':'output','VAR_IN_OUT':'in_out'}
|
|
19
|
+
KINDS={'FUNCTION':'FUNCTION','FUNCTION_BLOCK':'FUNCTION_BLOCK','FUNCTIONBLOCK':'FUNCTION_BLOCK','PROGRAM':'PROGRAM'}
|
|
20
|
+
IDENTIFIER=re.compile(r'^[A-Za-z_][A-Za-z_0-9]*$')
|
|
21
|
+
|
|
22
|
+
def compiler_type_names(text):
|
|
23
|
+
"""Read explicit names/type IDs from the observed complete TYLLIST table."""
|
|
24
|
+
header=re.match(r'\A\(\*\r?\nNDTE: (\d+)\r?\nNCPE: (\d+)\r?\nNDME: (\d+)\r?\n\*\)\r?\n',text)
|
|
25
|
+
if not header or '\0' in text:raise ValueError('Unsupported compiler type-table header/encoding')
|
|
26
|
+
roots=[];properties=0;dimensions=0;current=None;children=0;types={};root_ids=set();root_names=set()
|
|
27
|
+
def bind(name,number):
|
|
28
|
+
if not IDENTIFIER.fullmatch(name) or not number.isdigit() or int(number)<1:raise ValueError('Invalid compiler type identity')
|
|
29
|
+
key=int(number)
|
|
30
|
+
if key in types and types[key].casefold()!=name.casefold():raise ValueError('Conflicting compiler type names')
|
|
31
|
+
types[key]=name
|
|
32
|
+
def finish():
|
|
33
|
+
if current and current[6]!='STRING' and children!=int(current[4]):raise ValueError('Compiler type member count mismatch')
|
|
34
|
+
for line in text[header.end():].splitlines():
|
|
35
|
+
if not line:continue
|
|
36
|
+
fields=line.split('\t')
|
|
37
|
+
if len(fields)<2:raise ValueError('Unsupported compiler type row')
|
|
38
|
+
if not re.fullmatch(r'\d+ \d+',fields[0]):raise ValueError('Invalid compiler type source identity')
|
|
39
|
+
if len(fields)>6 and fields[1]:
|
|
40
|
+
finish()
|
|
41
|
+
if len(fields) not in (11,12) or fields[5]!='USER' or fields[6] not in ('STRUCT','ARRAY','ENUM','STRING') or not fields[4].isdigit():raise ValueError('Unsupported compiler type root')
|
|
42
|
+
if fields[3] in root_ids or fields[2].casefold() in root_names:raise ValueError('Duplicate compiler type root')
|
|
43
|
+
root_ids.add(fields[3]);root_names.add(fields[2].casefold());bind(fields[2],fields[3])
|
|
44
|
+
if fields[6]=='ARRAY':bind(fields[7],fields[8])
|
|
45
|
+
roots.append(fields);current=fields;children=0
|
|
46
|
+
else:
|
|
47
|
+
if current is None or fields[1] or len(fields) not in (6,7):raise ValueError('Unsupported compiler type member')
|
|
48
|
+
children+=1
|
|
49
|
+
if current[6]=='STRUCT':
|
|
50
|
+
if not IDENTIFIER.fullmatch(fields[2]):raise ValueError('Invalid compiler structure member')
|
|
51
|
+
bind(fields[3],fields[4]);properties+=1
|
|
52
|
+
elif current[6]=='ARRAY':
|
|
53
|
+
if fields[2] or not re.fullmatch(r'-?\d+',fields[3]) or not re.fullmatch(r'-?\d+',fields[4]):raise ValueError('Invalid compiler array dimension')
|
|
54
|
+
dimensions+=1
|
|
55
|
+
elif current[6]=='ENUM':
|
|
56
|
+
if not IDENTIFIER.fullmatch(fields[2]):raise ValueError('Invalid compiler enum member')
|
|
57
|
+
properties+=1
|
|
58
|
+
else:raise ValueError('Unexpected compiler string member')
|
|
59
|
+
finish()
|
|
60
|
+
if (len(roots),properties,dimensions)!=tuple(int(x) for x in header.groups()):raise ValueError('Compiler type table is incomplete')
|
|
61
|
+
return types
|
|
62
|
+
|
|
63
|
+
def parse_compiled_interface(listing,dependency,name,worksheet,type_names=None):
|
|
64
|
+
"""Diagnostic pins from explicit cache declarations, independently counted.
|
|
65
|
+
|
|
66
|
+
This does not establish freshness against a protected source worksheet and
|
|
67
|
+
intentionally has a different evidence kind from insertion-eligible tables.
|
|
68
|
+
"""
|
|
69
|
+
if '\0' in listing or '\0' in dependency:raise ValueError('Unsupported compiled interface encoding')
|
|
70
|
+
listing=listing.replace('\r','')
|
|
71
|
+
header=re.match(r'\A\(\*\n(.*?)\n\*\)\nFUNCTION_BLOCK ([A-Za-z_][A-Za-z_0-9]*)\n',listing,re.S)
|
|
72
|
+
if not header or header[2]!=name:raise ValueError('Compiled library interface identity mismatch')
|
|
73
|
+
counts=re.findall(r'^NVD:\s*(\d+)\s*$',header[1],re.M)
|
|
74
|
+
kinds=re.findall(r'^T:\s*(\w+)\s*$',header[1],re.M)
|
|
75
|
+
if kinds!=['FUNCTION_BLOCK'] or len(counts)!=1:raise ValueError('Compiled library header absent or ambiguous')
|
|
76
|
+
markers=list(re.finditer(r'^@WS (.+)$',listing,re.M))
|
|
77
|
+
expected='POE/'+name+'/'+worksheet
|
|
78
|
+
if len(markers)<2 or markers[0][1].replace('\\','/').casefold()!=expected.casefold():
|
|
79
|
+
raise ValueError('Compiled declaration worksheet identity mismatch')
|
|
80
|
+
declaration=listing[markers[0].end():markers[1].start()]
|
|
81
|
+
handles=re.findall(r'^@V (\d+) (\d+)\s+',declaration,re.M)
|
|
82
|
+
if not handles or len(set(handles))!=len(handles):raise ValueError('Compiled source declaration handles absent or duplicate')
|
|
83
|
+
cleaned=re.sub(r'^@V \d+ \d+\s*','',declaration,flags=re.M)
|
|
84
|
+
table=parse_declarations(cleaned)
|
|
85
|
+
if table.warnings or len(table.variables)!=len(handles):raise ValueError('Compiled source declarations incomplete')
|
|
86
|
+
names=[v.name.casefold() for v in table.variables]
|
|
87
|
+
if len(set(names))!=len(names):raise ValueError('Duplicate compiled source declaration name')
|
|
88
|
+
if compiler_identity(dependency)!=('FUNCTION_BLOCK',name):raise ValueError('Compiler dependency block identity mismatch')
|
|
89
|
+
dep_header=dependency.split('*)',1)[0]
|
|
90
|
+
dep_counts=re.findall(r'^QVE:\s*(\d+)\s*$',dep_header,re.M)
|
|
91
|
+
par_counts=re.findall(r'^QPar:\s*(\d+)\s*$',dep_header,re.M)
|
|
92
|
+
rows=list(DEPENDENCY_DECLARATION.finditer(dependency))
|
|
93
|
+
if len(dep_counts)!=1 or int(dep_counts[0])!=int(counts[0]) or len(rows)!=int(counts[0]):raise ValueError('Compiler declaration count mismatch')
|
|
94
|
+
if {int(r[2]) for r in rows}!=set(range(1,len(rows)+1)) or len({r[1].casefold() for r in rows})!=len(rows):
|
|
95
|
+
raise ValueError('Compiler declaration ordinals/names incomplete or duplicate')
|
|
96
|
+
source={(v.name,v.section) for v in table.variables}
|
|
97
|
+
ordinary={(r[1],r[3]) for r in rows if not re.fullmatch(r'@T_Code_\d+',r[1])}
|
|
98
|
+
if source!=ordinary or any(r[3]!='VAR' for r in rows if r[1].startswith('@')):
|
|
99
|
+
raise ValueError('Library/dependency declaration identities differ')
|
|
100
|
+
pins=[dict(name=v.name,type=v.type_name,section=v.section,direction=SECTIONS[v.section],initial_value=v.initial_value,description=v.description)
|
|
101
|
+
for v in table.variables if v.section in SECTIONS]
|
|
102
|
+
if par_counts!=[str(len(pins))] or not pins:raise ValueError('Compiler public parameter count mismatch')
|
|
103
|
+
if type_names is not None:
|
|
104
|
+
by_name={r[1]:r for r in rows}
|
|
105
|
+
for pin in pins:
|
|
106
|
+
token=re.fullmatch(r'@TYP:(\d+)\s*',by_name[pin['name']][4])
|
|
107
|
+
if not token or type_names.get(int(token[1]),'').casefold()!=pin['type'].casefold():raise ValueError('Compiled public pin type differs from explicit declaration')
|
|
108
|
+
return dict(pins=pins,source_declaration_count=len(table.variables),compiler_declaration_count=len(rows),compiler_pin_types_verified=type_names is not None)
|
|
109
|
+
|
|
110
|
+
def _cached_library_interface(project_root,library_root,pou):
|
|
111
|
+
cache=pou.source_path.parent/'tmp.sto'
|
|
112
|
+
if not cache.resolve().is_relative_to(Path(library_root).resolve()):raise ValueError('Linked library cache escapes its bound root')
|
|
113
|
+
before=hashlib.sha256(cache.read_bytes()).hexdigest()
|
|
114
|
+
source_hash=hashlib.sha256(pou.source_path.read_bytes()).hexdigest()
|
|
115
|
+
container=CompoundFile(cache);stream='@$@$@$@$.clu'
|
|
116
|
+
matches=[n for n in container.stream_names() if n.casefold()==stream.casefold()]
|
|
117
|
+
worksheets=[n for n in pou.source().stream_names() if n.upper().endswith('.VB')]
|
|
118
|
+
if len(matches)!=1 or len(worksheets)!=1:raise ValueError('Compiled library declaration stream absent or ambiguous')
|
|
119
|
+
listing=container.read_stream(matches[0])
|
|
120
|
+
if len(listing)>2_000_000:raise ValueError('Compiled declaration cache exceeds bound')
|
|
121
|
+
dependencies=[]
|
|
122
|
+
for path in (Path(project_root)/'C').rglob('ICI*.DIT'):
|
|
123
|
+
if not path.resolve().is_relative_to(Path(project_root).resolve()):raise ValueError('Linked compiler dependency escapes project')
|
|
124
|
+
if path.stat().st_size>2_000_000:raise ValueError('Compiler dependency exceeds bound')
|
|
125
|
+
raw=path.read_bytes()
|
|
126
|
+
try:kind,name=compiler_identity(raw.decode('latin1'))
|
|
127
|
+
except ValueError:continue
|
|
128
|
+
if kind=='FUNCTION_BLOCK' and name==pou.name:dependencies.append((path,raw))
|
|
129
|
+
if len(dependencies)!=1:raise ValueError('Matching saved compiler dependency absent or ambiguous')
|
|
130
|
+
dependency,raw=dependencies[0]
|
|
131
|
+
type_table=dependency.with_name('TYLLIST.TYP')
|
|
132
|
+
if not type_table.resolve().is_relative_to(Path(project_root).resolve()) or type_table.stat().st_size>2_000_000:raise ValueError('Compiler type table outside project or oversized')
|
|
133
|
+
type_bytes=type_table.read_bytes();type_names=compiler_type_names(type_bytes.decode('latin1'))
|
|
134
|
+
identifiers=re.findall(r'^CI#:\s*(\d+)\s*$',raw.decode('latin1').split('*)',1)[0],re.M)
|
|
135
|
+
if len(identifiers)!=1 or int(identifiers[0])!=int(dependency.stem[3:]):raise ValueError('Compiler dependency file/type identity mismatch')
|
|
136
|
+
result=parse_compiled_interface(listing.decode('latin1'),raw.decode('latin1'),pou.name,worksheets[0],type_names)
|
|
137
|
+
if before!=hashlib.sha256(cache.read_bytes()).hexdigest() or raw!=dependency.read_bytes() or type_bytes!=type_table.read_bytes() or source_hash!=hashlib.sha256(pou.source_path.read_bytes()).hexdigest():raise ValueError('Compiled interface changed during read')
|
|
138
|
+
result.update(source_stream=matches[0],cache_file=str(cache),cache_sha256=before,
|
|
139
|
+
worksheet_file=str(pou.source_path),worksheet_sha256=source_hash,
|
|
140
|
+
compiler_dependency=str(dependency),compiler_dependency_sha256=hashlib.sha256(raw).hexdigest(),
|
|
141
|
+
compiler_type_table=str(type_table),compiler_type_table_sha256=hashlib.sha256(type_bytes).hexdigest(),
|
|
142
|
+
origin='user_library_compiled_declarations',compiler_cache_freshness_verified=False,compiler_source_binding_verified=False,
|
|
143
|
+
insertion_eligible=False,evidence_kind='installed-compiled-block-interface')
|
|
144
|
+
return result
|
|
145
|
+
|
|
146
|
+
def parse_parameter_table(data):
|
|
147
|
+
headers={}; pins=[]; started=False
|
|
148
|
+
for line in data.decode('latin1').splitlines():
|
|
149
|
+
if not line.strip():continue
|
|
150
|
+
if line=='parameters:':started=True;continue
|
|
151
|
+
if not started:
|
|
152
|
+
key,sep,value=line.partition(':')
|
|
153
|
+
if not sep or key in headers:raise ValueError('Malformed parameter-table header')
|
|
154
|
+
headers[key]=value.strip()
|
|
155
|
+
else:
|
|
156
|
+
columns=line.split('\t')
|
|
157
|
+
if len(columns)<4 or columns[0] or columns[1] not in SECTIONS:raise ValueError('Unsupported parameter-table row')
|
|
158
|
+
section,name,type_name=columns[1:4]
|
|
159
|
+
if not IDENTIFIER.fullmatch(name) or not type_name:raise ValueError('Invalid parameter identity')
|
|
160
|
+
pins.append(dict(name=name,type=type_name,section=section,direction=SECTIONS[section],native_attributes=columns[4:]))
|
|
161
|
+
name=headers.get('pouName','');kind=KINDS.get(headers.get('pouKind',''))
|
|
162
|
+
if not IDENTIFIER.fullmatch(name) or not kind or not started or not headers.get('parNum','').isdigit():raise ValueError('Unsupported parameter-table identity/count')
|
|
163
|
+
if len(pins)!=int(headers['parNum']) or len({p['name'].casefold() for p in pins})!=len(pins):raise ValueError('Parameter-table count/identity mismatch')
|
|
164
|
+
return dict(name=name,kind=kind,pins=pins,native_headers=headers)
|
|
165
|
+
|
|
166
|
+
def _registry(path):
|
|
167
|
+
rows=[]
|
|
168
|
+
for line in path.read_text(encoding='latin1').splitlines():
|
|
169
|
+
if not line.strip():continue
|
|
170
|
+
cols=line.split('\t');kind=KINDS.get(cols[0].upper())
|
|
171
|
+
if not kind or len(cols)<2 or not IDENTIFIER.fullmatch(cols[1]):raise ValueError('Unsupported library registry row')
|
|
172
|
+
alias=cols[5] if len(cols)>5 and cols[5] else cols[1]
|
|
173
|
+
if not IDENTIFIER.fullmatch(alias):raise ValueError('Unsupported library worksheet alias')
|
|
174
|
+
rows.append(dict(name=cols[1],kind=kind,alias=alias,hidden=any(c=='HIDDEN=1' for c in cols)))
|
|
175
|
+
if len({r['name'].casefold() for r in rows})!=len(rows):raise ValueError('Duplicate library registry name')
|
|
176
|
+
return rows
|
|
177
|
+
|
|
178
|
+
def _same_path(a,b):return str(Path(a).resolve()).casefold()==str(Path(b).resolve()).casefold()
|
|
179
|
+
|
|
180
|
+
def _user_library_declarations(root,pou):
|
|
181
|
+
if pou.declaration_stream_name() is not None:
|
|
182
|
+
return pou.declarations()
|
|
183
|
+
# User libraries can name their worksheets Variables/Code instead of
|
|
184
|
+
# <POU>V/<POU>. Bind the one declaration stream to its saved grid worksheet;
|
|
185
|
+
# do not infer directions from compiler heaps or unrelated streams.
|
|
186
|
+
container=pou.source();names=container.stream_names()
|
|
187
|
+
matches=[n for n in names if n.upper().endswith('.VB')]
|
|
188
|
+
if len(matches)!=1 or not matches[0][:-3]:
|
|
189
|
+
raise ValueError('User-library declaration worksheet absent or ambiguous')
|
|
190
|
+
declaration=matches[0];grid=declaration[:-3]+'.VGR'
|
|
191
|
+
grids=[n for n in names if n.casefold()==grid.casefold()]
|
|
192
|
+
if len(grids)!=1:raise ValueError('User-library declaration/grid worksheet pair absent or ambiguous')
|
|
193
|
+
document=parse_document(CompoundFile(Path(root)/'src.st1').read_stream('PROJECT.TRE').decode('latin1'))
|
|
194
|
+
expected=('POE/'+pou.name+'/'+grids[0]).casefold()
|
|
195
|
+
nodes=[n for n,_ in document.walk_with_ancestors()
|
|
196
|
+
if n.path.split('\t')[0].replace('\\','/').casefold()==expected]
|
|
197
|
+
if document.warnings or len(nodes)!=1 or document.lines[nodes[0].start_line].strip()!='8':
|
|
198
|
+
raise ValueError('User-library variable worksheet tree identity absent or ambiguous')
|
|
199
|
+
table=decode_declarations(container.read_stream(declaration),declaration)
|
|
200
|
+
count=read_grid_variable_count(container.read_stream(grids[0]))
|
|
201
|
+
if count is None:raise ValueError('User-library variable grid count unavailable')
|
|
202
|
+
table.warnings.extend(cross_check(table,count))
|
|
203
|
+
return table
|
|
204
|
+
|
|
205
|
+
def sources(root,native_libraries):
|
|
206
|
+
root=Path(root);project=Project(root)
|
|
207
|
+
native={r['name'].casefold():r for r in native_libraries}
|
|
208
|
+
if len(native)!=len(native_libraries):raise ValueError('Ambiguous native library inventory')
|
|
209
|
+
result=[dict(library='project',kind='PROJECT',root=root,registry=root/'LIST.POU',binding='active_project')]
|
|
210
|
+
lines=(root/'@LIBRARY.LST').read_text(encoding='latin1').splitlines()
|
|
211
|
+
if not lines or lines[0]!='Library List, V40':raise ValueError('Unsupported saved library registry')
|
|
212
|
+
used=set()
|
|
213
|
+
for line in lines[1:]:
|
|
214
|
+
if not line.strip():continue
|
|
215
|
+
fields=line.split(';')
|
|
216
|
+
if len(fields)!=4 or fields[0] not in ['FW','USER']:raise ValueError('Unsupported saved library reference')
|
|
217
|
+
kind,path,label,flags=fields;directory=Path(path)
|
|
218
|
+
library=directory.name if kind=='USER' else label
|
|
219
|
+
if not IDENTIFIER.fullmatch(library):raise ValueError('Unsupported library name')
|
|
220
|
+
row=native.get(library.casefold())
|
|
221
|
+
expected=Path(str(directory)+'.mwt') if kind=='USER' else directory/(label+'.fwl')
|
|
222
|
+
if row:
|
|
223
|
+
if not _same_path(row['full_name'],expected):raise ValueError('Saved/native library paths disagree: '+library)
|
|
224
|
+
used.add(library.casefold());binding='native_reference'
|
|
225
|
+
elif kind=='FW' and library.casefold() in ['iec','eclr']:
|
|
226
|
+
binding='saved_implicit_reference'
|
|
227
|
+
else:raise ValueError('Saved/native library inventories disagree: '+library)
|
|
228
|
+
registry=directory/'LIST.POU' if kind=='USER' else directory/(label+'.POU')
|
|
229
|
+
result.append(dict(library=library,kind=kind,root=directory,registry=registry,binding=binding,reference_file=expected,flags=flags))
|
|
230
|
+
if used!=set(native):raise ValueError('Native library absent from saved references')
|
|
231
|
+
return result
|
|
232
|
+
|
|
233
|
+
def inspect(root,native_libraries,name=None,library=None):
|
|
234
|
+
candidates=[];unavailable=[]
|
|
235
|
+
for source in sources(root,native_libraries):
|
|
236
|
+
if library and source['library'].casefold()!=library.casefold():continue
|
|
237
|
+
try:rows=_registry(source['registry'])
|
|
238
|
+
except (OSError,ValueError) as error:
|
|
239
|
+
unavailable.append(dict(library=source['library'],error=str(error)));continue
|
|
240
|
+
for row in rows:
|
|
241
|
+
if name and row['name'].casefold()!=name.casefold():continue
|
|
242
|
+
candidates.append({**row,'library':source['library'],'binding':source['binding'],'_source':source})
|
|
243
|
+
if not name:
|
|
244
|
+
return dict(blocks=[{k:v for k,v in row.items() if k!='_source'} for row in candidates],unavailable_libraries=unavailable,
|
|
245
|
+
evidence_kind='bound-installed-block-catalog',action_performed=False)
|
|
246
|
+
if len(candidates)!=1:raise ValueError('Block absent or ambiguous; specify its library. Candidates: '+str([(c['library'],c['name']) for c in candidates])+'; unavailable: '+str(unavailable))
|
|
247
|
+
row=candidates[0];source=row.pop('_source')
|
|
248
|
+
if source['kind']=='FW':
|
|
249
|
+
file=source['root']/'tmp.sto';container=CompoundFile(file)
|
|
250
|
+
matches=[n for n in container.stream_names() if n.casefold()==(row['alias']+'.PT').casefold()]
|
|
251
|
+
if len(matches)!=1:raise ValueError('Firmware parameter table absent or ambiguous')
|
|
252
|
+
data=container.read_stream(matches[0]);interface=parse_parameter_table(data)
|
|
253
|
+
if interface['name'].casefold()!=row['name'].casefold() or interface['kind']!=row['kind']:raise ValueError('Registry/parameter interface identity mismatch')
|
|
254
|
+
row.update(interface);row.update(source_stream=matches[0],source_sha256=hashlib.sha256(data).hexdigest(),origin='firmware_parameter_table')
|
|
255
|
+
else:
|
|
256
|
+
pou=Project(source['root']).pou(row['name'])
|
|
257
|
+
try:
|
|
258
|
+
table=_user_library_declarations(source['root'],pou) if source['kind']=='USER' else pou.declarations()
|
|
259
|
+
except CompressedStreamError:
|
|
260
|
+
if source['kind']!='USER':raise
|
|
261
|
+
row.update(_cached_library_interface(root,source['root'],pou))
|
|
262
|
+
file=Path(row['cache_file'])
|
|
263
|
+
row.update(source_sha256=hashlib.sha256(file.read_bytes()).hexdigest(),source_file=str(file),
|
|
264
|
+
reference_registry=str(source['registry']),registry_sha256=hashlib.sha256(source['registry'].read_bytes()).hexdigest(),
|
|
265
|
+
action_performed=False,note='Diagnostic cache declarations matched a saved compiler dependency. Freshness against the protected worksheet is unverified; do not use this interface for insertion. Native Build and complete source/library validation are still required.')
|
|
266
|
+
return row
|
|
267
|
+
if table.warnings:raise ValueError('Declaration interface parse warnings: '+str(table.warnings))
|
|
268
|
+
file=pou.source_path
|
|
269
|
+
row['pins']=[dict(name=v.name,type=v.type_name,section=v.section,direction=SECTIONS[v.section],initial_value=v.initial_value,description=v.description)
|
|
270
|
+
for v in table.variables if v.section in SECTIONS]
|
|
271
|
+
row.update(source_sha256=hashlib.sha256(file.read_bytes()).hexdigest(),source_stream=table.source_stream,origin='project_declarations' if source['kind']=='PROJECT' else 'user_library_declarations')
|
|
272
|
+
row.update(source_file=str(file),reference_registry=str(source['registry']),registry_sha256=hashlib.sha256(source['registry'].read_bytes()).hexdigest(),
|
|
273
|
+
evidence_kind='installed-declared-block-interface',action_performed=False,
|
|
274
|
+
note='Pin directions/types come from declarations or native parameter tables. Implicit references are identified separately. Verify the selected controller/firmware profile and Build/Make before machine use.')
|
|
275
|
+
return row
|