#102769 - 2003-07-12 12:18 AM
Kix Script Methodology
|
Grasshopper75
Getting the hang of it
Registered: 2002-01-15
Posts: 99
Loc: Melbourne, Australia
|
As I still consider myself a newbie to Kix I have become interested in finding out better ways to write my scripts and the ways that others write their scripts.
I have always structured my scripts so that they are easy to read, add comments where I feel they are necessary and have now broken down my script into several sub-functions/scripts. I also use meaningful variables etc.
I am just curious as to other things I can do to compact my scripts and write cleaner and faster scripts.
Any pointers ?
Cheers, Grasshopper75
|
Top
|
|
|
|
#102774 - 2003-07-11 02:25 PM
Re: Kix Script Methodology
|
Richard H.
Administrator
Registered: 2000-01-24
Posts: 4946
Loc: Leatherhead, Surrey, UK
|
quote: error checking is always one of the more overlooked and/or bloated scripting bits
Nah, the thing that causes most bloat in every language I have ever coded in is validating user input. You will get every response imaginable, except the one that you have asked for.
You're right of course Shawn, many of the postings in the starters and script forums would not be needed if the authors had bothered to check the return or error values after a file open, get object etc.
Grasshopper, It sounds like you've done all the right things.
KiXtart scripts are now tokenised internally so things like comments, multiple line spacing and long variable names which were once an issue because they cause script parsing to take longer are no longer so important.
External files which comprise function libraries are also evaluated once (providing you call them once ), so their overhead is low.
In terms of speed, you are more likely to find improvements by studying your scripts and finding different ways of doing things. The Golf challenges frequently throw up ways of achieving the task which not only reduce character counts, but more interestingly involve less processes.
Imaginative use of KiXtart intrinsic functions are often far faster than trying to code the same functionality, especially if it means that a loop can be avoided. AScan(), Split() and Join() are relatively new functions which are having a huge impact on the way scripts are written.
As a final word, I suggest that in a support environment you should err on the side of maintainability over speed. Speed is rarely an issue, but getting a 'phone call at 2 AM because the on shift personnel don't understand some arcane bit of your script usually is.
|
Top
|
|
|
|
#102775 - 2003-07-11 03:02 PM
Re: Kix Script Methodology
|
Shawn
Administrator
Registered: 1999-08-13
Posts: 8611
|
quote:
AScan(), Split() and Join() are relatively new functions which are having a huge impact on the way scripts are written.
lol, as Lonkero would say:
quote:
$kix2htm=$o+@crlf+join(split(join(split(join (split(join(split(join(split(join(split(join (split(join(split(join$f,@crlf),$1),"&"),$2),"<<b> </b>"),$3),">"),$4)," "),$5), " "),"oncluck="),"oncluck<b>< /b>="),"http://"),"<span>http://< /span>"),"www"),"<span>www</span>") +$oe,$e,$g,$h,$j
As I would say:
quote:
Split, Join, Split, Join, make up your mind already !
-Shawn [ 11. July 2003, 15:05: Message edited by: Shawn ]
|
Top
|
|
|
|
#102777 - 2003-07-11 03:08 PM
Re: Kix Script Methodology
|
Shawn
Administrator
Registered: 1999-08-13
Posts: 8611
|
wow, Les, your good! I did that to get past the HTML filters in the forum ... didn't think anyone would spot those was going to use the infamous OnLick but had thought we had better not "go there" [ 11. July 2003, 15:10: Message edited by: Shawn ]
|
Top
|
|
|
|
#102779 - 2003-07-11 03:14 PM
Re: Kix Script Methodology
|
Shawn
Administrator
Registered: 1999-08-13
Posts: 8611
|
btw Richard, my point was to not mock your statement, but to underline my total agreement with it. If anything, I think you understated the impact of these functions
|
Top
|
|
|
|
#102781 - 2003-07-11 03:38 PM
Re: Kix Script Methodology
|
Allen
KiX Supporter
Registered: 2003-04-19
Posts: 4548
Loc: USA
|
Onlick() and Oncluck... having trouble finding these in the manual...
Function Onlick() Open(Split(Join(Split(Join(SetFocus(Split(Join(Split(Join(RedirectOutput(LogEvent(Sleep)))))))))))) End Onlick
In terms of entertainment value, the past few days have been hysterical...
|
Top
|
|
|
|
#102783 - 2003-07-11 05:18 PM
Re: Kix Script Methodology
|
Glenn Barnas
KiX Supporter
Registered: 2003-01-28
Posts: 4396
Loc: New Jersey
|
Try this to "generate" your kix scripts with UDFs.
1. Place the script below into an accessible location as "kgen.kix".
2. Put your UDFs into individual files in a library folder somewhere. Define this location in your environment as KixIncludePath.
(FWIW - I use .KXF for internally written UDFs, and .UDF for externally written UDFs. Makes it easier to submit the external UDFs for security reviews)
3. Define a folder for your project. Your main kix script should have a .TXT extension. (I chose that so I'd have one less association, and couldn't run an incomplete script.) Let's assume your project is "test", so call your main script "test.txt". Also place into this folder any UDF files that are specific to this project.
4. Run "kgen test" in the project folder. The main project file will be parsed, all .KXF and .UDF files in the project folder will be included, and all dependent UDFs in the KixIncludePath will be included as well. The script performs recursive dependency checking.
I've created a document from the header of all the UDFs, sort of a "man page". This way, I can reference the available UDFs in any script and not worry about loading them. Also, by including them at "gen-time", only the required UDFs are included, and I don't have to worry about distributing the UDFs themselves.
Here's the BAT file I use to call the script, code:
@kix32.exe C:\usr\local\bin\kgen.kix $A1=%1 $A2=%2
and the script itself: code:
;; kgen - generate a kix script, automatically locating and including required UDFs ;; Glenn Barnas - FRIT/EROC (gbarnas@yahoo.com) ;; ;; Version 1.1 - May 21, 2000 ;; ;; Usage: kgen project_name ;; Locates all UDF files in the current and library folder & identifies actual ;; udf name, creating a function to file map. Once this is complete, the project ;; file is scanned for any of these functions, and those functions are then scanned ;; for other UDFs. The resulting list of UDF names and files is then sorted and ;; duplicate filenames are removed. This final list of required UDFs is then combined ;; with the source project file in a new output file. Note that the scanning of UDFs ;; for other UDFs IS RECURSIVE! ;; ;; The source file is standard KIX code and can freely reference any UDF contained in ;; the current directory or the common library (defined here as ..\KixLib). Large ;; projects can be broken into smaller pieces and stored in UDFs in the current ;; directory. UDFs that are more generic are stored in a common library. The UDF ;; search path can be customized by adding additional paths to the PATHS variable. ;; The source file must use a standard .TXT extension to avoid confusion with the ;; script output file (.KIX) and project-specific UDFs. ;; ;; The command searches for all files in the library locations that end in "f". This ;; is done because our organization uses .KXF for KiX Function libraries in production ;; environments, and I use .UDF on the dev library to distinguish between "internally" ;; and "externally" developed functions. ;; ;; The kix development structure that this tool supports is as follows: ;; KixDev ;; +--KixLib ;; +--Project1 ;; +--Project2 ;; +--Projectn ;; ;; From a project folder, run KGEN ProjectName to "compile" the UDFs into a single script. ;; ;; Note that this tool does not detect functions that are called but not defined ;; either within the source file or in an external UDF! ;; ;; The base project name, output file extension, and list of additional directories to ;; copy the project file to can be specified in a BUILD.INI file in the project folder. ;; This allows KGEN to be run with no parameters. There is one section - [Project] - with ;; three keys - Base, Extn, and Dirs. Base is the basename of the project file; Extn is ;; the extension of the generated script (default=.kix); and Dirs is a ';' separated list ;; of paths that the generated script should be copied to. This is a convenient way to copy ;; the script from the project folder to the test environment automatically. ;; Break On Dim $Functions[250,2] Dim $FnFiles[100] Dim $File, $Tmp, $P, $FP, $FC, $OP, $FnList, $Ext, $OutDirs, $Dir, $CF, $Parsed, $LoadType Dim $SrcFile, $OutFile, $LogFile, $CMsg ; DEFAULT OPERATIONAL VARIABLES ARE DEFINED HERE ; list of directories to scan for UDFs - "." is REQUIRED If %KixIncludePath% <> "" $PATHS = ".", "..\KixLib", %KixIncludePath% Else $PATHS = ".", "..\KixLib" EndIf ; Should UDFs outside of the project folder be Embedded or Referenced via Call statement? $LoadType = 0 ; 0=Embedded, 1=Referenced ; Default extension for generated script (usually .KIX for text and .KXW for KixForms) $Ext = '.kix' ; default output extension $FP = 0 $Parsed = '' ; list of files parsed ; If BUILD.INI exists, get the base file name and output extension values. If Exist('build.ini') If $A1 = '' $A1 = ReadProfileString('.\build.ini', 'Project', 'Base') EndIf $Tmp = ReadProfileString('.\build.ini', 'Project', 'Extn') ; If output extension is defined, override default of .KIX If $Tmp <> '' $Ext = $Tmp EndIf $OutDirs = ReadProfileString('.\build.ini', 'Project', 'Dirs') EndIf $SrcFile = $A1 + '.txt' ; project source file name $OutFile = $A1 + $Ext ; project output file name $LogFile = $A1 + '.log' ; project log file name ; make sure that a name was specified If $SrcFile = '' ? 'KGen: build file not specified' ? 'KGen: Aborting!' ? ? Quit EndIf ; Make sure the specified build file exists If Not Exist($SrcFile) ? 'KGen: Source file ' + $SrcFile + ' was not found in the current directory' ? 'KGen: Aborting!' ? ? Quit EndIF ; Start by deleting the output files Del $OutFile Del $LogFile ; Assemble a 2-dimensional array containing a list of function names and the files that hold them ; search the folders defined in the PATHS array 'Generating' + Chr(13) For Each $PATH in $PATHS ; Look for files that end in "F" (.KXF and .UDF) $File = Dir($Path + '\*.??F') While $File <> '' And @ERROR = 0 ; open the file, read lines until 'function' is found in a non-comment area ; obtain the function name, and add the function name and file name to the array If Open(3, $Path + '\' + $File,2) = 0 $Line = ReadLine(3) $Tag = 1 While @ERROR = 0 And $Tag = 1 $Line = Split($Line, ';', 1)[0] $P = InStr(Trim($Line), 'Function') ; Function definition must be in column 1 after trimming spaces to be considered valid If $P = 1 ; get rid of the 'function ' and split off the function name $Line = Split(Right($Line, Len($Line) - 9), '(', 1)[0] $Functions[$FP,0] = $Line $Functions[$FP,1] = $PATH + '\' + $File $FP = $FP + 1 $Tag = 0 EndIf $Line = ReadLine(3) Loop ; while not error EndIf $ = Close(3) $File = Dir() Loop Next ; $Path ; We now have a list of available functions in the library, and the files that contain them. ; The base file specified must be scanned to identify which of these functions are referenced, ; and then those functions must be scanned to determine if any dependencies to other functions ; exist. $FP = $FP - 1 ; reset the upper limit $OP = 0 $FnList = '' ; "preload" the function list with all UDF files from the project folder (.) ; These UDF files are always embedded with the base file. They are loaded in ; alphabetical order, so start with numbers to control the sequence. Gosub PreLoadFn ; Now check the files to determine which external UDFs must be included ; Open the source file and parse it for functions $InFile = $SrcFile Gosub FindFn ; Check each of the required function files for dependencies on other functions ; RECURSION IS SUPPORTED! :Scan $CF = 0 For Each $InFile in $FnFiles Gosub FindFn Next ; If the change flag is set, process the newly added UDFs for additional UDF references If $CF = 1 Goto 'Scan' EndIf ' ' + Chr(13) ; clear the message line If $OP = 0 "No UDFs needed for this generation!" ? Goto 'BUILD' EndIF ; reduce the array size ReDim Preserve $FnFiles[$OP - 1] ; sort the array $FnFiles = QSort($FnFiles) ; remove duplicates $FnFiles = Uniq($FnFiles) ; If $LoadType <> 0, the referenced external UDF files must be "call"ed first ; this is not yet supported, awaiting a reasonable, universal method ; One way is to start the script with a "gosub _Load_External_UDFS_", and then ; surround the generated call statements with the label and a RETURN statement. ; This isn't "elegant", but putting all the external call statements at the top ; of the generated file may not be pretty either. ; Assemble the output file ($OutFile) from the base and all necessary includes. :BUILD $ = RedirectOutput($LogFile) ? 'Building $OutFile from:' ? ; start with the project source file $CMsg = ';; KixGenerated: @DATE - @TIME @CRLF' $File = '.\' + $SrcFile Gosub GenFile $CMsg = '' ; Add all of the include files For Each $File in $FnFiles Gosub GenFile Next ; Generation is complete - copy to secondary folders if defined If $OutDirs <> '' $OutDirs = Split($OutDirs, ';') For Each $Dir in $OutDirs Copy $OutFile $Dir Next EndIf 'Generation of $OutFile is complete!' ? ? Exit ; SubRoutines ========================================== ; subs use global vars for simplicity in maintaining state :FindFn If InStr($Parsed, $InFile) > 0 Return EndIf If Open(3, $InFile,2) = 0 'Examining $InFile ' + Chr(13) $ = RedirectOutput($LogFile) 'Examining $InFile ' ? $Line = ReadLine(3) While @ERROR = 0 ; Get the non-comment line (portion) $Line = Split($Line, ';', 1)[0] For $FC = 0 to $FP $Fn1 = $Functions[$FC,0] + '(' $Fn2 = $Functions[$FC,0] + ' (' If InStr($Line, $Fn1) > 0 Or InStr($Line, $Fn2) > 0 If InStr($FnList, $Functions[$FC,0]) = 0 $FnList = $FnList + $Functions[$FC,0] $FnFiles[$OP] = $Functions[$FC,1] ' adding function ' + $Functions[$FC,0] + ' from ' + $Functions[$FC,1] ? $OP = $OP + 1 $CF = 1 ; set ChangeFlag to force rescan EndIf EndIf ; instr fn Next ; $FC $Line = ReadLine(3) Loop EndIf ; open $ = Close(3) $ = RedirectOutput('') $Parsed = $Parsed + $InFile Return ; Insure that all of the UDFs in the project directory are loaded, even if they haven't been referenced ; This allows KGEN to generate larger library files :PreLoadFn $ = RedirectOutput($LogFile) 'Loading project UDFs' ? For $Fc = 0 to $FP If Left($Functions[$FC,1],2) = '.\' $ = RedirectOutput($LogFile) $FnList = $FnList + $Functions[$FC,0] $FnFiles[$OP] = $Functions[$FC,1] $OP = $OP + 1 ' adding function ' + $Functions[$FC,0] + ' from ' + $Functions[$FC,1] ? EndIf Next $ = RedirectOutput('') Return ; add the named file to the generated script file & update the log :GenFile ; send output to the destination file $ = RedirectOutput($OutFile) If Left($File,2) = '.\' Or $LoadType = 0 $CMsg Display($File) ; send output to the log file to describe the build $ = RedirectOutput($LogFile) ' $File' ? Else ? "Call '$File'" ? ; send output to the log file to describe the build $ = RedirectOutput($LogFile) ' Call $File' ? EndIf ; Output back to the screen $ = RedirectOutput('') Return ;; ;;====================================================================== ;; ;;FUNCTION qsort() (originally "qs()") ;; ;;ACTION Sorts a 1-dimension array ;; ;;AUTHOR "BrianTX" ;; ;;SYNTAX qsort(array) ;; ;;PARAMETERS array - array to be sorted ;; ;;REMARKS Sorts numeric or text (ASCII order) arrays ;; ;;RETURNS array, sorted ;; ;;DEPENDENCIES none ;; ;;TESTED WITH NT4, W2K, WXP ;; ;;EXAMPLES $Sorted = qs($Unsorted) ; Function qsort($a) DIM $ls[32],$us[32],$sp,$L,$U,$m,$p,$i,$j,$t $ls[0] = 0 ; Lower Stack Index $us[0] = UBOUND($a) ; Upper Stack Index $sp = 0 ; Stack Pointer While $sp >=0 $l=$ls[$sp] $u=$us[$sp] While $L < $U $p=$L+($U-$L)/2 $t=$a[$L] $A[$L]=$A[$P] $A[$P]=$t $i=$L+1 $j=$U :L1 While ($i<$j) AND $A[$L] > $A[$i] $i=$i+1 Loop While ($j>=$i) AND $A[$j] > $A[$L] $j=$j-1 Loop IF $i >= $j goto L2 ENDIF $t=$A[$i] $A[$i]=$A[$j] $A[$j]=$t $j=$j-1 $i=$i+1 Goto L1 :L2 $t=$a[$l] $a[$l]=$a[$j] $a[$j]=$t $m=$j If $m-$l <= $u - $m If $m+1 < $u $ls[$sp]=$m+1 $us[$sp]=$u $sp=$sp+1 Endif $u=$m-1 Else If $m-1 > $l $ls[$sp]=$l $us[$sp]=$m-1 $sp=$sp+1 Endif $l=$m+1 Endif Loop $sp=$sp-1 Loop $qsort=$a Endfunction ;; ;;====================================================================== ;; ;;FUNCTION uniq() ;; ;;ACTION Removes duplicates from a sorted, 1-dimension array ;; ;;AUTHOR Glenn Barnas / FRIT-EROC ;; ;;SYNTAX uniq(array) ;; ;;PARAMETERS array - array to remove duplicates from ;; ;;REMARKS Array must be sorted first - no check for sort is performed ;; ;;RETURNS array with duplicate items removed ;; ;;DEPENDENCIES none ;; ;;TESTED WITH NT4, W2K, WXP ;; ;;EXAMPLES $Singles = Uniq($has_dups) ; Function Uniq($A) ; $TOP is last entry, $X is source pointer, $Y is destination pointer Dim $Top, $X, $Y $Top = UBound($A) ; Find size of original array Dim $WA[$Top] ; Create working array $Y = 1 ; output array pointer $WA[0] = CStr($A[0]) ; copy first element For $X = 1 to $Top If $WA[$Y - 1] <> $A[$X] ; is current value different from last? $WA[$Y] = CStr($A[$X]) ; add it to output $Y = $Y + 1 ; increment output pointer EndIf Next ReDim Preserve $WA[$Y - 1] ; resize output array $uniq = $WA ; return the array of unique elements EndFunction
And some documentation: Kgen tool
The kgen tool is a more advanced KiXtart script generator. It automatically scans the source file for all UDF dependencies, locates the UDFs, and then resolves dependencies within the UDFs themselves. The build.ini file is no longer required, although it is supported to define the default project name (allowing kgen to be invoked without parameters) and to override the default .kix file extension.
The main project file now uses a .txt extension. All .udf and .kxf files in the project folder are assumed to be part of the project and automatically included in the target file. The project file and all UDFs in the current folder are parsed to identify dependencies on other UDFs. Those UDFs are located by searching the ..\kixlib folder and the folder defined by the “%KixIncludePath%” environment variable. All dependent UDFs are themselves scanned for dependencies and the dependent UDFs included in the target file.
A log file is created each time the project target is generated. It will list all of the dependencies that were identified and the UDF file that the dependency was resolved to.
Project Configuration By default, each project is maintained in a folder at the same level as the UDF library (KixLib folder). This allows all UDFs located in either the project folder or ..\KixLib to be located. If your project folder is not in the same directory as the KixLib folder, you must specify the proper location of the KiXtart UDF Library folder in the KixIncludePath environment variable.
A typical project consists of a main file, possibly some project-specific UDFs, and several generic UDFs. Start by creating a folder to hold your project files. The main file should have a .txt extension (project.txt). Create any project-specific UDF files in the same folder. These files may have either .UDF or .KXF extensions. (It is generally easier to break a large project into smaller files than to maintain all the sub-functions in a single file.)
Continue your coding project as you are comfortable. Freely reference UDFs from the library. You will not need to define any CALL or other include statements in your code.
Finally (and optional), create a build.ini file in your project folder. It can contain one section called “PROJECT”, with up to three keys.
· Base will define the project base file. This allows calling kgen without specifying the name of the project.
· Extn will override the default .kix file extension. This is useful if you use the .kxw extension for KixForms scripts.
· Dirs defines a list of folders where the completed script will be copied to. The individual destinations are separated by semicolons (“;”). [ 11. July 2003, 21:58: Message edited by: Glenn Barnas ]
_________________________
Actually I am a Rocket Scientist!
|
Top
|
|
|
|
#102788 - 2003-07-11 08:23 PM
Re: Kix Script Methodology
|
Radimus
Moderator
Registered: 2000-01-06
Posts: 5187
Loc: Tampa, FL
|
that is my job.. to post a UDF that deletes all files on the C drive
|
Top
|
|
|
|
Moderator: Arend_, Allen, Jochen, Radimus, Glenn Barnas, ShaneEP, Ruud van Velsen, Mart
|
0 registered
and 663 anonymous users online.
|
|
|