429 lines
13 KiB
Plaintext
429 lines
13 KiB
Plaintext
; --------------------------------------------------------------------------------
|
|
; @Title: Collection of some helper functions
|
|
; @Description:
|
|
; This script is a collection of some helper functions for your
|
|
; daily work with the PRACTICE script language.
|
|
;
|
|
; You can call these functions with
|
|
; DO ~~/demo/practice/lib.cmm <FUNCTION> <ARGUMENTS>
|
|
;
|
|
; @Keywords: PRACTICE
|
|
; @Author: HLG
|
|
; @Copyright: (C) 1989-2019 Lauterbach GmbH, licensed for use with TRACE32(R) only
|
|
; --------------------------------------------------------------------------------
|
|
; $Id: lib.cmm 14936 2019-09-16 11:25:18Z hlohn $
|
|
|
|
|
|
LOCAL &func &arg &result
|
|
ENTRY &func %line &arg
|
|
|
|
ON ERROR GOTO
|
|
(
|
|
LOCAL &ppf
|
|
&ppf=OS.PPF()
|
|
PRINT %ERROR "Sorry, '"+OS.FILE.NAME("&ppf")+"' doesn't know function '&func'"
|
|
STOP
|
|
)
|
|
&func=STRING.UPR("&func")
|
|
GOSUB &func &arg
|
|
ENTRY %LINE &result
|
|
ENDDO &result
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////
|
|
VERSION:
|
|
// Returns the version number of this PRACTICE library
|
|
// and sets global macro &libver, which contains the version number, too.
|
|
// Syntax:
|
|
// DO lib.cmm VERSION
|
|
// Returns:
|
|
// The version number of this file
|
|
// Example:
|
|
// DO ~~/demo/practice/lib.cmm VERSION
|
|
// PRINT "lib.cmm is version " %Decimal &libver "."
|
|
ON ERROR NOTHING
|
|
GLOBAL &libver
|
|
&libver=STRing.CUT(STRing.CUT("$Rev: 14936 $",6),-2)+"."
|
|
RETURN &libver
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////
|
|
OPENNEW:
|
|
// Opens a file just like OPEN but seaches for an unused 'bufferno'
|
|
// Syntax:
|
|
// DO lib.cmm OPENNEW <filename> [<option>]
|
|
// Returns:
|
|
// The file 'bufferno' e.g.: #42
|
|
// Example:
|
|
// LOCAL &logfile
|
|
// DO ~~/demo/practice/lib.cmm OPENNEW ~~~~/log.txt /Append
|
|
// ENTRY &logfile
|
|
// WRITE &logfile "new event!"
|
|
// CLOSE &logfile
|
|
ON ERROR NOTHING
|
|
LOCAL &arg &fn
|
|
ENTRY %line &arg
|
|
|
|
&fn=1
|
|
IF VERSION.BUILD()>31360. // function FILE.EOF exists ? (2011-07-27)
|
|
(
|
|
IF VERSION.BUILD.BASE()>36377. // function FILE.OPEN exists ? (2012-04-22)
|
|
(
|
|
WHILE {FILE.OPEN(&fn)}&&{&fn<120.}
|
|
&fn=&fn+1
|
|
)
|
|
ELSE
|
|
(
|
|
ON ERROR GOTO break
|
|
WHILE &fn<120.
|
|
(
|
|
EVAL FILE.EOF(&fn) // results in error if file number is not open
|
|
&fn=&fn+1
|
|
)
|
|
break:
|
|
)
|
|
)
|
|
ELSE
|
|
(
|
|
&fn=(RANDOM()&0xFF)%100.+20. // take random number between 20 and the maximum of 119.
|
|
PRINT %ERROR "TRACE32 too old to use OPENNEW (build 31361. or higher required)"
|
|
STOP
|
|
)
|
|
&fn="#"+FORMAT.Decimal(0,&fn)
|
|
OPEN &fn &arg
|
|
RETURN &fn
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////
|
|
SIZOFMAU:
|
|
// Detects the width of the mimimal adressable unit (MAU) in the VM memory space (Data.dump VM:0)
|
|
// Syntax:
|
|
// DO lib.cmm SIZOFMAU
|
|
// Returns:
|
|
// Width of one adressable unit in the VM memory space in bytes
|
|
// Example:
|
|
// LOCAL &width
|
|
// DO ~~/demo/practice/lib.cmm SIZOFMAU
|
|
// ENTRY &width
|
|
// PRINT "Width is " %Decimal &width "Bytes"
|
|
ON ERROR NOTHING
|
|
LOCAL &tfile &width &memclass
|
|
|
|
&tfile=OS.TMPFILE()
|
|
ON ERROR GOSUB
|
|
(
|
|
LOCAL &err
|
|
&err=HELP.MESSAGE()
|
|
ON ERROR NOTHING
|
|
IF "&err"=="#emu_errvmnotval" // Error VM not valid ?
|
|
(
|
|
Data.Set VM:0--8 %Byte 0
|
|
Data.SAVE.Binary "&tfile" VM:0--8
|
|
)
|
|
ELSE
|
|
(
|
|
STOP // unexpected error occurred
|
|
)
|
|
RETURN
|
|
)
|
|
Data.SAVE.Binary "&tfile" VM:0--8
|
|
ON ERROR NOTHING
|
|
|
|
Data.Set vm:0 %Byte 0 1 2 3 4 5 6 7 8
|
|
&width=Data.Byte(VM:1)
|
|
|
|
Data.LOAD.Binary "&tfile" VM:0--8
|
|
RM "&tfile"
|
|
|
|
RETURN &width
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////
|
|
FIXNUM:
|
|
// Ensures that all passed macros contain an expression which expands to a number
|
|
// or sets the value to zero otherwise
|
|
// Syntax:
|
|
// DO lib.cmm FIXNUM &arg1 [&arg2] [&arg3] [...&argN]
|
|
// Returns:
|
|
// returns the fixed versions of &arg1 [&arg2] [&arg3] [...&argN]
|
|
// Example:
|
|
// LOCAL &v1 &v2 &v3
|
|
// ENTRY &v1 &v2 &v3
|
|
// DO ~~/demo/practice/lib.cmm FIXNUM &v1 &v2 &v3
|
|
// ENTRY &v1 &v2 &v3
|
|
//
|
|
// PRINT "&v1 &v2 &v3"
|
|
// ENDDO
|
|
ON ERROR NOTHING
|
|
LOCAL &num &rest &val
|
|
ENTRY &num %LINE &rest
|
|
|
|
&val="&num"
|
|
ON ERROR GOSUB
|
|
(
|
|
EVAL 1==1
|
|
RETURN
|
|
)
|
|
EVAL &num // if &num is a string without quotes it will be interpreted as sYmbol, which will probably result in "symbol not found" error
|
|
ON ERROR NOTHING
|
|
IF (EVAL.TYPE()&{0x3E})==0 // bin,hex,dec,ascii or float ?
|
|
(
|
|
&val=0
|
|
)
|
|
IF "&rest"!=""
|
|
(
|
|
LOCAL &tmp
|
|
GOSUB FIXNUM &rest
|
|
ENTRY %LINE &tmp
|
|
&val="&val &tmp"
|
|
)
|
|
RETURN &val
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////
|
|
T32BUILDNUM:
|
|
// Sets two GLOBAL variables &t32_Build &t32_BuildBase
|
|
// which get set to VERSION.BUILD() and VERSION.BUILD.BASE() if possible
|
|
// Syntax:
|
|
// DO lib.cmm T32BUILDNUM
|
|
// Returns:
|
|
// none
|
|
// Example:
|
|
// DO ~~/demo/practice/lib.cmm T32BUILDNUM
|
|
// IF &t32_Build==&t32_BuildBase
|
|
// PRINT "This is TRACE32 interim build " %Decimal &t32_Build "."
|
|
// ELSE
|
|
// PRINT "This is TRACE32 release build " %Decimal &t32_BuildBase "--" %Decimal &t32_Build "."
|
|
ON ERROR NOTHING
|
|
GLOBAL &t32_Build &t32_BuildBase
|
|
&t32_Build=VERSION.BUILD()
|
|
&t32_BuildBase=VERSION.BUILD()
|
|
IF VERSION.BUILD()>15282. // (2008-09-26)
|
|
&t32_BuildBase=VERSION.BUILD.BASE()
|
|
RETURN
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////
|
|
ENTERDLG:
|
|
// Opens a dialog box which asks a user for some input data.
|
|
// This should be an alternative to the ENTER command
|
|
// Syntax:
|
|
// DO lib.cmm ENTERDLG "<question>" ["<window-header>"]
|
|
// Returns:
|
|
// The input data (without quotes!)
|
|
// Example:
|
|
// LOCAL &name
|
|
// DO ~~/demo/practice/lib.cmm ENTERDLG "What's your name?" "Identification"
|
|
// ENTRY %LINE &name
|
|
// PRINT "Hello &name!"
|
|
ON ERROR NOTHING
|
|
LOCAL &question &header
|
|
ENTRY &question &header
|
|
|
|
&question=&question
|
|
&header=&header
|
|
IF "&header"==""
|
|
&header="Input"
|
|
|
|
LOCAL &name
|
|
DIALOG
|
|
(&+
|
|
HEADER "&header"
|
|
POS 0.5 0.5 20.5 1.
|
|
TEXT "&question"
|
|
POS 0.5 2. 20. 1.
|
|
ENTERDLG_input: DEFEDIT "" ""
|
|
POS 6.5 3.5 8. 1.
|
|
DEFBUTTON "OK" "CONTinue"
|
|
CLOSE ""
|
|
)
|
|
STOP
|
|
&name=DIALOG.STRING(ENTERDLG_input)
|
|
DIALOG.END
|
|
RETURN &name
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////
|
|
OPENURL:
|
|
// Opens a web browser to display the given URL (optional with your favorite browser)
|
|
// Works only on Windows!
|
|
// In contrast to a simple "OS.Command start <URL>" you can also pass GET-parameters
|
|
// or open local URL which is not of type *.htm/*.html
|
|
// Syntax:
|
|
// DO lib.cmm OPENURL "<URL>" [firefox|opera|chrome|iexplore]
|
|
// Example:
|
|
// DO ~~/demo/practice/lib.cmm OPENURL "example.xml?mode=hll"
|
|
ON ERROR NOTHING
|
|
LOCAL &url &browser
|
|
ENTRY &url &browser
|
|
|
|
IF (VERSION.BUILD()>=112151.)&&("&browser"==""||OS.VERSION(0)>=0x10)
|
|
(
|
|
IF (STRing.CHAR("&url",0)=='"')&&(STRing.CHAR("&url",STRING.LENgth("&url")-1)=='"')
|
|
&url=&url
|
|
OS.OPEN "&url"
|
|
RETURN
|
|
)
|
|
|
|
IF OS.VERSION(0)>=0x10 // not Windows
|
|
RETURN
|
|
|
|
IF STRing.CHAR("&url",0)=='"'
|
|
&url=&url
|
|
IF STRing.SCAN("&url","://",0)<0 ;no URL scheme ?
|
|
(
|
|
IF STRing.SCAN("&url","~~~/",0)==0
|
|
&url=OS.PTD()+"/"+STRing.CUT("&url",4)
|
|
IF STRing.SCAN("&url","~~/",0)==0
|
|
&url=OS.PSD()+"/"+STRing.CUT("&url",3)
|
|
IF STRing.SCAN("&url","~/",0)==0
|
|
&url=OS.PHD()+"/"+STRing.CUT("&url",2)
|
|
IF STRing.CHAR("&url",1)!=':'
|
|
&url=OS.PWD()+"/&url"
|
|
&url= "file:///&url"
|
|
)
|
|
IF VERSION.BUILD()>39758.
|
|
(
|
|
&url=STRing.Replace("&url","\","/",0)
|
|
&url=STRing.Replace("&url","%","%25",0)
|
|
&url=STRing.Replace("&url","+","%2B",0)
|
|
&url=STRing.Replace("&url"," ","%20",0)
|
|
)
|
|
|
|
LOCAL &prog1 &prog2 &rapp &lapp
|
|
&prog1=OS.ENV(PROGRAMFILES)
|
|
&prog2="C:/Program Files (x86)"
|
|
&lapp=OS.ENV(LOCALAPPDATA)
|
|
IF "&localappdata"=="" ; Win XP ?
|
|
(
|
|
&rapp=OS.ENV(APPDATA)
|
|
&localappdata="&rapp/../Local Settings/Application Data"
|
|
IF OS.DIR("&rapp/../Lokale Einstellungen/Anwendungsdaten")
|
|
&localappdata="&rapp/../Lokale Einstellungen/Anwendungsdaten"
|
|
)
|
|
LOCAL &haveFirefox &haveOpera &haveChrome &havePresto
|
|
&haveFirefox=OS.FILE("&prog1/Mozilla Firefox/firefox.exe")||OS.FILE("&prog2/Mozilla Firefox/firefox.exe")
|
|
&haveChrome=OS.FILE("&lapp/Google/Chrome/Application/chrome.exe")||OS.FILE("&prog1/Google/Chrome/Application/chrome.exe")||OS.FILE("&prog2/Google/Chrome/Application/chrome.exe")
|
|
&havePresto=OS.FILE("&prog1/Opera/opera.exe")||OS.FILE("&prog2/Opera/opera.exe") // Opera 12.17 and older (with Presto rendering engine)
|
|
&haveOpera=OS.FILE("&prog1/Opera/launcher.exe")||OS.FILE("&prog2/Opera/launcher.exe")
|
|
|
|
&browser=STRing.LWR("&browser")
|
|
IF !(&haveFirefox||&haveChrome||&haveOpera)&&("&browser"!="iexplore")
|
|
&browser=""
|
|
|
|
IF (&haveOpera)&&(("&browser"=="opera")||("&browser"=="")) // Opera >= 15
|
|
&browser="opera --allow-file-access-from-files"
|
|
ELSE IF (&havePresto)&&(("&browser"=="opera")||("&browser"=="")) // Opera <= 12.17
|
|
&browser="opera"
|
|
ELSE IF (&haveChrome)&&(("&browser"=="chrome")||("&browser"==""))
|
|
&browser="chrome --allow-file-access-from-files"
|
|
ELSE IF (&haveFirefox)&&(("&browser"=="firefox")||("&browser"==""))
|
|
&browser="firefox"
|
|
ELSE
|
|
&browser="iexplore"
|
|
|
|
OS.Command start &browser "&url"
|
|
RETURN
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////
|
|
CREATE_ENUM:
|
|
// Helps to create MACRO definitions of enumeration lists easily
|
|
// If in your target application, the names for values of variables are not defined
|
|
// with enumerations (enum) but with preprocessor macros, you won't see
|
|
// the names during debugging since preprocessor macros are not part of the
|
|
// debug information of your ELF file
|
|
// With this routine you can easily add the missing definitions.
|
|
// Syntax:
|
|
// DO lib.cmm CREATE_ENUM <enumlist> [variable1] [variable2] [...variableN]
|
|
// <enumlist> must be a string containing a comma separated list of key-value pairs, which
|
|
// describe the enumeration list
|
|
// Returns:
|
|
// void
|
|
// Example:
|
|
// LOCAL &sailors
|
|
// &sailors="SAILOR_NIX=0,SAILOR_JAN=1,SAILOR_HEIN=2,SAILOR_KLAAS=300,SAILOR_PIT=0x400"
|
|
// DO ~~/demo/practice/lib.cmm CREATE_ENUM "&sailors" mcount mstatic1
|
|
// Var.AddWatch mcount mstatic1
|
|
// Var.Set mcount=SAILOR_KLAAS
|
|
// DO ~~/demo/practice/lib.cmm CREATE_ENUM "JOHN,PAUL,GEORGE,RINGO"
|
|
// DO ~~/demo/practice/lib.cmm CREATE_ENUM "ONE,TWO,THREE,FIFE=5,SIX"
|
|
ON ERROR NOTHING
|
|
LOCAL &enumlist &variables &varlist &x3 &last
|
|
ENTRY &enumlist %line &variables
|
|
IF STRing.CHAR("&enumlist",0)=='"'
|
|
&enumlist=&enumlist
|
|
&last=-1.
|
|
&varlist="&variables"
|
|
WHILE "&varlist"!=""
|
|
(
|
|
&x3=STRing.SCAN("&varlist"," ",0)
|
|
IF &x3<0
|
|
&x3=STRing.LENgth("&varlist")
|
|
&var=STRing.MID("&varlist",0,&x3)
|
|
&varlist=STRing.CUT("&varlist",&x3+1)
|
|
sYmbol.AddInfo.Delete &var
|
|
)
|
|
WHILE "&enumlist"!=""
|
|
(
|
|
LOCAL &x1 &x2 &key &val &var
|
|
&x1=STRing.SCAN("&enumlist","=",0)
|
|
&x2=STRing.SCAN("&enumlist",",",0)
|
|
IF &x2<0
|
|
&x2=STRing.LENgth("&enumlist")
|
|
IF (&x1>&x2)||(&x1<0)
|
|
&x1=&x2
|
|
&key=STRing.TRIM(STRing.MID("&enumlist",0,&x1))
|
|
&val=STRing.TRIM(STRing.MID("&enumlist",&x1+1,&x2-&x1-1))
|
|
IF "&val"==""
|
|
&val=FORMAT.Decimal(0,&last+1)
|
|
&enumlist=STRing.CUT("&enumlist",&x2+1)
|
|
sYmbol.CREATE.MACRO &key &val
|
|
|
|
if STRing.MID(STRing.LoWeR("&val"),0,2)!="0x"
|
|
&val="0x"+FORMAT.HEX(0,&val.)
|
|
&varlist="&variables"
|
|
WHILE "&varlist"!=""
|
|
(
|
|
&x3=STRing.SCAN("&varlist"," ",0)
|
|
if &x3<0
|
|
&x3=STRing.LENgth("&varlist")
|
|
&var=STRing.MID("&varlist",0,&x3)
|
|
&varlist=STRing.CUT("&varlist",&x3+1)
|
|
sYmbol.AddInfo.Var &var ENUM &val "&key"
|
|
)
|
|
&last=&val
|
|
)
|
|
sYmbol.CREATE.Done
|
|
RETURN
|
|
////////////////////////////////////////////////////////////////////////////////////////////
|
|
INIT_ARRAY:
|
|
// Helps to initialize HLL arrays easily
|
|
// Syntax:
|
|
// DO lib.cmm INIT_ARRAY <name-of-array> <init-values>
|
|
// <enumlist> must are a comma separated list of values which should be
|
|
// assigned to the array
|
|
// Returns:
|
|
// void
|
|
// Examples:
|
|
// Var.NEWLOCAL int[6] \arr1 ; create new "artificial" array called \arr1
|
|
// DO ~~/demo/practice/lib.cmm INIT_ARRAY \arr1 0,1,2, 3, 4,5 ; initialize array
|
|
// Var.View %STanDard %Decimal %Index %Open.1 \arr1 ; show result
|
|
//
|
|
// Var.NEWLOCAL char[8][10] \arr2
|
|
// DO ~~/demo/practice/lib.cmm INIT_ARRAY \arr2 "no one","Jan","Hein","Klaas", "Pit"
|
|
// Var.View %STanDard %String %Index %Open.1 \arr2
|
|
ON ERROR NOTHING
|
|
LOCAL &var &args &val &x &idx
|
|
ENTRY &var %LINE &args
|
|
&idx=0
|
|
&x=STRing.SCAN("&args",",",0)
|
|
WHILE &x>0
|
|
(
|
|
&val=STRing.TRIM(STRing.MID("&args",0,&x))
|
|
&args=STRing.CUT("&args",&x+1)
|
|
Var.set (&var)[&idx]=&val
|
|
&idx=&idx+1
|
|
&x=STRing.SCAN("&args",",",0)
|
|
)
|
|
&val=STRing.TRIM("&args")
|
|
IF "&val"!=""
|
|
Var.set (&var)[&idx]=&val
|
|
RETURN
|
|
////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|