Sign in to follow this  
Followers 0
LegitStack

Manual and Convoluted Plugin System

1 post in this topic

#1 ·  Posted (edited)

I wanted some kind of a plugin system for a project I'm working on.

So naturally I decided to write my own from scratch. Stupid.

I actually know of better ways to do this such as...

...But I thought, since I spent several days on this, and it does technically work for my purposes I may as well post it up and maybe some part of it might help someone someday. 

 

;#NoTrayIcon
#include <Math.au3>
#include <File.au3>
#include <Misc.au3>
#include <Crypt.au3>
#include <Array.au3>
#include <FileConstants.au3>
#include <MsgboxConstants.au3>
#include <GUIConstantsEx.au3>
#include <GuiListView.au3>
#Include <GDIPlus.au3>

Global $procs[256][256]
Global $loops[256][256]
Global $v[65000]
Global $a[256][256]
Global $hotkey[100]
Global $hotproc[100]

Func HotkeyPlugin()
  for $hki = 0 to ubound($hotkey)-1
    if @HotKeyPressed == $hotkey[$hki] then
      ExecuteProc($hotproc[$hki])
    endif
  next
EndFunc


Func ImportPlugin()
  local $path = "c:\plugin.au3p"
  local $file = FileOpen($path, $FO_READ)
  local $read = FileRead($file)
  FileClose($file)
  local $nread = Stringsplit($read, @CRLF, 2)
  if Stringleft($nread[0],1) == "'" then
    $nread = stringtrimleft($nread[0],1)
    $nread = stringtrimright($nread,1)
  Else
    $nread = $nread[0]
  endif
  $read = BinaryToString(_Crypt_DecryptData($nread, "a", $CALG_AES_256))
  $read = Stringsplit($read, @CRLF, 2)
  AnalyzePlugin($read)
EndFunc


Func AnalyzePlugin($read)
  local $procnum = 0
  local $loopnum = -1
  local $temp
  local $temp1
  local $ln = 0
  local $lnloop[256]
  local $embedded = -1
  local $hki = 0


  for $r in $read
    $temp = Stringsplit($r, " ", 2)
    $temp1= stringleft($r, 4)
    ;msgbox(64,"temp1",$temp1)
    if $temp1 == "proc" Or $temp1 == "Proc" then
      $procnum = $temp[1]
      $embedded = -1
      $ln = 0
    elseif $temp1 == "endp" Or $temp1 == "Endp" then
      ;msgbox(64,"r",$r)
      $procs[$procnum][$ln] = $r
      $procnum = ""
      $embedded = -1
    elseif $temp1 == "hkps" Or $temp1 == "Hkps" then ;hot key pressed set
      $hotkey[$hki] = $temp[1]
      $hotproc[$hki] = $temp[2]
      $hki = $hki + 1
      HotKeySet($temp[1],"HotkeyPlugin")
    elseif StringStripWS($r, $STR_STRIPLEADING + $STR_STRIPTRAILING + $STR_STRIPSPACES) == "loop" Or StringStripWS($r, $STR_STRIPLEADING + $STR_STRIPTRAILING + $STR_STRIPSPACES) == "Loop" then
      $oldloopnum = $loopnum
      $loopnum = $loopnum + 1
      $embedded = $embedded + 1
      $lnloop[$embedded] = 0
      if $embedded == 0 then
        $procs[$procnum][$ln] = "loop " & $loopnum
        $ln = $ln + 1
      else
        ;msgbox(64,"loop found," & $loopnum, $embedded & " " & $lnloop[$embedded])
        $loops[$oldloopnum][$lnloop[$embedded-1]] = "loop " & $loopnum
        $lnloop[$embedded-1] = $lnloop[$embedded-1] + 1
        ;_arraydisplay($loops)
      endif
    elseif StringStripWS($r, $STR_STRIPLEADING + $STR_STRIPTRAILING + $STR_STRIPSPACES) == "endl" Or StringStripWS($r, $STR_STRIPLEADING + $STR_STRIPTRAILING + $STR_STRIPSPACES) == "Endl" then
      $loops[$loopnum][$lnloop[$embedded]] = StringStripWS($r, $STR_STRIPLEADING + $STR_STRIPTRAILING + $STR_STRIPSPACES)
      $embedded = $embedded - 1
      if $embedded > -1 then
        $loopnum = $loopnum - 1
      endif
    else ; regular code
      if $procnum <> "" then
        if $r <> "" then
          if $embedded == -1 then
            $procs[$procnum][$ln] = StringStripWS($r, $STR_STRIPLEADING + $STR_STRIPTRAILING + $STR_STRIPSPACES)
            $ln = $ln + 1
          else
            $loops[$loopnum][$lnloop[$embedded]] = StringStripWS($r, $STR_STRIPLEADING + $STR_STRIPTRAILING + $STR_STRIPSPACES)
            $lnloop[$embedded] = $lnloop[$embedded] + 1
          endif
        endif
      endif
    endif
  next
  ;_arraydisplay($procs)
  ;_arraydisplay($loops)

  ExecuteProc(0)
EndFunc


Func ExecuteProc($number, $arg1 = "", $arg2 = "")
  local $temp
  local $temp1
  local $return
  local $ift = ""
  local $embeddedif = 0
  local $command = ""

  for $pcount = 0 to 255
    ;put loops in the right places!
    $read = $procs[$number][$pcount]

    ;msgbox(64,"readsays "& $pcount,$read)
    $r = Stringsplit($read, " ", 2)
    $command = stringleft($read, 4)
    ExecuteCode($read, $r, $arg1, $arg2, $temp, $temp1, $return, $ift, $embeddedif, $command)
  next
  return $return
EndFunc



Func ExecuteLoop($number, Byref $arg1, Byref $arg2, Byref $temp, Byref $temp1, Byref $return, Byref $command)
  local $embeddedif = 0
  local $ift = ""
  ;_arraydisplay($procs)
  while 1
    For $pcount = 0 to 255
      ;put loops in the right places!
      $read = $loops[$number][$pcount]
      $r = Stringsplit($read, " ", 2)
      $command = stringleft($read, 4)
      ;msgbox(64,"readsays " & $pcount,$read & " " & $embeddedif & " " & $ift)
      $ret = ExecuteCode($read, $r, $arg1, $arg2, $temp, $temp1, $return, $ift, 0, $command)
      if $ret == 300 then
        $pcount = 300
      elseif $ret == "bklp" then
        exitloop 2
      endif
    next
  wend

EndFunc



Func ExecuteCode(Byref $read, Byref $r, Byref $arg1, Byref $arg2, Byref $temp, Byref $temp1, Byref $return, Byref $ift, Byref $embeddedif, Byref $command)
  local $tempread1
  local $tempread2
  local $tempread3
  local $execute1 = false
  local $execute2 = false
  local $execute3 = false

  if ($command == "goto" Or $command == "Goto") And ($ift == "" Or stringright($ift, 1) == "t") then
    if StringLeft($r[1], 1) == "'" or StringLeft($r[1], 1) == '"'  then ; 1 is text
      $tempread1 = StringTrimLeft(StringTrimRight($r[1], 1), 1)
    elseif StringIsDigit(Stringleft($r[1], 1)) == 1 then ; 1 is number
      $tempread1 = $r[1]
    else ; its code so we're going to execute it.
      $execute1 = true
    endif
    if Ubound($r) == 4 then
      if StringLeft($r[2], 1) == "'" or StringLeft($r[2], 1) == '"'  then ; 2 is text
        $tempread2 = StringTrimLeft(StringTrimRight($r[2], 1), 1)
      elseif StringIsDigit(Stringleft($r[2], 1)) == 1 then ; 2 is number
        $tempread2 = $r[2]
      else ; its code so we're going to execute it.
        $execute2 = true
      endif

      if StringLeft($r[3], 1) == "'" or StringLeft($r[3], 1) == '"'  then ; 3 is text
        $tempread3 = StringTrimLeft(StringTrimRight($r[3], 1), 1)
      elseif StringIsDigit(Stringleft($r[3], 1)) == 1 then ; 3 is number
        $tempread3 = $r[3]
      else ; its code so we're going to execute it.
        $execute3 = true
      endif

      if $execute1 And $execute2 And $execute3 then
        $return = ExecuteProc(execute($tempread1), execute($tempread2), execute($tempread3))
      elseif $execute1 And $execute2 then
        $return = ExecuteProc(execute($tempread1), execute($tempread2),         $tempread3 )
      elseif $execute1 And $execute3 then
        $return = ExecuteProc(execute($tempread1),         $tempread2 , execute($tempread3))
      elseif $execute2 And $execute3 then
        $return = ExecuteProc(        $tempread1 , execute($tempread2), execute($tempread3))
      elseif $execute1 then
        $return = ExecuteProc(execute($tempread1),         $tempread2 ,         $tempread3 )
      elseif $execute2 then
        $return = ExecuteProc(        $tempread1 , execute($tempread2),         $tempread3 )
      elseif $execute3 then
        $return = ExecuteProc(        $tempread1 ,         $tempread2 , execute($tempread3))
      else
        $return = ExecuteProc(        $tempread1 ,         $tempread2 ,         $tempread3 )
      endif
    elseif Ubound($r) == 3 then
      if StringLeft($r[2], 1) == "'" or StringLeft($r[2], 1) == '"'  then ; 2 is text
        $tempread2 = StringTrimLeft(StringTrimRight($r[2], 1), 1)
      elseif StringIsDigit(Stringleft($r[2], 1)) == 1 then ; 2 is number
        $tempread2 = $r[2]
      else ; its code so we're going to execute it.
        $execute2 = true
      endif

      elseif $execute1 And $execute2 then
        $return = ExecuteProc(execute($tempread1), execute($tempread2))
      elseif $execute1 then
        $return = ExecuteProc(execute($tempread1),         $tempread2 )
      elseif $execute2 then
        $return = ExecuteProc(        $tempread1 , execute($tempread2))
      else
        $return = ExecuteProc(        $tempread1 ,         $tempread2 )
      endif
    elseif Ubound($r) == 2 then
      if $execute1 then
        $return = ExecuteProc(execute($tempread1))
      else
        $return = ExecuteProc(        $tempread1 )
      endif
    endif
  elseif ($command == "set " Or $command == "Set ") And ($ift == "" Or stringright($ift, 1) == "t") then
    if UBound($r) == 3 then
      if StringLeft($r[1], 1) == "'" or StringLeft($r[1], 1) == '"'  then ; 1 is text
        $tempread1 = StringTrimLeft(StringTrimRight($r[1], 1), 1)
      elseif StringIsDigit(Stringleft($r[1], 1)) == 1 then ; 1 is number
        $tempread1 = $r[1]
      else ; its code so we're going to execute it.
        $execute1 = true
      endif

      if StringLeft($r[2], 1) == "'" or StringLeft($r[2], 1) == '"'  then ; 2 is text
        $tempread2 = StringTrimLeft(StringTrimRight($r[2], 1), 1)
      elseif StringIsDigit(Stringleft($r[2], 1)) == 1 then ; 2 is number
        $tempread2 = $r[2]
      else ; its code so we're going to execute it.
        $execute2 = true
      endif

      if $execute1 And $execute2 then
        $v[execute($tempread1)] = execute($tempread2)
      elseif $execute1 then
        $v[execute($tempread1)] = $tempread2
      elseif $execute2 then
        $v[$tempread1] = execute($tempread2)
      else
        $v[$tempread1] = $tempread2
      endif
    elseif ubound($r) > 3 then
      for $temp = 2 to ubound($r)-1
        $a[$r[1]][$temp-2] = $r[$temp]
      next
    endif
  elseif ($command == "loop" Or $command == "Loop") And ($ift == "" Or stringright($ift, 1) == "t") then
    ExecuteLoop($r[1], $arg1, $arg2, $temp, $temp1, $return, $command)
  elseif ($command == "endl" or $command == "Endl") And ($ift == "" Or stringright($ift, 1) == "t") then
    return 300
  elseif ($command == "bklp" or $command == "Bklp") And ($ift == "" Or stringright($ift, 1) == "t") then
    ;$ift = ""
    return "bklp"
  elseif $command == "ift " Or $command == "Ift " then
    if $ift == "" Or stringright($ift, 1) == "t" then
      if execute(stringtrimleft($read, 4)) then
        $ift = $ift & "t"
        $embeddedif = $embeddedif + 1
      else
        $ift = $ift & "f"
      endif
    endif
  elseif $command == "elif" Or $command == "Elif" then
    if $ift == "f" Or stringright($ift, 2) == "tf" then
      if execute(stringtrimleft($read, 4)) then
        $ift = stringtrimright($ift, 1)
        $ift = $ift & "t"
        $embeddedif = $embeddedif + 1
      else
        $ift = stringtrimright($ift, 1)
        $ift = $ift & "f"
      endif
    endif
  elseif $command == "else" Or $command == "Else" then
    if $ift == "f" Or stringright($ift, 2) == "tf" then
      $ift = stringtrimright($ift, 1)
      $ift = $ift & "t"
      $embeddedif = $embeddedif + 1
    else
      $ift = stringtrimright($ift, 1)
      $ift = $ift & "f"
    endif
  elseif ($command == "endi" Or $command == "Endi") then
    if $ift == "" Or stringright($ift, 1) == "t" then
      $ift = stringtrimright($ift, 1)
      $embeddedif = $embeddedif - 1
    elseif stringright($ift, 1) == "f" then
      $ift = stringtrimright($ift, 1)
      $embeddedif = $embeddedif - 1
    endif
  elseif ($command == "endp" Or $command == "Endp") And ($ift == "" Or stringright($ift, 1) == "t")then
    if Ubound($r) == 2 then
      if stringleft($r[1], 1) == "$" then
        $return = ExecuteProc(execute($r[1]))
      else
        $return = $r[1]
      endif
    else
      $return = ""
    endif
    $pcount =300
  elseif  ($read == "exit" Or $read == "Exit") And ($ift == "" Or stringright($ift, 1) == "t") then
    Exit
  else
    if  $ift == "" Or stringright($ift, 1) == "t" then
      Execute($read)
    endif
  endif

EndFunc

ImportPlugin()














;METHOD 3 (special Raw Execute)
;at least 3 arrays:
  ;1. proc code, arguments of procs = 2d array p[]
  ;2. variables (public)  g[]
  ;3. variables (private) v[]

;this script loads the entire plugin.
;as it loads it it fills up the arrays.
;no returns, args
;everything is separated by spaces
;encoding of Functions:
  ;proc 0          - tells you which i to put it in.
    ;args 1 2     - array 1 1-99
    ;              - array 1 first,
  ;endp            - none
;encoding calling functions
  ;goto 2          - start loading each line from p[2] into execution
;encoding of variables:
  ;set 1 [code]       - v[1] = Execute($restofline)
  ;set 1 puts 2       - v[1] = v[2]
;we may use set as setv for arrays and let them use assign for regular variables
;so first we analyze it to separate it out,
;then the very last line of the code should be only number
;thats when we switch over to run mode
;and starting with the numbered proc we being to execute each line of code.

;limitations:
  ; we could make arrays of 1000 or something like a1-10
  ; no includes
  ; no switches or anything else other than If statement.
  ; clunky. but basically func becomes proc args call becomes goto and local becomes set, while becomes loop, if becomes ift

;how to prepare plugins
  ;1. create a plugin script
  ;2. encrypt the data, replace code
  ;3. encryptfile, put in the plugins folder in scriptdir.

;plugin requirements:
  ;1. cannot have a function called "ImportPlugin"
  ;2. cannot have a function called "ExecutePlugin"
  ;3. cannot have a variable called "$__R__"
  ;4. cannot have a variable called "$__READ__"
  ;5. you must load everything into Memory before you being to execute.
  ;6. Your plugin cannot have more than 30k lines of code.
  ;7. cannot #include anything.
  ;8. cannot assign variables the normal way. you must use Assign("message", "world") (Assign, Call, Eval)
  ;9. convention suggests you use RMPlugin_ at the beginning of all function and variables in order to avoid duplicates because all the includes have to be

That's the actual script that acts as the plugin-executor.

I basically had to recreate flow-control inside the context of the autoit flow-control. Which means I had to make a sudo-language. 

Hobby: masochist.  

Here's an example script I created to show how it works. 

 

;how to set a hotkey key procnumber - must be first thing you do.
hkps {END} 3

;proc 0 is the natural entry point to the program.
;If you want it to constantly run, and wait for user hotkey then make proc 0 look like this:
;proc 0
;  loop
;  endl
;endp
;here's a sudo-function. only numbers (as the name) allowed. No need to specify arguments
proc 0
  ; this how you make comment
  ;

  ; make a call:
  goto 1

  ; reference a variable
  msgbox(64,"01","hello " & $v[1] )

  ; reference elements in an array
  msgbox(64,"01","hello " & $a[1][1] & $a[1][2] & $a[1][3] )

  goto 4

;end sudo function
endp

proc 1

  ; make a variable - use number as variable name
  set 1 "world"
  msgbox(64,"1","hello " & $v[1])

  ; variable substitution available on name or value.
  set 9 1
  set $v[9] "world!"
  msgbox(64,"1","hello " & $v[1])

  ; make an array - substitution not not allowed when creating these, its litteral
  set 1 "a" b "c" d "e" f

  ; make some regular autoit code
  msgbox(64,"1","hello world")

  ; 2 max arguments allowed. arguments only allow single words or numbers or variables
  goto 2 hello $v[1]

  ; how to access the return
  msgbox(64,"1-returned",$return)
Endp

proc 2 args are ignored if you write them in here.

  ; here's how to use args, 1 or 2 args allowed
  msgbox(64, "2", $arg1 & " " & $arg2)

  ; if you want to return a value simply add it onto the end of this line
Endp goodbyeworld


proc 3 called from hotkey

  msgbox(64, "3", "called from hotkey")

Endp

code outside procs are ignored, like comments


proc 4 if statements are ift statments NO then

  ift $v[1] == "hello"
    msgbox(64,"4","this is false and wont be executed!")
  elif $v[1] == "world"
    msgbox(64,"4","hello ift statement! this is elif")
  endi

  ift $v[1] == "goodbye"
    msgbox(64,"4","this is false and wont be executed!")
  else
    msgbox(64,"4","Hello else statement!")
  endi

  msgbox(64,"4","This code is not in an if statement.")

  set 1 0

  goto 5

endp


proc 5 for small loops recursion should work fine

  ift $v[1] == 3
    msgbox(64,"5","done with loop! please press the END key after you press ok. " & $v[1])

    ;wait so we can test the hotkey command
    sleep(5000)

    goto 6
  else
    msgbox(64,"5",$v[1])
    set 1 $v[1]+1
    goto 5
  endi

endp



proc 6 but for large loops or embedded loops "loop" might work best.

  set 2 0

  loop
    set 2 $v[2]+1
    tooltip($v[2])
    sleep(1000)
    ift $v[2] >= 2
      bklp
    endi
  endl

  set 3 0
  set 4 0

  loop
    loop
      set 3 $v[3]+1
      tooltip($v[3])
      sleep(1000)
      ift $v[3] >= 2
        bklp
      endi
    endl
    set 4 $v[4]+1
    tooltip($v[4])
    sleep(1000)
    ift $v[4] >= 2
      bklp
    endi
  endl

  msgbox(64,"6","This concludes our tour of the au3p language!")

endp

 

Edited by LegitStack

Share this post


Link to post
Share on other sites



Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0