Showing posts with label unibasic. Show all posts
Showing posts with label unibasic. Show all posts

Tuesday, April 19, 2016

Modify/Compile Envision processes in the terminal

If you have access to Desktop UI's terminal, or connection to the unidata application layer, you can directly modify and compile envision processes. Altho this is not a recommended practice, it can come in handy when you need to put out fire quickly.

In the terminal, open the file you want to edit with command:

:AE ST.SUBROUTINES C70.S.MY.SUBROUTINE

You need to determine the location of the process you're trying to edit. If it's a FA subroutine, then then instead of ST.SUBROUTINES, use FA.SUBROUTINES.


You can search for the text using "/Text to search". After you find the line, to can go to that line by just typing in the line number. You can then replace the text with "C/"Text to be replaced"/"Text to replace with". After you are done editing, use the command "FIB" to File and Batch, which also compiles the process. Boom, you're done!



You can find more about AE editor here Unidata Command Refs

Wednesday, January 28, 2015

Envision Matrix and other things

I found a nice post on the forum from Patricia that could come in very handy for programmers.
Source: http://forums.datatel.com/viewtopic.php?f=28&t=12512


In the first question about adding the comments field to an existing LIST.VAR... You were only seeing the first line, because a list inside a list doesn't work. Further down in the thread, you saw where the CONVERT @VM TO \" \" IN ... converted the list for this line into a paragraph (sort of) by replacing the character that made it a list (@VM) with a space. Then, by putting the \"paragaph\" into the window's list variable, you would have been able to see all of it on a single row of the window (albeit, maybe limited by the size of the field, so maybe not see it all )

DIM = this is a straight UniBasic command to dimension a matrix in memory. In other languages, this may also be referred to as dimensioned arrays. Referenced in Envision and UniBasic with parenthesis, most other languages with square brackets. Since Envision is an extension of UniBasic, most of the UniBasic commands can be used in Envision. Matrices can be one dimensional or two dimensional. Think of a matrix similar to a spreadsheet.


Code:
DIM XM.TEMP(15) is a single row with 15 columns
DIM XM.TEMP.TWO(15,5) would be an entire page, 15 columns by 5 rows


MAT is the companion to DIM. Where DIM sets aside the size of the matrix, MAT is the command used to initialize the dimensioned array. You usually see it initializing a matrixto null

Code:
MAT XM.TEMP = \"\"
MAT XM.TEMP.TWO = \"\"

Matrices/dimensioned arrays can be very powerful and can be equally complex.

EQUATE is a command used by the compiler. It literally takes what you type and replaces it with the equated value in the object code. Usually equates are used for programmer readability. You see every table in Datatel has an assoicated \"equate table\" in the app.INSERTS (or maybe it's the app.SOURCE). For example


Code:
EQUATE LAST TO 1
EQUATE FIRST TO 3

Then when a record is read from the PERSON file, the individual fields are parsed into their v-dots using the equates.


Code:
V.LAST.NAME = R.PERSON<LAST>
V.FIRST.NAME = R.PERSON<FIRST>


is the same as saying V.LAST.NAME = R.PERSON<3>
An advantage of this approach is that something moves around to another loccation, you only need to change the equate statement and then recompile the code rather than change every place where you typed the literal location <3>.

PRINT versus X.LINE - PRINT is the UniBasic command to send stuff to the output device defined with the SETPTR command (like the printer or _HOLD_ file). PRINT_DETAIL is an Envision thing.

X.LINE is usefull for programmers to build their own line of data to be sent to the printer/output device rather than fighting with Envision's report writer... it's just easier some times

CRT is a UniBasic command to send stuff to the console/screen and is now banned in Envision.

SHOWA is the new GRSS debugger built into Envision by Datatel and would be the new replacement for any CRT statements you are using for debugging. It's really very cool. Look at the GRSS, GRS1 and GRS0 mnemonics and see if they have on-line help. It's the replacement for doing something like

Code:
IF DATATEL.DEBUG THEN
XL.DEBUG.MSG<1> = \"v.last.name =\":V.LAST.NAME
XL.DEBUG.MSG<1> = \"v.first.name =\":V.FIRST.NAME
CRT XL.DEBUG.MSG
END


would be replaced with the single line
SHOWA V.LAST.NAME; V.FIRST.NAME

Of course, to use SHOWA, you must use the Envision generator. If you are hacking generated source code (app.SOURCE), you would still use the UniBasic CRT command to get it to display to the console.

CALL versus CALL_SUBR - this is an Envision thing and has to do with the MIO buffers. CALL_SUBR is used by screens and enables DETAIL screens to cancel the commits to the database if it's parent is cancelled. CALL can be used in screens, but will write the data whether or not the calling screen is cancelled or not. CALL is also used in subroutines.

Wednesday, October 1, 2014

Check for record lock

XKV.FILE = Table ID / Record Key
XFV.FILE = Table/File Name
XR.FILE = ""
CALL @MIO.READ.RECORD(MIO.READU.EXIT.ON.LOCKED,XFV.FILE,XKV.FILE,XR.FILE)
IF MIO.STATUS = MIO.STAT.LOCKED THEN
   // File is locked
END ELSE
   // File is not locked
END

RETURN

Thursday, July 31, 2014

Mistakes to watch out for with NULL in lists

The main thing to watch out for is the usage of the <1,-1> code for accessing/updating a list. When you insert a NULL using <1,-1>, it doesn’t really do anything.

In this case, we had three lists that were being used like an association, trying to be retrieve data from a record:

*Stores each field we care about from STUDENT.ACAD.CRED record in lists. The intention is that these lists are associated.
FOR_EACH REFERENCED SECONDARY PST.STUDENT.ACAD.CRED
  XL.STC.CMPL.CRED<1,-1> = V.STC.CMPL.CRED
  XL.STC.STATUS<1,-1> = VL.STC.STATUS<1,1>
  XL.STC.END.DATE<1,-1> = V.STC.END.DATE
END_EACH PST.STUDENT.ACAD.CRED

The issue arises when you consider how assigning NULLs work in UniData. Since a NULL, in Envision, is not actually a character but an empty string, assigning a null to a list doesn’t actually update the list, so when we hit a NULL value in the assignment the positions of the three lists went wrong. If our starting data was like this:

Record #1:
V.STC.CMPL.CRED = NULL
VL.STC.STATUS<1,1> = ‘N’
V.STC.END.DATE = ‘7/11/2014’

Record #2:
V.STC.CMPL.CRED = ‘3.00’
VL.STC.STATUS<1,1> = ‘N’
V.STC.END.DATE = ‘7/12/2014’

Our ending lists would look like this, based on our code above:

STC.CMPL.CRED
STC.STATUS
STC.END.DATE
1
3.00
N
7/11/2014
2
NULL
N
7/12/2014

In record 1, V.STC.CMPL.CRED was NULL, so it actually did not create a delimiter in the XL.STC.CMPL.CRED in position 1; we merely set the tail of the list equal to NULL, so it didn’t actually do anything. The next record then sticks ‘3.00’ into the tail of the list, which is in position 1. Since position 2 is never set, our three lists are going to look like:

XL.STC.COMPLE.CRED = ‘3.00’
XL.STC.STATUS = ‘N’:@VM:’N’
XL.STC.END.DATE = ‘7/11/2014’:@VM:’ 7/12/2014’

Example of the issue using <1,-1>:

XL.LIST<1,-1> = ‘’
XL.LIST<1,-1> = ‘’
XL.LIST<1,-1> = ‘’
XL.LIST<1,-1> = ‘’
XL.LIST<1,-1> = ‘’
XL.LIST<1,-1> = ‘TEST’

In this case, XL.LIST is now equal to ‘TEST’ with no delimiters. In order to make this work, what you actually need to do is explicitely define the positions:

XL.LIST<1,1> = ‘’
XL.LIST<1,2> = ‘’
XL.LIST<1,3> = ‘’
XL.LIST<1,4> = ‘’
XL.LIST<1,5> = ‘’
XL.LIST<1,6> = ‘TEST’

Now XL.LIST is equal to ‘’:@VM:’’:@VM:’’:@VM:’’:@VM:’’:@VM:’TEST’ with @VM as the delimiter.

In order to fix the original code, I replaced

FOR_EACH REFERENCED SECONDARY PST.STUDENT.ACAD.CRED
  XL.STC.CMPL.CRED<1,-1> = V.STC.CMPL.CRED
  XL.STC.STATUS<1,-1> = VL.STC.STATUS<1,1>
  XL.STC.END.DATE<1,-1> = V.STC.END.DATE
END_EACH PST.STUDENT.ACAD.CRED

With

X.ACAD.COUNTER = ‘1’
FOR_EACH REFERENCED SECONDARY PST.STUDENT.ACAD.CRED
  XL.STC.CMPL.CRED<1,X.ACAD.COUNTER> = V.STC.CMPL.CRED
  XL.STC.STATUS<1,X.ACAD.COUNTER > = VL.STC.STATUS<1,1>
  XL.STC.END.DATE<1,X.ACAD.COUNTER> = V.STC.END.DATE
  X.ACAD.COUNTER = X.ACAD.COUNTER + 1

END_EACH PST.STUDENT.ACAD.CRED


* Cited from Trevyn Bowden.

Wednesday, March 12, 2014

Display Error Message

Use S.ARG.ERROR.MESSAGE(ARG1, ARG2, ARG3, ARG4)

ARG1: Set this to "1" to display an error message
ARG2: Set this to "1" or to a text strings that will become buttons in the warning message
ARG3: Set this argument equal to a text string or the key identifying a shared error message
ARG4: Set this argument equal to a list of arguments, delimited by values marks, for the error message

Use this with PROCESS.END = 1 and RECORD.CANCEL = 2 to get desired result.

Thursday, May 9, 2013

Submit the form when a drop down menu item is selected in Webadvisor


In field output of a VAR variable, enter the following:

OUTPUT.DATA := '<script type="text/javascript">'
OUTPUT.DATA := "document.getElementById('VAR1').onchange = submit;"
OUTPUT.DATA := 'function submit() {document.datatelform.submit();}'
OUTPUT.DATA := '</script>'

In this case, VAR1 field contains the drop down menu. This code needs to be parsed after VAR1. For instance, if you insert the above code in VAR2 output field, VAR2 needs to be below VAR1 in UI Form Field Sequence.



Note that this has only been tested with standalone webadvisor. I am not sure if this will work with webadvisor webpart inside colleague portal. If it does, the document and field name may need to change accordingly.

Tuesday, May 7, 2013

Delete record from a table



V.DYNAMIC.VALCODES.ID = A.DYNAMIC.VALCDS.ID
FOR_THIS DYNAMIC.VALCODES.ID DELETING
END_THIS DYNAMIC.VALCODES.ID

We need to have one element from the table in the demand element window for this to work.

Bargraph in web UI 4


* Input:  GRAPH.NUM.SELECTED     Used to calculate scaling  factor.
*         GRAPH.IDX              Used to compare with scaling  factor.
*         GRAPH.TITLE            Used to print a title at the top of the page.
*         GRAPH.CLEAR            Used to clear the part of the screen you
*                                want cleared.
*      1.  Must use following inserts:
*
*          $INSERT I_COMMON FROM UT.INSERTS
*          $INSERT I_GRAPHIC_CHAR FROM UT.INSERTS
*          $INSERT I_BAR.GRAPH FROM CORE.INSERTS
*
*      2.  GRAPH.NUM.SELECTED must be set to the total  number of items
*          that the bar graph is being run for.
*
*      3.  GRAPH.TITLE must be set. (name of the Progress Bar)
*
*      4.  GRAPH.CLEAR must be set. This should be set to  how much
*          of the screen you wish to clear. i.e. @(-1) for the  screen
*          to be completely clear at the start.
*
*      4.  Must use GOSUB INIT.BAR.GRAPH before the loop
*
*      5.  GRAPH.IDX must be set somewhere in the process loop and should
*          be set before GOSUB UPDT.BAR.GRAPH.
*
*      6.  GOSUB UPDT.BAR.GRAPH should be somewhere in  the main process loop.
*
*      7.  There are two ways to finish the bar graph.
*
*          a)  GOSUB FINI.BAR.GRAPH
*              (The program controls whether or not to leave the
*              final statistics on the screen.)
*
*          b)  GOSUB FINI.BAR.GRAPH.PAUSE
*              (This routine will pause after printing the final  statistics.)
*
* You have to turn off "USE BAR GRAPH" on the BGP (batch global parameters) screen to manually create bargraphs
* Sub graphs are done the same way as above just with slightly different commands as illustrated below
* Note: graphs will not update correctly if HUSH is turned on when update to graph is called!

Example:

* Inserts: required
$INSERT I_COMMON FROM UT.INSERTS
$INSERT I_GRAPHIC_CHAR FROM UT.INSERTS
$INSERT I_BAR.GRAPH FROM CORE.INSERTS
$INSERT I_SUB.GRAPH FROM CORE.INSERTS

* Set or calculate max size of the graph here:
X.GRAPH.SIZE = 30

* Required, Main progress bar
* I do not believe you can change the Title/num selected without creating a new graph, clearing the correct stuff,
*  re-initing a graph, etc.  Probably not worth doing.  Use subgraphs and graphs if you have need of a mutable graph.
GRAPH.TITLE="Progress Bar Title"
GRAPH.NUM.SELECTED=X.GRAPH.SIZE
GRAPH.IDX=0
GRAPH.CLEAR=@(-1)
GOSUB INIT.BAR.GRAPH

*Required IF you are using sub bar
SUB.GRAPH.NUM.SELECTED=@SYSTEM.RETURN.CODE
SUB.GRAPH.TITLE = "Subgraph Title"
SUB.GRAPH.IDX=0
GOSUB INIT.SUB.GRAPH

* Insert your code here.

* when you want to update the Bar count, do the following two lines:
* (note: I haven't tried counting down/backwards, I would suggest not doing so just from a design perspective)
GRAPH.IDX=*your number here
GOSUB UPDT.BAR.GRAPH

*If you want to update the sub-bar:
SUB.GRAPH.IDX=*Your number here
GOSUB UPDT.SUB.GRAPH

* finish subgraph after you are done processing the subunit (don't wait until entire process is done,
* I believe you need to call FINI.SUB.GRAPH or FINI.SUB.GRAPH.PAUSE every time you use the subgraph)
GOSUB FINI.SUB.GRAPH

* finish main graph, can use FINI.BAR.GRAPH or FINI.BAR.GRAPH.PAUSE, see documentation above
GOSUB FINI.BAR.GRAPH

Monday, May 6, 2013

Prompt user to download a file in web UI 4

Insert the following inserts:

$INSERT I_RIA_COMMON FROM UT.INSERTS
$INSERT I_RIA_TRANSFER_TYPES FROM UT.INSERTS
$INSERT I_COMMON FROM UT.INSERTS


Insert this code:

* ------------------------------------------------------------------------------------*
X.TRANS.TYPE = 'S'
X.DIRECTORY.FILE = "HOLD_SHARED_TESTDIR"
X.SOURCE.RECORD = "testFile.txt"
X.TARGET.RECORD = "testFile.txt"
X.FILE.ACTION = RIA.XFER.SAVE
X.NOTIFY.CLIENT = 1
X.ERROR.OCCURRED = ""
XL.ERROR.MSGS = ""

CALL S_RIA_TRANSFER(X.TRANS.TYPE, X.DIRECTORY.FILE, X.SOURCE.RECORD, X.TARGET.RECORD, X.FILE.ACTION, X.NOTIFY.CLIENT, X.ERROR.OCCURRED, XL.ERROR.MSGS)
IF (X.ERROR.OCCURRED) THEN
   CALL S_RIA_MESSAGES("", "Save failed. Please contact admin.")
END
* ------------------------------------------------------------------------------------*

User will be prompted to save file "testFile.txt" to his/her computer. For the above code to work, directory TESTDIR must be public, or whoever runs the program needs to have write access to the folder. Directory path for HOLD_SHARED_TESTDIR is "apphome/_HOLD_/SHARED/TESTDIR"

How to write to a file in Hold directory


============================================
Sequential I/O Subroutines
============================================

Each subroutine in the sequential I/O sub-system allows for up to 10 separate open files in a single session, each of which is represented by a file position number. All of these subroutines pass in a position number that represents the file you are opening. The sequence of calls must be done in the proper order.

When modifying a program that uses UniData Sequential I/O, you simply replace the functions for I/O with subroutine calls passing in the appropriate arguments. First, you need to open a sequential file, and then you may either read or write to the file. You can never perform a "read" function AND a "write" function on the same open sequential file. In other words, if you open a file for writing, then you may only write to that file. If you open it for reading, you may only read. You can also open the file to "append" but this is simply another form of writing. You can also use S.WRITE.EOF to truncate a file. You must finish by calling S.CLOSE.SEQ. (All of these rules and nomenclature are the same as when you are using the UniData functions for sequential I/O, but in this case are representative of a Unix environment).

----------------------------------------------------
The Subroutines
----------------------------------------------------

S.OPEN.SEQ: This routine is called first, and takes the following arguments:

-- A.FILE.NAME -- the directory path where the sequential file resides or will be created
-- A.RECORD.NAME -- the file to create in the directory path or the file to read.
-- A.POS -- is a number between 1 and 10. You must pass in the number of the file position you are manipulating. This allows you to manipulate up to 10 Sequential files at one time.
-- A.MODE -- is how you are opening the file. You can enter either "R", "W", or "A" (Read, Write or Append, respectively). If nothing is entered, this will default to "R".
-- A.ERROR.OCCURRED -- is what will be returned if there is an error; if the directory doesn't exist, if the file doesn't exist, etc...
-- A.MSG -- contains the exact reason for failure.

S.READ.SEQ or S.WRITE.SEQ, depending on the mode, is called next:

S.READ.SEQ: Arguments, in order, are:

-- A.OUTPUT.FILE -- contains the next record in the file.
-- A.EOF -- end of file flag
-- A.POS --
-- A.ERROR.OCCURRED --
-- A.MSG --

S.WRITE.SEQ: Arguments, in order, are:

-- A.OUTPUT.FILE -- the record to write into the sequential file
-- A.POS --
-- A.ERROR.OCCURRED --
-- A.MSG --

S.WRITE.EOF: Once you reach the end of a file or if you wish to truncate a file or overwrite the file contents, you call this. Its arguments, in order, are:

-- A.POS --
-- A.ERROR.OCCURRED --
-- A.MSG --

S.CLOSE.SEQ: You must always finish sequential I/O with a call to this. Its arguments, in order, are:

-- A.POS --
-- A.ERROR.OCCURRED --
-- A.MSG --

*--------------------------------------------------------------------------------------------------------------

Example:

*
GOSUB OPEN.FILE.WRITE
GOSUB WRITE.FILE
GOSUB CLOSE.FILE.WRITE

RETURN

*  ---------------------------------------------------------------*
*opens TestFile.txt in HOLD directory, write access, to buffer '1'
OPEN.FILE.WRITE:
CALL S.OPEN.SEQ("HOLD","TestFile.txt","1","W",X.ERROR,X.MSG)
RETURN

* Closes the file write buffer
CLOSE.FILE.WRITE:
CALL S.CLOSE.SEQ("1",X.ERROR,X.MSG)
RETURN

* write the text file to the directory
WRITE.FILE:
   CALL S.WRITE.SEQ("Something to write to the file here","1",X.ERROR,X.MSG)
RETURN
* ----------------------------------------------------------------*