Skip to content

Instantly share code, notes, and snippets.

@Drugoy
Last active August 29, 2015 14:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Drugoy/7905a4c8fc4167098bf2 to your computer and use it in GitHub Desktop.
Save Drugoy/7905a4c8fc4167098bf2 to your computer and use it in GitHub Desktop.
A small script to save describe networking stands
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn ; Enable warnings to assist with detecting common errors.
SetWorkingDir, %A_ScriptDir% ; Ensures a consistent starting directory.
#SingleInstance, Force
If %0% ; The script was called with at least 1 argument, expectedly the user drag'n'dropped something onto the script.
Loop, %0%
input := %A_Index%
If FileExist(input) ; Not sure if this needed, since user can't drag'n'drop an unexisting file.
FileRead, input, %input%
; Loop, %inputFileName%
; inputFileName := A_LoopFileName
; input = [{"defroute":"123.123.123.123","ifaces":[{"addrs":[{"IP":"1.0.0.2","mask":"24"},{"IP":"321.123.123.123","mask":"23"}],"name":"em0","descr":"external","Net":"vnet2"},{"addrs":[{"IP":"2.0.0.1","mask":"24"},{"IP":"2.0.0.3","mask":"23"}],"name":"em1","descr":"internal","Net":"vnet3"}],"name":"NCC"},{"defroute":"2.0.0.1","ifaces":[{"addrs":[{"IP":"2.0.0.2","mask":"24"}],"name":"em0","descr":"external","Net":"vnet4"},{"addrs":[{"IP":"172.17.6.6","mask":"22"},{"IP":"10.0.0.3","mask":"24"}],"name":"em1","descr":"external","Net":"vnet5"}],"name":"ПУ ЦУС"}]
If input
{
Try
machines := JSON.parse(input)
Catch E
MsgBox, % e
}
Else
machines := [{"Name": "", "DefRoute": "", "ifaces":[ {"Name": "em0", "Descr": "external", "Net": "vnet1", "Addrs":[ {"IP": "0.0.0.0", "Mask": "24"} ] }] }]
DrawGUI:
; Menu, menuToolbar, Add, Add node, AddNode
Menu, menuToolbar, Add, Open, Open
Menu, menuToolbar, Add, Save, Save
Menu, menuToolbar, Add, Parse JSON, ParseTextJSON
Gui, Menu, menuToolbar
GoSub, ParseJSON
Gui, Show
Return
ParseJSON:
For node In machines
{
margin := 10 + (node-1) * 190
Gui, Add, Text, x%margin% y0, Name:
Gui, Add, Edit, x+0 w120 h16 vn%node%Name, % machines[node].Name
If !(node = 1 && machines.MaxIndex() = 1) ; Forbid to remove the last existing node.
Gui, Add, Button, x+0 w16 h16 vdelN%node% gDeleteNode, -
Gui, Add, Button, x+0 w16 h16 vaddN%node% gAddNode, +
Gui, Add, Text, x%margin% y+0, Default route:
Gui, Add, Edit, x+0 w87 h16 vn%node%DefRoute, % machines[node].defRoute
For iface In machines[node].ifaces
{
Gui, Add, Text, x%margin% y+0, If %iface%:
Gui, Add, Edit, x+0 w29 h16 vn%node%If%iface%Name, % machines[node].ifaces[iface].Name
Gui, Add, Text, x+0, Type:
Gui, Add, Edit, x+0 w77 h16 vn%node%If%iface%Descr, % machines[node].ifaces[iface].Descr
If !(iface = 1 && machines[node].ifaces.MaxIndex() = 1) ; Forbid to remove the last existing iface.
Gui, Add, Button, x+0 w16 h16 vn%node%DelIf%iface% gDeleteIf, -
Gui, Add, Button, x+0 w16 h16 vn%node%AddIf%iface% gAddIf, +
Gui, Add, Text, x%margin% y+0, Net:
Gui, Add, Edit, x+0 w131 h16 vn%node%If%iface%Net, % machines[node].ifaces[iface].Net
For addr In machines[node].ifaces[iface].addrs
{
Gui, Add, Text, x%margin% y+0, Addr%addr%:
Gui, Add, Edit, x+5 w89 h16 vn%node%If%iface%a%addr%addr, % machines[node].ifaces[iface].addrs[addr].IP
Gui, Add, Text, x+0, /
Gui, Add, Edit, x+0 w21 h16 vn%node%if%iface%a%addr%mask, % machines[node].ifaces[iface].addrs[addr].mask
If !(addr = 1 && machines[node].ifaces[iface].addrs.MaxIndex() = 1) ; Forbid to remove the last existing addr.
Gui, Add, Button, x+0 w16 h16 vn%node%If%iface%DelA%addr% gDeleteAddr, -
Gui, Add, Button, x+0 w16 h16 vn%node%If%iface%AddA%addr% gAddAddr, +
}
}
}
Return
Open:
FileSelectFile, input,,, Select a file with your saved stand, Stand (*.json)
If (!ErrorLevel && input)
{
FileRead, input, %input%
If input
{
Try
machines := JSON.parse(input)
Catch E
MsgBox, % e
}
GoSub, Repaint
}
Return
Save:
FileSelectFile, output, S, % (output ? output : A_WorkingDir) "\" A_Now ".json", Where to save this stand to?
If (!ErrorLevel && output)
{
jsoned := JSON.stringify(machines)
If FileExist(output)
FileDelete, %output%
FileAppend, %jsoned%, %output%, UTF-8
; GoSub, Repaint
}
Return
ParseTextJSON:
Gui, InputJSON: New
Gui, Add, Text,, Paste your JSON'ified stand:
Gui, Add, Edit, w300 h250 vinputJSON
Gui, Add, Button, x250, Parse
Gui, InputJSON: Show
Gui, 1: Default
Return
Repaint:
Gui, Destroy
GoSub, DrawGUI
Return
DeleteNode:
machines.Remove(SubStr(A_GuiControl, 5))
GoSub, Repaint
Return
AddNode:
RegExMatch(A_GuiControl, "Si)^addN(\d+)$", this)
; machines.Insert(this1+1, machines[machines.MaxIndex()]) ; Duplicate
machines.Insert(this1+1, {"name": "", "defroute": "", "ifaces":[ {"name":"","type":"","addrs":[ {"IP": "", "mask": ""} ] } ] })
GoSub, Repaint
Return
DeleteIf:
RegExMatch(A_GuiControl, "Si)^n(\d+)DelIf(\d+)$", this)
machines[this1].ifaces.Remove(this2)
GoSub, Repaint
Return
AddIf:
RegExMatch(A_GuiControl, "Si)^n(\d+)AddIf(\d+)$", this)
; machines[this1].ifaces.Insert(this2+1, machines[this1].ifaces[machines[this1].ifaces.MaxIndex()]) ; Duplicate
machines[this1].ifaces.Insert(this2+1, {"name":"","type":"","addrs":[ {"IP": "", "mask": ""} ] })
GoSub, Repaint
Return
DeleteAddr:
RegExMatch(A_GuiControl, "Si)^n(\d+)If(\d+)DelA(\d+)$", this)
machines[this1].ifaces[this2].addrs.Remove(this3)
GoSub, Repaint
Return
AddAddr:
RegExMatch(A_GuiControl, "Si)^n(\d+)If(\d+)AddA(\d+)$", this)
; machines[this1].ifaces[this2].addrs.Insert(this3+1, machines[this1].ifaces[this2].addrs[machines[this1].ifaces[this2].addrs.MaxIndex()]) ; Duplicate
machines[this1].ifaces[this2].addrs.Insert(this3+1, {"IP": "", "mask": ""})
GoSub, Repaint
Return
;{ JSON lib
class JSON
{
/* Function: parse
* Deserialize a string containing a JSON document to an AHK object.
* Syntax:
* json_obj := JSON.parse( src [, jsonize:=false ] )
* Parameter(s):
* src [in] - String containing a JSON document
* jsonize [in] - If true, objects {} and arrays [] are wrapped as
* JSON.object and JSON.array instances respectively.
*/
parse(src, jsonize:=false) {
;// Pre-validate JSON source before parsing
if ((src := Trim(src, " `t`n`r")) == "") ;// trim whitespace(s)
throw "Empty JSON source"
first := SubStr(src, 1, 1), last := SubStr(src, 0)
if !InStr("{[""tfn0123456789-", first) ;// valid beginning chars
|| !InStr("}]""el0123456789", last) ;// valid ending chars
|| (first == "{" && last != "}") ;// if starts w/ '{' must end w/ '}'
|| (first == "[" && last != "]") ;// if starts w/ '[' must end w/ ']'
|| (first == """" && last != """") ;// if starts w/ '"' must end w/ '"'
|| (first == "n" && last != "l") ;// assume 'null'
|| (InStr("tf", first) && last != "e") ;// assume 'true' OR 'false'
|| (InStr("-0123456789", first) && !InStr("0123456789", last)) ;// number
throw "Invalid JSON format"
esc_seq := {
(Join
"""": """",
"/": "/",
"b": "`b",
"f": "`f",
"n": "`n",
"r": "`r",
"t": "`t"
)}
i := 0, strings := []
while (i := InStr(src, """",, i+1)) {
j := i
while (j := InStr(src, """",, j+1)) {
str := SubStr(src, i+1, j-i-1)
StringReplace, str, str, \\, \u005C, A
if (SubStr(str, 0) != "\")
break
}
if !j
throw "Missing close quote(s)"
src := SubStr(src, 1, i) . SubStr(src, j+1)
k := 0
while (k := InStr(str, "\",, k+1)) {
ch := SubStr(str, k+1, 1)
if InStr("""btnfr/", ch, 1)
str := SubStr(str, 1, k-1) . esc_seq[ch] . SubStr(str, k+2)
else if (ch == "u") {
hex := "0x" . SubStr(str, k+2, 4)
if !(A_IsUnicode || (Abs(hex) < 0x100))
continue ;// throw Exception() ???
str := SubStr(str, 1, k-1) . Chr(hex) . SubStr(str, k+6)
} else throw "Invalid escape sequence: '\" ch "'"
}
strings.Insert(str)
}
;// Check for missing opening/closing brace(s)
if InStr(src, "{") || InStr(src, "}") {
StringReplace, dummy, src, {, {, UseErrorLevel
c1 := ErrorLevel
StringReplace, dummy, src, }, }, UseErrorLevel
c2 := ErrorLevel
if (c1 != c2)
throw "Missing " . Abs(c1-c2) . (c1 > c2 ? "clos" : "open") . "ing brace(s)"
}
;// Check for missing opening/closing bracket(s)
if InStr(src, "[") || InStr(src, "]") {
StringReplace, dummy, src, [, [, UseErrorLevel
c1 := ErrorLevel
StringReplace, dummy, src, ], ], UseErrorLevel
c2 := ErrorLevel
if (c1 != c2)
throw "Missing " . Abs(c1-c2) . (c1 > c2 ? "clos" : "open") . "ing bracket(s)"
}
t := "true", f := "false", n := "null", null := ""
jbase := jsonize ? {"{":JSON.object, "[":JSON.array} : {"{":0, "[":0}
, pos := 0
, key := "", is_key := false
, stack := [tree := []]
, is_arr := Object(tree, 1)
, next := first ;// """{[01234567890-tfn"
while ((ch := SubStr(src, ++pos, 1)) != "") {
if InStr(" `t`n`r", ch)
continue
if !InStr(next, ch)
throw "Unexpected char: '" ch "'"
is_array := is_arr[obj := stack[1]]
if InStr("{[", ch) {
val := (proto := jbase[ch]) ? new proto : {}
, obj[is_array? NumGet(&obj+4*A_PtrSize)+1 : key] := val
, ObjInsert(stack, 1, val)
, is_arr[val] := !(is_key := ch == "{")
, next := is_key ? """}" : """{[]0123456789-tfn"
}
else if InStr("}]", ch) {
ObjRemove(stack, 1)
, next := is_arr[stack[1]] ? "]," : "},"
}
else if InStr(",:", ch) {
if (obj == tree)
throw "Unexpected char: '" ch "' -> there is no container object."
next := """{[0123456789-tfn", is_key := (!is_array && ch == ",")
}
else {
if (ch == """") {
val := ObjRemove(strings, 1)
if is_key {
key := val, next := ":"
continue
}
} else {
val := SubStr(src, pos, (SubStr(src, pos) ~= "[\]\},\s]|$")-1)
, pos += StrLen(val)-1
if InStr("tfn", ch, 1) {
if !(val == %ch%)
throw "Expected '" %ch% "' instead of '" val "'"
val := %val%
} else if (Abs(val) == "") {
throw "Invalid number: " val
}
val += 0
}
obj[is_array? NumGet(&obj+4*A_PtrSize)+1 : key] := val
, next := is_array ? "]," : "},"
}
}
return tree[1]
}
/* Function: stringify
* Serialize an object to a JSON formatted string.
* Syntax:
* json_str := JSON.stringify( obj [, indent:="" ] )
* Parameter(s):
* obj [in] - The object to stringify.
* indent [in] - Specify string(s) to use as indentation per level.
*/
stringify(obj:="", indent:="", lvl:=1) {
if IsObject(obj) {
if (ObjGetCapacity(obj) == "") ;// COM,Func,RegExMatch,File object
throw "Unsupported object type"
is_array := 0
for k in obj
is_array := (k == A_Index)
until !is_array
if (Abs(indent) != "") {
if (indent < 0)
throw "Indent parameter must be a postive integer"
spaces := indent, indent := ""
Loop % spaces
indent .= " "
}
indt := ""
Loop, % indent ? lvl : 0
indt .= indent
lvl += 1, out := "" ;// make #Warn happy
for k, v in obj {
if IsObject(k) || (k == "")
throw "Invalid JSON key"
if !is_array
out .= ( ObjGetCapacity([k], 1) ? JSON.stringify(k) : q . k . q ) ;// key
. ( indent ? ": " : ":" ) ;// token + padding
out .= JSON.stringify(v, indent, lvl) ;// value
. ( indent ? ",`n" . indt : "," ) ;// token + indent
}
if (out != "") {
out := Trim(out, ",`n" indent)
if (indent != "")
out := "`n" . indt . out . "`n" . SubStr(indt, StrLen(indent)+1)
}
return is_array ? "[" out "]" : "{" out "}"
}
;// Not a string - assume number -> integer or float
if (ObjGetCapacity([obj], 1) == "") ;// returns an integer if 'obj' is string
return InStr("01", obj) ? (obj ? "true" : "false") : obj
;// null
else if (obj == "")
return "null"
;// String
; if obj is float
; return obj
esc_seq := {
(Join
"""": "\""",
"/": "\/",
"`b": "\b",
"`f": "\f",
"`n": "\n",
"`r": "\r",
"`t": "\t"
)}
StringReplace, obj, obj, \, \\, A
for k, v in esc_seq
StringReplace, obj, obj, %k%, %v%, A
while RegExMatch(obj, "[^\x20-\x7e]", wstr) {
ucp := Asc(wstr), hex := "\u", n := 16
while ((n-=4) >= 0)
hex .= Chr( (x := (ucp >> n) & 15) + (x < 10 ? 48 : 55) )
StringReplace, obj, obj, %wstr%, %hex%, A
}
return """" . obj . """"
}
class object
{
__New(args*) {
ObjInsert(this, "_", [])
if ((count := NumGet(&args+4*A_PtrSize)) & 1)
throw "Invalid number of parameters"
Loop, % count//2
this[args[A_Index*2-1]] := args[A_Index*2]
}
__Set(key, val, args*) {
ObjInsert(this._, key)
}
Insert(key, val) {
return this[key] := val
}
/* Buggy - remaining integer keys are not adjusted
Remove(args*) {
ret := ObjRemove(this, args*), i := -1
for index, key in ObjClone(this._) {
if ObjHasKey(this, key)
continue
ObjRemove(this._, index-(i+=1))
}
return ret
}
*/
Count() {
return NumGet(&(this._)+4*A_PtrSize) ;// Round(this._.MaxIndex())
}
stringify(indent:="") {
return JSON.stringify(this, indent)
}
_NewEnum() {
static proto := {"Next":JSON.object.Next}
return {
(LTrim Join
"base": proto,
"enum": this._._NewEnum(),
"obj": this
)}
}
Next(ByRef key, ByRef val:="") {
if (ret := this.enum.Next(i, key))
val := this.obj[key]
return ret
}
}
class array
{
__New(args*) {
args.base := this.base
return args
}
stringify(indent:="") {
return JSON.stringify(this, indent)
}
}
}
;}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment