4.30: Difference between revisions

From BR Wiki
Jump to navigation Jump to search
(corrected sample code error)
 
(58 intermediate revisions by 4 users not shown)
Line 7: Line 7:
==MISCELLANEOUS ENHANCEMENTS==
==MISCELLANEOUS ENHANCEMENTS==


“ON error-type IGNORE” now ignores the error instead of going to an Ignore label. This is effective for both ON statements and individual statement error exits. This could change the way your programs work if your Ignore statements do more than CONTINUE.   
===ON error-type IGNORE===
ON error-type IGNORE now ignores the error instead of going to an Ignore label. This is effective for both ON statements and individual statement error exits. This could change the way your programs work if your Ignore statements do more than CONTINUE.   


The general purpose ERROR exit implies SOFOW truncation. So statements that are governed by ERROR IGNORE also do SOFLOW truncation as needed.  
The general purpose ERROR exit implies SOFOW truncation. So statements that are governed by ERROR IGNORE also do SOFLOW truncation as needed.  


For client / server configurations:
===For client / server configurations===
SPOOLPATH  @: client-pathname
SPOOLPATH  @: client-pathname
Sets the remote spool path on the client. In addition to regular spool files, this is where PDF files are created. SPOOLPATH can be set concurrently for both client and server by specifying two SPOOLPATH statements. The @: indicates remote.   
Sets the remote spool path on the client. In addition to regular spool files, this is where PDF files are created. SPOOLPATH can be set concurrently for both client and server by specifying two SPOOLPATH statements. The @: indicates remote.   
Line 21: Line 22:
The status of SPOOLPATH and REMOTESPOOLPATH settings are displayed in response to the STATUS SUBSTITUTE command.   
The status of SPOOLPATH and REMOTESPOOLPATH settings are displayed in response to the STATUS SUBSTITUTE command.   


===CHR$(6)===
CHR$(6) is a field separator that displays as a space but causes the immediately preceding data to be right justified. This applies to both Native Windows Printing and PRINT FIELDS.  
CHR$(6) is a field separator that displays as a space but causes the immediately preceding data to be right justified. This applies to both Native Windows Printing and PRINT FIELDS.  


===MAT2STR and STR2MAT===
MAT2STR, STR2MAT changes to trim outside of quotes, but not inside of quotes and to always quote MAT2STR when quotes are present.   
MAT2STR, STR2MAT changes to trim outside of quotes, but not inside of quotes and to always quote MAT2STR when quotes are present.   


===STATUS USERS===
STATUS USERS will display the WSID and name of each user logged in on the network.  
STATUS USERS will display the WSID and name of each user logged in on the network.  
The SQL statement SHOW USERS responds with the same information for ODBC users.
The SQL statement SHOW USERS responds with the same information for ODBC users.


===BRERR$===
BRERR$ is a new system function that display the description of BR ERR value.
BRERR$ is a new system function that display the description of BR ERR value.
BRERR$(error-code) returns the description of that code.
BRERR$(error-code) returns the description of that code.
Examples-
Examples:
When ERR returns 4270, BRERR$ will return “end of file”.
When ERR returns 4270, BRERR$ will return “end of file”.
BRERR$(0875) returns “unrecognized data after field specification”
BRERR$(0875) returns “unrecognized data after field specification”


===ODBC===
For making it easier to configure ODBC with BRconfig.sys and to setup common configuration files for multiple platforms we have added:
For making it easier to configure ODBC with BRconfig.sys and to setup common configuration files for multiple platforms we have added:
@LINUX
@LINUX
Line 49: Line 55:
=== GRID AND LIST CHANGES===
=== GRID AND LIST CHANGES===


Arrays are automatically resized when receiving data from 2D INPUT operations. This also applies to grouped arrays. Automatic resizing only applies to one dimensional arrays and does not occur when INPUTing into two dimensional arrays.
In [[list and grid]] controls, arrays are automatically resized when receiving data from 2D INPUT operations. This also applies to grouped arrays. Automatic resizing only applies to one dimensional arrays and does not occur when INPUTing into two dimensional arrays.


e.g.  INPUT FIELDS "row,col,LIST rows/cols, ROW, ALL" : ( MAT Array1$,
Example where all arrays are one dimensional and may have the incorrect number of elements:
            MAT Array2$, MAT Array3, MAT Array4, MAT Array5$ )
 
  Where all arrays are one dimensional and may have the incorrect number of elements.
INPUT FIELDS "row,col,LIST rows/cols, ROW, ALL" : ( MAT Array1$, MAT Array2$, MAT Array3, MAT Array4, MAT Array5$ )
 
Where all arrays are one dimensional and may have the incorrect number of elements.




==== Three New Read Types====
==== Three New Read Types====
  Notes-
 
Auto Resizing applies
Auto Resizing applies.
Selection Type must be ALL
 
Selection Type must be ALL.


The original 2D INPUT read types are:
The original 2D INPUT read types are:
  CNT - The number of cells specified.
  SUB - Read the Cell Subscript Values.
  CELL - Read each cell specified.
  ROWCNT - The number of rows specified.
  ROWSUB - The subscripts of the specified rows.
  ROW - Read all cells in each specified row.


HEADERS The original PRINT FIELDS HEADER values.
'''CNT''' - The number of cells specified.
e.g. INPUT FIELDS "row,col,LIST rows/cols, HEADERS,,NOWAIT" :
 
                                  (MAT HEADINGS$,MAT WIDTHS, MAT FORMS$)
'''SUB''' - Read the Cell Subscript Values.
 
'''CELL''' - Read each cell specified.
 
'''ROWCNT''' - The number of rows specified.
 
'''ROWSUB''' - The subscripts of the specified rows.
 
'''ROW''' - Read all cells in each specified row.
 
'''HEADERS''' - The original PRINT FIELDS HEADER values.
 
Example:
 
  INPUT FIELDS "row,col,LIST rows/cols, HEADERS,,NOWAIT" :(MAT HEADINGS$,MAT WIDTHS, MAT FORMS$)
 
'''COLCNT''' - The number of columns established by the header arrays.
 
Example:


  COLCNT - The number of columns established by the header arrays.
INPUT FIELDS "row,col,LIST rows/cols, COLCNT, ALL" : numeric-variable
e.g.  INPUT FIELDS "row,col,LIST rows/cols, COLCNT, ALL" : numeric-variable


These  are for generalized library routines to inspect passed controls.  
These  are for generalized library routines to inspect passed controls.  


  SORT_ORDER - Provides a value of zero for each unsorted column and gives
'''SORT_ORDER''' - Provides a value of zero for each unsorted column and gives the ascending sequence of column sorts that have occurred. If a column has been reversed (double sorted) it's value will be negative.
the ascending sequence of column sorts that have occurred. If a column has
 
been reversed (double sorted) it's value will be negative.
Example:
 
INPUT FIELDS "row,col,LIST rows/cols, SORT_ORDER, ALL" : numeric-array


e.g.  INPUT FIELDS "row,col,LIST rows/cols, SORT_ORDER, ALL" : numeric-array
Given the following history of sorting a four column GRID:
Given the following history of sorting a four column GRID:
column 1 (descending most rescent)
column 1 (descending most rescent)
column 2 (ascending first sorted)
column 2 (ascending first sorted)
column 3 (not sorted)
column 3 (not sorted)
column 4 (sorted ascending)
column 4 (sorted ascending)
 
SORT_ORDER would return-
array(1) ->  -1
array(2) ->  3
array(3) ->  0
array(4) ->  2


'''SORT_ORDER''' would return
array(1) ->  -1
array(2) ->  3
array(3) ->  0
array(4) ->  2


=== Restoring a User Sorted 2D Control===
=== Restoring a User Sorted 2D Control===
Line 104: Line 124:
This has been extended to allow a numeric array of instead of a scalar. If an array is given, it is assumed to be in the same format that SORT_ORDER returns. The new format is:
This has been extended to allow a numeric array of instead of a scalar. If an array is given, it is assumed to be in the same format that SORT_ORDER returns. The new format is:


PRINT FIELDS "nn,nn,GRID 10/40,SORT": { column-number | numeric-array }
PRINT FIELDS "nn,nn,GRID 10/40,SORT": { column-number | numeric-array }


Where the numeric-array has one element for each column left to right. BR will resort the columns in the requested order.  
Where the numeric-array has one element for each column left to right. BR will resort the columns in the requested order.  
Line 111: Line 131:


=== A new Read Qualifier is available.===
=== A new Read Qualifier is available.===
[[Displayed_Order]] introduced
{{:Displayed_Order}}


===Masked 2D Display===
===Masked 2D Display===
Line 140: Line 160:


Valid current selection types are:
Valid current selection types are:
  SEL - Read one or more selected items.
 
  SELONE - Select only one item.
'''SEL''' - Read one or more selected items.
  ALL - Read all items in the control (except headings).
 
  CUR - Current cell or row number.
'''SELONE''' - Select only one item.
  CHG - All cells or rows who’s values have been changed by the operator.
 
'''ALL''' - Read all items in the control (except headings).
 
'''CUR''' - Current cell or row number.
 
'''CHG''' - All cells or rows who’s values have been changed by the operator.


BR now supports the following additional selection types:
BR now supports the following additional selection types:
  RANGE - Specifies which portion of a 2D control is to be input.
 
  CELL_RANGE – A special type of output range.
'''RANGE''' - Specifies which portion of a 2D control is to be input.
 
'''CELL_RANGE''' – A special type of output range.




Line 155: Line 182:
In the following examples BR will redimension the receiving arrays as needed:
In the following examples BR will redimension the receiving arrays as needed:


  INPUT FIELDS "row, col, LIST rows/cols, CELL, RANGE" : start, end, MAT Data$
INPUT FIELDS "row, col, LIST rows/cols, CELL, RANGE": start, end, MAT Data$


This reads the specified range of cells. BR redimensions MAT Data$ as needed.  Note that CELL may now be used with LIST. Previously, LISTs were only addressable by row.  
This reads the specified range of cells. BR redimensions MAT Data$ as needed.  Note that CELL may now be used with LIST. Previously, LISTs were only addressable by row.  


INPUT FIELDS "row, col, LIST rows/cols, ROW, RANGE" :
INPUT FIELDS "row, col, LIST rows/cols, ROW, RANGE": (start:=7), (end:=11), ( MAT Array1$, MAT Array2, MAT Array3$ )
            (start:=7), (end:=11), ( MAT Array1$, MAT Array2, MAT Array3$ )


This reads the cells in rows 7 through 11. The receiving arrays are redimensioned as appropriate.
This reads the cells in rows 7 through 11. The receiving arrays are redimensioned as appropriate.


  INPUT FIELDS "row, col, GRID rows/cols, ROW, RANGE" :
INPUT FIELDS "row, col, GRID rows/cols, ROW, RANGE": MAT start, MAT end, ( MAT Data1$, MAT Data2$, MAT Data3 )
            MAT start, MAT end, ( MAT Data1$, MAT Data2$, MAT Data3 )
 
This reads one or more ranges of rows.
This reads one or more ranges of rows.


A more detailed example of this is:
A more detailed example of this is:
   100 -- create and populate a LIST control --
   100 ! create and populate a LIST control  
  ........
   200 MAT START(3) : MAT END(3)
   200 MAT START(3) : MAT END(3)
   210 READ MAT START, MAT END
   210 READ MAT START, MAT END
   220 DATA 7,21,33
   220 DATA 7,21,33
   230 DATA 11,21,38
   230 DATA 11,21,38
   240 INPUT FIELDS "row, col, LIST rows/cols, ROW, RANGE" : MAT START,
   240 INPUT FIELDS "row, col, LIST rows/cols, ROW, RANGE" : MAT START, MAT END, ( MAT Array1$, MAT Array2, MAT Array3$ )
            MAT END, ( MAT Array1$, MAT Array2, MAT Array3$ )


This reads 12 rows of data ( row 7-11, row 21 and rows 33-38 ).
This reads 12 rows of data ( row 7-11, row 21 and rows 33-38 ).
Line 184: Line 208:
By default, RANGE output refers to rows. The special keyword CELL_RANGE is used to denote the specification of cell ranges. Additionally, the use of scalars versus arrays for start and end values determines important characteristics of the output process.  
By default, RANGE output refers to rows. The special keyword CELL_RANGE is used to denote the specification of cell ranges. Additionally, the use of scalars versus arrays for start and end values determines important characteristics of the output process.  


4c) Using Scalars For Range Specification
Using Scalars For Range Specification


PRINT FIELDS "7, 8, GRID 10/75, RANGE": start, end, MAT Data$
PRINT FIELDS "7, 8, GRID 10/75, RANGE": start, end, MAT Data$


This replaces the values in rows numbered 'start' through 'end' with the data in MAT Data$. The size of MAT Data$ must be a multiple of the number of columns in the GRID or an error is generated.
This replaces the values in rows numbered 'start' through 'end' with the data in MAT Data$. The size of MAT Data$ must be a multiple of the number of columns in the GRID or an error is generated.


PRINT FIELDS "7, 8, LIST 10/75, RANGE": start, end, (MAT NAME$,
PRINT FIELDS "7, 8, LIST 10/75, RANGE": start, end, (MAT NAME$, MAT CITY$, MAT AGE, MAT WEIGHT)
                                          MAT CITY$, MAT AGE, MAT WEIGHT)


This replaces the values in ROWs numbered 'start' through 'end' with the data from MATs NAME$, CITY$, AGE and WEIGHT. The data arrays must all be dimensioned the same.
This replaces the values in ROWs numbered 'start' through 'end' with the data from MATs NAME$, CITY$, AGE and WEIGHT. The data arrays must all be dimensioned the same.
Line 199: Line 222:
The number of rows being output do not need to match the number of rows being replaced. To delete a range of rows, output one or more grouped arrays with zero elements.
The number of rows being output do not need to match the number of rows being replaced. To delete a range of rows, output one or more grouped arrays with zero elements.


Examples- Using the following statement various scenarios are described.
Examples:
 
PRINT FIELDS "7,8,LIST 10/75, RANGE": start, end, (MAT NAME$, MAT CITY$, MAT AGE, MAT WEIGHT)
 
Start=7, end=11, and the arrays have been DIMed to nine elements
 
Result- Nine rows replace five, and the total content of the control is expanded by 4 rows.
 
Start=7, end=11, and the arrays are DIMed to zero elements


PRINT FIELDS "7,8,LIST 10/75, RANGE": start, end, (MAT NAME$,
Result- Five rows are deleted, and the total size of the control is reduced by 5 rows.
                                          MAT CITY$, MAT AGE, MAT WEIGHT)


  Start=7, end=11, and the arrays have been DIMed to nine elements
Start=7, end=0 (anything less than 7), and the arrays are DIMed to support three rows
  Result- Nine rows replace five, and the total content of the control is
          expanded by 4 rows.


  Start=7, end=11, and the arrays are DIMed to zero elements
Result- Three rows are inserted ahead of row seven and the total content of the control is expanded by three rows
  Result- Five rows are deleted, and the total size of the control is
          reduced by 5 rows.


  Start=7, end=0 (anything less than 7), and the arrays are DIMed to
Start=5000, end={any value}, the control only has 482 rows, and the source arrays are DIMed to support eleven rows
          support three rows
  Result- Three rows are inserted ahead of row seven and the total content
          of the control is expanded by three rows


  Start=5000, end={any value}, the control only has 482 rows, and the source
Result- Eleven rows are appended to the end of the control and become rows 483 through 493.
          arrays are DIMed to support eleven rows
  Result- Eleven rows are appended to the end of the control and become
          rows 483 through 493.


=== Outputting Ranges of Cells===
=== Outputting Ranges of Cells===
Line 226: Line 246:
Ranges of cells may be output in conjunction with the CELL_RANGE keyword.
Ranges of cells may be output in conjunction with the CELL_RANGE keyword.


PRINT FIELDS "7,8,LIST 10/75, CELL_RANGE": start, end, (MAT NAME$,
PRINT FIELDS "7,8,LIST 10/75, CELL_RANGE": start, end, (MAT NAME$, MAT CITY$, MAT AGE, MAT WEIGHT)
                                          MAT CITY$, MAT AGE, MAT WEIGHT)
 
                                - or -
OR


PRINT FIELDS "7,8,GRID 10/75, CELL_RANGE": start, end, MAT Data$
PRINT FIELDS "7,8,GRID 10/75, CELL_RANGE": start, end, MAT Data$


In this case, start and end specify cells instead of rows. If insertion or deletion is indicated by dimensioning the data arrays to greater or fewer elements than are being replaced, then the data must be a multiple of the number of columns. Insertion and deletion is only valid in terms
In this case, start and end specify cells instead of rows. If insertion or deletion is indicated by dimensioning the data arrays to greater or fewer elements than are being replaced, then the data must be a multiple of the number of columns. Insertion and deletion is only valid in terms
of rows, even when cell subscripts are used to specify ranges. In such cases, if the cell subscripts are not on row boundaries, an error is generated.
of rows, even when cell subscripts are used to specify ranges. In such cases, if the cell subscripts are not on row boundaries, an error is generated.


PRINT FIELDS "7,8,GRID 10/75, CELL_RANGE": start, start, Data$
PRINT FIELDS "7,8,GRID 10/75, CELL_RANGE": start, start, Data$
 
In this example, the value in one cell is replaced with the content of a scalar.
In this example, the value in one cell is replaced with the content of a scalar.


=== Using Arrays For RANGE Specification===
=== Using Arrays For RANGE Specification===
Line 250: Line 269:


An example of this is:
An example of this is:
  100 -- create and populate a GRID --
100 ! create and populate a GRID
  ........
150 ! Reading subscripts does not reset the CHG flags in the control
  200 INPUT FIELDS "row,col,GRID rows/cols,ROWSUB,CHG": MAT Rowsubs
200 INPUT FIELDS "row,col,GRID rows/cols,ROWSUB,CHG": MAT Rowsubs
        (Reading subscripts does not reset the CHG flags in the control.)
205 ! BR redimensions the receiving arrays as needed. Reading the data also resets the CHG flags in the control.
  210 INPUT FIELDS "row,col,GRID rows/cols,ROW,CHG,NOWAIT": ( MAT Data1$,
210 INPUT FIELDS "row,col,GRID rows/cols,ROW,CHG,NOWAIT": ( MAT Data1$, MAT Data2, MAT Data3$ )
                                  MAT Data2, MAT Data3$ )
220 ! process the changed rows now present in the data arrays --
          BR redimensions the receiving arrays as needed.
300 PRINT FIELDS "row,col,GRID rows/cols,RANGE": MAT Rowsubs, MAT Rowsubs, ( MAT Data1$, MAT Data2, MAT Data3$ )
        (Reading the data also resets the CHG flags in the control.)
 
  220 -- process the changed rows now present in the data arrays --
  ........
  300 PRINT FIELDS "row,col,GRID rows/cols,RANGE": MAT Rowsubs,
                  MAT Rowsubs, ( MAT Data1$, MAT Data2, MAT Data3$ )


This outputs the updated rows.
This outputs the updated rows.
Line 269: Line 282:
ROW/COL and ROWS/COLS in FIELDS operations may be expressed as decimal fractions.
ROW/COL and ROWS/COLS in FIELDS operations may be expressed as decimal fractions.


== LOGGING ENHANCEMENTS==
== LOGGING ==
The debug versions of BR now expect you to use a LOGGING configuration statement. This enables BR to post exit messages during unexpected terminations.
{{:Logging}}


A system function called DEBUG_STR( message-level, string-value ) will, depending on LOG LEVEL, send data to the LOGGING file as well as to the MyEditBR debugger if it is attached, or optionally to the command console if the debugger is not attached and GUI is ON. This lets you freely put trace related informational statements into your code without affecting normal processing. 
== CSV AND XML PARSING ENHANCEMENTS==


The LOGGING configuration statement now has two additional optional parameters:
The [[STR2MAT]] and [[MAT2STR]] functions have been extended to ease parsing of CSV and XML data.


  LOGGING  loglevel,  logfile  [ ,DEBUG_LOG_LEVEL=nn ]  [ ,+CONSOLE ]
STR2MAT function splits a string into an array.


Note- Logfile is a native OS filename.  Second and subsequent occurrences of the LOGGING statement may omit loglevel and the log filename.
MAT2STR function joins an array into a string.
DEBUG_LOG_LEVEL specifies the log level for debugging log messages Independently of the standard log level. If not specified the Debug_Log_Level is set to the standard log level.


+CONSOLE applies only when GUI is ON and specifies that all logging messages also go to the console and the console is to be left visible when not attached to MyEditBR. ( Console logging output is suppressed when GUI is OFF. )
STR2MAT( str$, MAT zzz$ [, [MAT] Sep$ [, flags$]] )


Message Levels are compared with Log Levels during the filtering process. The Logging Level is meant to specify the level of detail to be logged, with greater detail logged at higher log levels. 
Where Sep$ may be an array and flag$ is in the format:


The following types of messages are written to the LOGGING file:
[ quote-type ] [ :LTRM ] | [ :TRIM ] | [ :RTRM ]


Config error messages based on their assigned level of importance.
Where quote-type can be Q, QUOTES, ('), or ("), case insensitive. Q and QUOTES denote standard BR quote processing. The trim flags denote post processing of extracted elements and the leading colon is only present when quote-type is specified.


DEBUG_STR() messages where message-level is equal to or less than the DEBUG_LOG_LEVEL.
When Sep$ is an array, then any or all of the specified values are deemed to represent a single separator with the qualification that any one separator, cannot occur more than once in a string of adjacent separators. To restate this, when elements of a Sep$ array occur adjacent to each other within the source string, they are grouped as a separator substring.


Log levels 0, 1, 2 and 3-
Sep$ elements cannot occur more than once in a separator substring. When they do, it denotes the specification of a null element. e.g. two successive commas or two successive occurrences of CR+LF both denote null elements. Essentially when Sep$ elements are 'consumed' by their recognition within the source string, then they cannot be re-recognized without inserting a null element into the output array.  
  System generated warning messages such as OS failures and abnormal exits.
Log level 5 or above-
  User Logon data, including any logon attempts.
Log level 6 or above-
  Starting a BR program, exiting.
Log level 8 or above-
  Commands such as COPY plus shell calls with parameters.  
  PDF printing events.
Log level 11 or above-
  Any PRINT output that goes to the console is also logged (GUI ON only).
Log level 12 or above-
  TRACE, and DISPLAY messages.
Log level 13 or above-
  Lots of what the system is doing now messages.


Any DEBUG_STR() calls with a level >10 are deemed to be message level 10.
=== Quote Processing ===
 
Logging was added to PDF creation. Logging of minor events that happen during the printing process are logged at log level 8.  Errors are logged at a lower level. Logging was also improved with respect to loading older versions of pdflib.
Note- As a diagnostic, the following command is quite useful:
DIR >PDF:/READER
 
ODBC Logging was substantially increased.
 
Log Level Indication is given in Log Messages:
  (6) - 08/25/2011 11:33:53
Setting logging to log file logfile.txt log level 10.
  (6) - 08/25/2011 11:33:53
The BRConfig.sys file is C:\Users\dan\programs\cygwin\home\dan\br-wx\br\winbuild\dllbuild\output\brconfig.sys
The (6) here is the log level.


Quotation marks suppress the recognition of separators in accordance with the following rules.


== CSV AND XML PARSING ENHANCEMENTS==
Standard BR Quote Processing:
The string to mat and mat to string functions have been extended to ease parsing of CSV and XML data.


STR2MAT( str$, MAT zzz$ [, [MAT] Sep$ [, flags$]] )
Where Sep$ may be an array and flag$ is in the format:
[ quote-type ] [ :LTRM ] | [ :TRIM ] | [ :RTRM ]
Where quote-type can be Q, QUOTES, ('), or ("), case insensitive. Q and QUOTES denote standard BR quote processing. The trim flags denote post processing of extracted elements and the leading colon is only present when quote-type is specified.
When Sep$ is an array, then any or all of the specified values are deemed to represent a single separator with the qualification that any one separator, cannot occur more than once in a string of adjacent separators. To restate this, when elements of a Sep$ array occur adjacent to each other within the source string, they are grouped as a separator substring.
Sep$ elements cannot occur more than once in a separator substring. When they do, it denotes the specification of a null element.  e.g. two successive commas or two successive occurrences of CR+LF both denote null elements. Essentially when Sep$ elements are 'consumed' by their recognition within the source string, then they cannot be re-recognized without inserting a null element into the output array.
=== Quote Processing ===
Quotation marks suppress the recognition of separators in accordance with the following rules.
Standard BR Quote Processing
When examining str$ left to right, the first character (and the first character after each separator) is checked to see if is either (') or ("). If it is either of those then it activates quotation processing which suppresses the recognition of separators until quotation processing is deactivated. The first character thus becomes the governing quote type until quotation processing is deactivated.
When examining str$ left to right, the first character (and the first character after each separator) is checked to see if is either (') or ("). If it is either of those then it activates quotation processing which suppresses the recognition of separators until quotation processing is deactivated. The first character thus becomes the governing quote type until quotation processing is deactivated.


The string is copied until it ends or until an odd number of successive occurrences of the governing quote type is encountered. During this processing, two adjacent occurrences of the governing quote character denote an embedded occurrence of the quote character.
The string is copied until it ends or until an odd number of successive occurrences of the governing quote type is encountered. During this processing, two adjacent occurrences of the governing quote character denote an embedded occurrence of the quote character.
Examples
Examples
"abc,def" -> abc,def    where the comma is not recognized as a separator and is part of the data
"abc,def" -> abc,def    where the comma is not recognized as a separator and is part of the data
abc"def -> abc"def    naturally embedded quotes may occur anywhere within a string after the first character
abc"def -> abc"def    naturally embedded quotes may occur anywhere within a string after the first character
"abc"def" -> abcdef"  quotation processing is deactivated by the center quote mark
"abc"def" -> abcdef"  quotation processing is deactivated by the center quote mark
"abcdef" -> abcdef  normal data
"abcdef" -> abcdef  normal data
"abc'def" -> abc'def  the single quote is treated like any other character while double quotes govern
"abc'def" -> abc'def  the single quote is treated like any other character while double quotes govern
'abc"def' -> abc"def  double quotes are treated like any other character while single quotes govern
'abc"def' -> abc"def  double quotes are treated like any other character while single quotes govern
"abc""def" -> abc"def  pairs of governing quotes denote a single embedded quote
"abc""def" -> abc"def  pairs of governing quotes denote a single embedded quote
"abc"""def" -> abc"def"  the third successive occurrence deactivates quote processing which began with the first quote
"abc"""def" -> abc"def"  the third successive occurrence deactivates quote processing which began with the first quote


MAT2STR( MAT zzz$, str$ [, sep$ [, flags$]] )
MAT2STR( MAT zzz$, str$ [, sep$ [, flags$]] )
Where flag$ is in the format:
Where flag$ is in the format:
[ quote-type ] [ :LTRM ] | [ :TRIM ] | [ :RTRM ]
[ quote-type ] [ :LTRM ] | [ :TRIM ] | [ :RTRM ]
Where quote-type can be Q, QUOTES, ('), or ("), case insensitive. Quote-type denotes that each element should be enclosed in quotation marks. The trim flags denote pre-processing of array elements and the leading colon is only present when quote-type is specified.
Where quote-type can be Q, QUOTES, ('), or ("), case insensitive. Quote-type denotes that each element should be enclosed in quotation marks. The trim flags denote pre-processing of array elements and the leading colon is only present when quote-type is specified.
If Q or QUOTES is specified then BR automatically determines which quote type to apply as follows:
If Q or QUOTES is specified then BR automatically determines which quote type to apply as follows:
First the element is unpacked. That is, if it is contained in quotes, the quotes are stripped and embedded pairs are singled. Next the element is scanned left to right for either type of quote character ( single or double ). If a quote character is encountered the element is enclosed in the alternate quote type and embedded occurrences of that quote type are doubled. If no quote character is encountered then double quotes are applied.
First the element is unpacked. That is, if it is contained in quotes, the quotes are stripped and embedded pairs are singled. Next the element is scanned left to right for either type of quote character ( single or double ). If a quote character is encountered the element is enclosed in the alternate quote type and embedded occurrences of that quote type are doubled. If no quote character is encountered then double quotes are applied.
Examples
Examples
Quote Type is Q or QUOTES
Quote Type is Q or QUOTES
abcdef -> "abcdef"
abcdef -> "abcdef"
abc'def -> "abc'def"
abc'def -> "abc'def"
abc"def -> 'abc"def'
abc"def -> 'abc"def'
abc""def -> ‘abc""def’    embedded quotes are left intact when quotes are not active
abc""def -> ‘abc""def’    embedded quotes are left intact when quotes are not active
'abcdef -> "'abcdef"
'abcdef -> "'abcdef"


Quote Type is ' ( quote type single )
Quote Type is ' ( quote type single )
abcdef -> 'abcdef'
abcdef -> 'abcdef'
'abcdef -> '''abcdef'  single quotes get doubled when embedded in single quotes
'abcdef -> ' ' 'abcdef'  single quotes get doubled when embedded in single quotes
"abcdef -> '"abcdef'  leading double quote is treated normally
"abcdef -> '"abcdef'  leading double quote is treated normally


Quote type double mirrors quote type single.
Quote type double mirrors quote type single.
MAT2STR and STR2MAT trim outside of quotes but not inside of quotes. Also MAT2STR always adds quotes when quotes are present in the data.   
MAT2STR and STR2MAT trim outside of quotes but not inside of quotes. Also MAT2STR always adds quotes when quotes are present in the data.   
When using MAT2STR on a 2 dimensional array, the first delimiter is used for individual elements and the second delimiter at the end of each row. This principle also applies to three to seven dimensions.
When using MAT2STR on a 2 dimensional array, the first delimiter is used for individual elements and the second delimiter at the end of each row. This principle also applies to three to seven dimensions.
Line 387: Line 370:


=== CSV Parsing Example===
=== CSV Parsing Example===
Parsing CSV data files is now quite easy, the following code snippet demonstrates how to open a CSV/Tab File, read in the fields from the header, and then loop through  the records.
Parsing CSV data files is now quite easy.
  01000    dim CSV_LINE$*999,CSV_FILE$*256, CSV_DELIM$*1, CSV_HEADER$*999,  
 
CSV_FIELDS$(1)*40, CSV_DATA$(1)*60
To run the next code sample, first save the folowing text in a file named Sample_File.tab in your BR directory.
 
First, Last, Age, City
"Stas", "Kalban", 99, "Las Vegas"
"Mike", "Dugas",98, "Buenos Buenos"
"John", "Bubon", 96, "Hong Kong"
 
This code snippet demonstrates how to open a CSV/Tab File, read in the fields from the header, and then loop through  the records:
 
  01000    dim CSV_LINE$*999,CSV_FILE$*256, CSV_DELIM$*1, CSV_HEADER$*999, CSV_FIELDS$(1)*40, CSV_DATA$(1)*60
  01020    form C," "
  01020    form C," "
  01040    let CSV_FILE$="Sample_File.tab" : let TAB$=CHR$(9)
  01040    let CSV_FILE$="Sample_File.tab" : let TAB$=CHR$(9)
Line 407: Line 399:
  01320 Exit_Csv: !
  01320 Exit_Csv: !


You might wish to copy any CSV file to Sample_File.tab and run this program to view the content.
Alternatively, you could use any other valid CSV data, as long as the input file is named Sample_File.tab


=== XML Parsing Examples===
=== XML Parsing Examples===
Line 447: Line 439:


Notice that "Nested Nodes" are listed before the initial data, this may be used to identify the node.
Notice that "Nested Nodes" are listed before the initial data, this may be used to identify the node.


== NEW DLL STRUCTURE OF BUSINESS RULES!==
== NEW DLL STRUCTURE OF BUSINESS RULES!==


As of Release 4.3 Business Rules! has been restructured into the following modules:
As of Release 4.3 Business Rules! has been restructured into the following modules:
[[brserver.exe]] – The BR Server module accessed by Client-Server configurations. Brserver.exe also operates as what is now viewed as the Standard Model. If it is invoked by brlistener, then it act as brserver. If it is simply executed, it acts as brcombined. However, when operating as the standard model, it needs to have brclient.dll in the same directory as brserver.
*[[brserver.exe]] – The BR Server module accessed by Client-Server configurations. Brserver.exe also operates as what is now viewed as the Standard Model. If it is invoked by brlistener, then it act as brserver. If it is simply executed, it acts as brcombined. However, when operating as the standard model, it needs to have brclient.dll in the same directory as brserver.
[[brclient.exe]] – The program that the user accesses in Client-Server configurations
*[[brclient.exe]] – The program that the user accesses in Client-Server configurations
[[brclient.dll]] – The client processing program that correlates with the brserver edition.
*[[brclient.dll]] – The client processing program that correlates with the brserver edition.
[[npbrclient.dll]] - The standard (non-IE) browser plugin dll
*[[npbrclient.dll]] - The standard (non-IE) browser plugin dll
[[iebrclient.dll]] – Internet Explorer plugin dll
*[[iebrclient.dll]] – Internet Explorer plugin dll


Client installation is done by placing brclient.exe and brclient.dll on the client system and referencing brclient.exe in an icon. Server installation is done by placing brserver.exe and brclient.dll on the server and referencing brserver.exe in the brlistener.conf file. Exe files may be renamed as desired. The name of the released brclient.dll modules will be lengthy and must not be changed because BR relies on the DLL names for version identification.  
Client installation is done by placing brclient.exe and brclient.dll on the client system and referencing brclient.exe in an icon. Server installation is done by placing brserver.exe and brclient.dll on the server and referencing brserver.exe in the brlistener.conf file. Exe files may be renamed as desired. The name of the released brclient.dll modules will be lengthy and must not be changed because BR relies on the DLL names for version identification.  
Line 462: Line 453:
You will need one of the following possible configurations:
You will need one of the following possible configurations:
* Workstation Standard Model
* Workstation Standard Model
* Server executable
** Server executable
* Workstation Client dll
** Workstation Client dll
* Linux Terminal Support
** Linux Terminal Support
* Server executable
** Linux Client dll ( .so )
* Linux Client dll ( .so )
 
* Client Server Model
* Client Server Model
* On Client Machine-
** On Client Machine-
* Client executable
*** Client executable
* Workstation Client dll
*** Workstation Client dll
* On Server
** On Server
* Server executable
*** Server executable
* Workstation Client dll
*** Workstation Client dll
* BR Listener installed
*** BR Listener installed
[ Linux Client dll for Linux terminal access ]
*** [ Linux Client dll for Linux terminal access ]


The 32 and 64 bit versions of servers and clients can be intermixed. However dlls must be the in same bit class as the modules that call them.  Put your BR bmp files ( drawsunk.bmp, startup.bmp etc. ) in the BR server executable directory.  
The 32 and 64 bit versions of servers and clients can be intermixed. However dlls must be the in same bit class as the modules that call them.  Put your BR bmp files ( drawsunk.bmp, startup.bmp etc. ) in the BR server executable directory.  
Line 497: Line 488:
Client Dlls for uploading as needed
Client Dlls for uploading as needed
System Image files – linedraw, etc. - typically BMPs
System Image files – linedraw, etc. - typically BMPs
===) Exceptions===
 
=== Exceptions===


If [[WBcmd.wbh]] doesn't exist in the BR executable directory then BR looks for it in the initial directory specified by the first drive statement. ( deprecated – will be eliminated at some point)  ONQPATH currently defaults to this initial path as well. ( this will remain )
If [[WBcmd.wbh]] doesn't exist in the BR executable directory then BR looks for it in the initial directory specified by the first drive statement. ( deprecated – will be eliminated at some point)  ONQPATH currently defaults to this initial path as well. ( this will remain )
Line 504: Line 496:


The SPOOLPATH :OS-fullpath  configuration statement specifies where print spool files are temporarily stored during printing.  SPOOLPATH defaults to a spool directory that runs off of the BR root of the first drive statement. If no such spool directory exists and SPOOLPATH is not specified then BR creates one.
The SPOOLPATH :OS-fullpath  configuration statement specifies where print spool files are temporarily stored during printing.  SPOOLPATH defaults to a spool directory that runs off of the BR root of the first drive statement. If no such spool directory exists and SPOOLPATH is not specified then BR creates one.
e.g. DRIVE  J:, C:\BR, x, \MYAPP  would result in spool files being placed in:
 
C:\BR\SPOOL\
Example:
DRIVE  J:, C:\BR, x, \MYAPP  would result in spool files being placed in C:\BR\MYAPP\


SPOOLPATH @::client-OS-fullpath  specifies where on the client spool files are to be placed.   
SPOOLPATH @::client-OS-fullpath  specifies where on the client spool files are to be placed.   
  e.g.  SPOOLPATH  @::C:\BR\SPOOL  -or whatever other full path is desired-
 
Example:
SPOOLPATH  @::C:\BR\SPOOL  -or whatever other full path is desired-


The @:  tells BR that this path is on the client. The second colon says the path is independent of drive specifications.  
The @:  tells BR that this path is on the client. The second colon says the path is independent of drive specifications.  


WORKPATH defaults to the BR root of the first drive statement:
WORKPATH defaults to the BR root of the first drive statement:
e.g. C:\BR\
Example:
C:\BR\


BRconfig.sys INCLUDE statements are relative to the location of the file containing the INCLUDE statement ( the parent ).  CONFIG command INCLUDE statements are relative to the current directory at the time the command is issued.
BRconfig.sys INCLUDE statements are relative to the location of the file containing the INCLUDE statement ( the parent ).  CONFIG command INCLUDE statements are relative to the current directory at the time the command is issued.
Line 615: Line 611:
*BR_MODEL   “CLIENT/SERVER” or “COMBINED”
*BR_MODEL   “CLIENT/SERVER” or “COMBINED”


== NEW WORLD SQL SUPPORT==
== SQL SUPPORT==
The following are examples of SQL connection strings which can be placed inside of brconfig.sys file or executed dynamically from BR command line:
 
CONFIG DATABASE db-ref  DSN=dsn-ref  [, USER= department | LOGIN_NAME | ? ] [, {PASSWORD= dept-password | BR_PASSWORD | ?} | PASSWORDD=encrypted-passwd ]
 
? indicates a login or password prompt


CONFIG DATABASE db-ref  DSN=dsn-ref  [, USER= department | LOGIN_NAME | ? ]
    [, {PASSWORD= dept-password | BR_PASSWORD | ?} | PASSWORDD=encrypted-passwd ]
? indicates prompt
BR_PASSWORD indicates the password used during client login. If running the standard model ( not client-server ) then this is equivalent to “?”.
BR_PASSWORD indicates the password used during client login. If running the standard model ( not client-server ) then this is equivalent to “?”.
encrypted-passwd is the DB password encrypted with the key stated in OPTION 66.
encrypted-passwd is the DB password encrypted with the key stated in OPTION 66.
            - or -
CONFIG DATABASE db-ref  CONNECTSTRING="Driver={Microsoft Access Driver (*.mdb)}
e.g.      DBQ=C:\inetpub\wwwroot\BegASP\Chapter.14\Contact.mdb"
            - or -
CONFIG DATABASE ODBC-MANAGER
This will invoke the ODBC Manager to define or identify a file DSN.


OPEN #20: "DATABASE= db-ref" , SQL "sql-statement", OUTIN
CONFIG DATABASE db-ref CONNECTSTRING="Driver={Microsoft Access Driver (*.mdb)};DBQ=C:\inetpub\wwwroot\BegASP\Chapter.14\Contact.mdb;Uid=Admin;Pwd=abcd1234"
            - or -
 
OPEN #20: "DATABASE= db-ref, Name= filename" , SQL, OUTIN
The following will invoke the ODBC Manager to define or identify a file DSN.
    - filename refers to a DISPLAY file containing an SQL statement
 
      that gets executed when a WRITE statement is processed -
CONFIG DATABASE ODBC-MANAGER
 
Here are 2 methods of opening an SQL connection and execute a query in BR:
 
1) OPEN #20: "DATABASE= db-ref" , SQL "sql-statement", OUTIN
2) OPEN #20: "DATABASE= db-ref, Name= filename" , SQL, OUTIN
 
In method 2, filename refers to a DISPLAY file containing an SQL statement that gets executed when a WRITE statement is processed -


===Sequence of Operations===
===Sequence of Operations===


1. Begin processing with a WRITE statement.
1. Begin processing with a WRITE statement.
2. If the WRITE contains an IO list of values then it is used to populate the 'filename' SQL before it is executed. In this process IO list values replace question marks in the original SQL, positionally left to right.  These question marks only work with SQL arguments that refer to stored data. Question marks cannot be specified where SQL keywords or table column names appear.  
2. If the WRITE contains an IO list of values then it is used to populate the 'filename' SQL before it is executed. In this process IO list values replace question marks in the original SQL, positionally left to right.  These question marks only work with SQL arguments that refer to stored data. Question marks cannot be specified where SQL keywords or table column names appear.  
3. This may or may not produce a result set. If it does, the result set may be processed like a BR file opened RELATIVE. Some operations that use file positioning may be slow since the whole result set may not be in memory immediately. Simple sequential access should be fairly quick.
3. This may or may not produce a result set. If it does, the result set may be processed like a BR file opened RELATIVE. Some operations that use file positioning may be slow since the whole result set may not be in memory immediately. Simple sequential access should be fairly quick.
4. Once SQL has been populated by an IOlist, it may be reused with the same values by issuing a WRITE with no IOlist.
4. Once SQL has been populated by an IOlist, it may be reused with the same values by issuing a WRITE with no IOlist.
5. READ IOlist variable associations are positional with each READ accessing one row of values.
5. READ IOlist variable associations are positional with each READ accessing one row of values.


Line 646: Line 649:


A$ = SQL_DATE$(BR-date-string,"format-mask")    ! format date for storage
A$ = SQL_DATE$(BR-date-string,"format-mask")    ! format date for storage
B$ = BR_DATE$( SQL-date-string,"format-mask")  ! unpack DB date value
B$ = BR_DATE$( SQL-date-string,"format-mask")  ! unpack DB date value
* Note: SQL DATETIME fields are "Packed for Storage", but "DATE" fields are returned as a CCYY-MM-DD string in a SQL Query.
DATE returns "BLANK" for "Empty or Null Date"


=== SQL Table Interrogation===
=== SQL Table Interrogation===
Line 720: Line 728:
===Overview===
===Overview===


1. Symmetric key ciphers – where the same key is used to encrypt and decrypt data.  You can specify a key to encrypt some data and later use the same key to decrypt the data.
# Symmetric key ciphers – where the same key is used to encrypt and decrypt data.  You can specify a key to encrypt some data and later use the same key to decrypt the data.
 
# Hashing routines – one way routines that take data and convert it to a hash value.  Sometimes these are thought of as checksums such as MD5 sum.  Hash values are always the same length regardless of how big the hashed data is.  A 10 gb file will have a hash result that is the same length as a 200 byte file.  Hashing routines have a number of specific uses.
2. Hashing routines – one way routines that take data and convert it to a hash value.  Sometimes these are thought of as checksums such as MD5 sum.  Hash values are always the same length regardless of how big the hashed data is.  A 10 gb file will have a hash result that is the same length as a 200 byte file.  Hashing routines have a number of specific uses.
## Verify that data has not changed.
 
## Verifying that two files are the same.
1. Verify that data has not changed.
## Validating passwords – this is based on the concept that if two values have the same hash value the values are equal.  Using this technique improves security because it allows a server to store passwords in an unrecoverable format.  Even the server software is unable to regenerate the original password.  It is only capable of checking if the hash of a password matches the stored password hash.
 
2. Verifying that two files are the same.
 
3. Validating passwords – this is based on the concept that if two values have the same hash value the values are equal.  Using this technique improves security because it allows a server to store passwords in an unrecoverable format.  Even the server software is unable to regenerate the original password.  It is only capable of checking if the hash of a password matches the stored password hash.
 


===Symmetric Key Ciphers===
===Symmetric Key Ciphers===
Line 749: Line 752:
=== Interfacing With Other Programs (encryption type and initialization vector)===
=== Interfacing With Other Programs (encryption type and initialization vector)===


There are a number of different types of encryption that BR supports through OpenSSL:  AES, BLOWFISH, DES, triple DES, RC4 and RC2.  Most symmetric key ciphers are block ciphers meaning that they encrypt one block at a time.  This means if you have a bit message, it is broken up into multiple blocks and each block is encrypted.  The block size can be set as (128, 192, 256) bits.  Some encryption types don't support all of these values so STATUS ENCRYPTION should be checked to see what encryption types are available in BR.  Besides block size, there are also various schemes for blocking data.  One might expect that using 256 bit blocking would simply take every 32 bytes and call it a block.  This is not done though because there is a possibility that this would cause patterns in the encrypted data.  To prevent this, there are various schemes known as codebooks which change the way data is blocked.  Wikipedia explains this in more detail.  If the encryption type is not specified AES:256:CBC:128 will be used.  To be compatible with other programs the entire encryption type must be specified (cipher: key length: codebook: invitialization vector length).
There are a number of different types of encryption that BR supports through OpenSSL:  AES, BLOWFISH, DES, triple DES, RC4 and RC2.  Most symmetric key ciphers are block ciphers meaning that they encrypt one block at a time.  This means if you have a bit message, it is broken up into multiple blocks and each block is encrypted.  The block size can be set as (128, 192, 256) bits.  Some encryption types don't support all of these values so STATUS ENCRYPTION should be checked to see what encryption types are available in BR.  Besides block size, there are also various schemes for blocking data.  One might expect that using 256 bit blocking would simply take every 32 bytes and call it a block.  This is not done though because there is a possibility that this would cause patterns in the encrypted data.  To prevent this, there are various schemes known as codebooks which change the way data is blocked.  [https://en.wikipedia.org/wiki/OpenSSL Wikipedia] explains this in more detail.  If the encryption type is not specified AES:256:CBC:128 will be used.  To be compatible with other programs the entire encryption type must be specified (cipher: key length: codebook: invitialization vector length).


Initialization-vector – this is used to cause the same data encrypted with the same key to have a different encrypted result.  This is significant because otherwise an attacker looking at data seeing the same encrypted result twice would know that the key and the unencrypted data have not changed.  Regardless of whether or not you are concerned about this potential security issue, the standard encryption methods require this value so interfacing with other programs may require you to use it.  It is a common practice to use a random number for this value and store the value at the beginning of (ahead of) the encrypted result.  This is what BR does if this parameter is omitted.
Initialization-vector – this is used to cause the same data encrypted with the same key to have a different encrypted result.  This is significant because otherwise an attacker looking at data seeing the same encrypted result twice would know that the key and the unencrypted data have not changed.  Regardless of whether or not you are concerned about this potential security issue, the standard encryption methods require this value so interfacing with other programs may require you to use it.  It is a common practice to use a random number for this value and store the value at the beginning of (ahead of) the encrypted result.  This is what BR does if this parameter is omitted.
Line 758: Line 761:


If the initialization vector is explicitly specified as in:
If the initialization vector is explicitly specified as in:
ENCRYPT$(“test”, “key”, “AES:256:CBC:128”, “RANDOM”)  
 
ENCRYPT$(“test”, “key”, “AES:256:CBC:128”, “RANDOM”)  
 
the result would be simply “encrypted result”.
the result would be simply “encrypted result”.


Line 767: Line 772:
Three common forms of hashing are allowed in BR.  They are MD5, SHA, and SHA-1.  These are also provided through the ENCRYPT$ function specifying a null key$ value:
Three common forms of hashing are allowed in BR.  They are MD5, SHA, and SHA-1.  These are also provided through the ENCRYPT$ function specifying a null key$ value:


ENCRYPT$(data$, “”, “MD5”)
ENCRYPT$(data$, “”, “MD5”)
ENCRYPT$(data$, “”, “SHA”)
ENCRYPT$(data$, “”, “SHA”)
ENCRYPT$(data$, “”, “SHA-1”)
ENCRYPT$(data$, “”, “SHA-1”)


Hashing is also referred to as Message Digests or digests.  This is what the MD in MD5 means.  There is no way to restore data that has been hashed.  Hashing is a one way function so DECRYPT$ will yield an error.
Hashing is also referred to as Message Digests or digests.  This is what the MD in MD5 means.  There is no way to restore data that has been hashed.  Hashing is a one way function so DECRYPT$ will yield an error.


=== Asymmetric Encryption===
=== Asymmetric Encryption===
Line 792: Line 796:
Encryption is invoked by Business Rules HTTP support as follows:
Encryption is invoked by Business Rules HTTP support as follows:


  CONFIG HTTPS PORT port-number  [ LOG file-pathname ]
  CONFIG HTTPS port-number  [ LOG file-pathname ] [CERT= cert-file-basename]
  CONFIG OPTION  66  private-key-file-encryption-password
  CONFIG OPTION  66  private-key-file-encryption-password
  OPEN #400: “HTTP=SERVER”, DISPLAY, OUTIN
  OPEN #400: “HTTP=SERVER”, DISPLAY, OUTIN
Line 801: Line 805:


These files are made by the following commands under Linux, MAC and cygwin for Windows:
These files are made by the following commands under Linux, MAC and cygwin for Windows:
openssl req -new -x509 -out httpserver.pem -days 10000
 
openssl req -new -x509 -out httpserver.pem -days 10000


( this will prompt for the OPTION 66 password )
( this will prompt for the OPTION 66 password )
Line 808: Line 813:
  mv httpserver.pem  https-cert.pem
  mv httpserver.pem  https-cert.pem


This port specific service can then be accessed with browsers. When the specified port is accessed through a browser, BR establishes an HTTPS connection rather than an HTTP connection.
This port specific service can then be accessed with browsers. When the specified port is accessed through a browser, BR establishes an HTTPS connection rather than an HTTP connection.


=== Signing and Certificate Processing Industry Standards===
=== Signing and Certificate Processing Industry Standards===
Line 835: Line 840:


Improved installation routines:
Improved installation routines:
Easy to use
*Easy to use
Compatible with Windows Vista/7
*Compatible with Windows Vista/7
Compatible with 64 Bit Machines (both 32 and 64 bit drivers).
*Compatible with 64 Bit Machines (both 32 and 64 bit drivers).
Easily create DNS entries from the CONTEXT using a BR program called CREATE_INI.BR. (You will need to tailor the resulting INI file to the target setting.)
*Easily create DNS entries from the CONTEXT using a BR program called CREATE_INI.BR. (You will need to tailor the resulting INI file to the target setting.)
Installation on a client can be done from a command line avoiding the need for human interaction at the client.  
*Installation on a client can be done from a command line avoiding the need for human interaction at the client.  
 
 
 
 
 
 
 


Support for 64 bit Record Locking (No 2GB Limit!).
Other improvements:
Implemented Dynamic (on the fly) Indexes.
*Support for 64 bit Record Locking (No 2GB Limit!).
The ODBC splash screen has been removed.
*Implemented Dynamic (on the fly) Indexes.
*The ODBC splash screen has been removed.


ODBC Logging:
ODBC Logging:
Line 890: Line 889:
=== New Procedure for Utilizing MS Access ODBC Middleware ===
=== New Procedure for Utilizing MS Access ODBC Middleware ===


A procedure has been established for greatly expanding the SQL capabilities of the BR ODBC driver by routing ODBC requests through MS Access. Using this technique one can create reusable queries that combine several tables. This procedure is described in the installation guide.  
A procedure has been established for greatly expanding the SQL capabilities of the BR ODBC driver by routing ODBC requests through MS Access. Using this technique one can create reusable queries that combine several tables. This procedure is described in the installation guide.
 


==  PRINT FONT STRETCHING==
==  PRINT FONT STRETCHING==
Line 902: Line 900:


Relative Font Heights ( height to width ratios ):
Relative Font Heights ( height to width ratios ):
    Native Courier New  1.6 - available in PCL -
*Native Courier New  1.6 - available in PCL
    Native Letter Gothic  2.0 - available in PCL -
*Native Letter Gothic  2.0 - available in PCL
    Stretched Fonts 2.6 - NWP and PDF only -
*Stretched Fonts 2.6 - NWP and PDF only


The 1.6, 2.0, 2.6 are ratios.  For Courier New the 1.6 means that the font is 1.6 times as high as it is wide.  PCL measures all fixed width fonts in width and calculates the height based on these ratios.  So for Courier New a 10 CPI font would be 1.6 * (1 / 10)(CPI) * 72 (points per inch) = 11.52 points.  Actually the ratio for Courier New appears to be 1.66666666.  This would mean that 1.66666666 * (1/10) * 72 = 12 points.
The 1.6, 2.0, 2.6 are ratios.  For Courier New the 1.6 means that the font is 1.6 times as high as it is wide.  PCL measures all fixed width fonts in width and calculates the height based on these ratios.  So for Courier New a 10 CPI font would be 1.6 * (1 / 10)(CPI) * 72 (points per inch) = 11.52 points.  Actually the ratio for Courier New appears to be 1.66666666.  This would mean that 1.66666666 * (1/10) * 72 = 12 points.


==  EXTENDED DATE / TIME FUNCTIONS==
==  EXTENDED DATE / TIME FUNCTIONS==
Line 923: Line 920:


Extended Date Mask Examples:
Extended Date Mask Examples:
 
DATE( “Month dd, ccyy at H#.## hours”)  ->  September 12, 2011 at 14.58 hours
DATE( “Month dd, ccyy at H#.## hours”)  ->  September 12, 2011 at 14.58 hours
DATE( “mm/dd/yy at H:M AM”)  ->  09/15/11 at 2:35 PM
DATE( “mm/dd/yy at H:M AM”)  ->  09/15/11 at 2:35 PM
DATE( “mon dd cy at H#:M# PM”)  ->  Sep 15 2011 at 02:35 PM
DATE( “mon dd cy at H#:M# PM”)  ->  Sep 15 2011 at 02:35 PM




Example of using DATE$ to get time to 9 decimal places:
Example of using DATE$ to get time to 9 decimal places:
 
Date$("H#:M#:S#.#########") -> 14:06:22.968419347
Date$("H#:M#:S#.#########") -> 14:06:22.968419347




Line 940: Line 935:
DATE(mask) can now be used as an INPUT FIELDS specification.
DATE(mask) can now be used as an INPUT FIELDS specification.


10 INPUT FIELDS “row, col, DATE(mask)  ,UH” : date-var
10 INPUT FIELDS “row, col, DATE(mask)  ,UH” : date-var


Special keyboard processing:
Special keyboard processing:
Line 969: Line 964:


A sample program to demonstrate date entry is:
A sample program to demonstrate date entry is:
01000 ! Rep Date_Input
01000 ! Rep Date_Input
01020 ! Demonstrate The New Date() Input Format
01020 ! Demonstrate The New Date() Input Format
01040 ! Skip Punctuation (Commas, Colons, Slashes, Semicolons, And Dashes)
01040 ! Skip Punctuation (Commas, Colons, Slashes, Semicolons, And Dashes)
01060 ! Insert And Delete Within Subfields That Are Delineated By Punctuation
01060 ! Insert And Delete Within Subfields That Are Delineated By Punctuation
01080 ! Continue To Support Cut And Paste Including Punctuation
01080 ! Continue To Support Cut And Paste Including Punctuation
01100 !  
01100 !  
01120    rinput fields "5,10,DATE(mm/dd/yy) ;6,10,c": DATE_VAR
01120    rinput fields "5,10,DATE(mm/dd/yy) ;6,10,c": DATE_VAR
01140    print fields "8,10,date(Month DD, CCYY)": DATE_VAR
01140    print fields "8,10,date(Month DD, CCYY)": DATE_VAR
01160 !  
01160 !  
01180    rinput fields "12,10,date(month dd, ccyy)": DATE_VAR
01180    rinput fields "12,10,date(month dd, ccyy)": DATE_VAR
01200    if NOT DATE_VAR then goto 1180
01200    if NOT DATE_VAR then goto 1180
01220    print fields "15,10,date(yy/mm/dd)": DATE_VAR  
01220    print fields "15,10,date(yy/mm/dd)": DATE_VAR  
01240    print fields "18,10,N 6": DATE_VAR  !Show days format
01240    print fields "18,10,N 6": DATE_VAR  !Show days format
       


==  NEW TEXT FIELD FORMAT==
==  NEW TEXT FIELD FORMAT==
Line 1,014: Line 1,020:
*Left-Arrow/Up-Arrow – Goes to the prior control
*Left-Arrow/Up-Arrow – Goes to the prior control
*Right-Arrow/Down-Arrow – Goes to the next control
*Right-Arrow/Down-Arrow – Goes to the next control




Line 1,020: Line 1,025:




A sample program to demonstrate TEXT entry is:


A sample program to demonstrate TEXT entry is:
  01000 ! Rep Text
  01000 ! Rep Text
  01020 ! Test New Text Fiueld Type
  01020 ! Test New Text Fiueld Type
Line 1,030: Line 1,035:
  01120    print TEXT$
  01120    print TEXT$
  01140    let STR2MAT(TEXT$, MAT TEXT$, CHR$(10))
  01140    let STR2MAT(TEXT$, MAT TEXT$, CHR$(10))
  1160 rint MAT TEXT$
  01160    print MAT TEXT$


==  INPUT ACROSS MULTIPLE WINDOWS==
==  INPUT ACROSS MULTIPLE WINDOWS==

Latest revision as of 17:15, 25 July 2020

Status: Beta

The prior versions were 4.1 and 4.2.

As Of 08/30/2012

MISCELLANEOUS ENHANCEMENTS

ON error-type IGNORE

ON error-type IGNORE now ignores the error instead of going to an Ignore label. This is effective for both ON statements and individual statement error exits. This could change the way your programs work if your Ignore statements do more than CONTINUE.

The general purpose ERROR exit implies SOFOW truncation. So statements that are governed by ERROR IGNORE also do SOFLOW truncation as needed.

For client / server configurations

SPOOLPATH @: client-pathname Sets the remote spool path on the client. In addition to regular spool files, this is where PDF files are created. SPOOLPATH can be set concurrently for both client and server by specifying two SPOOLPATH statements. The @: indicates remote.

The client-pathname has some unique characteristics: Paths are assumed to be OS pathnames relative to the CLIENT_CURRENT_DIR folder, or the startup directory if CLIENT_CURRENT_DIR is not specified. If a full pathname is specified it must begin with a colon. ( e.g. @::X:\path ) Otherwise it will be preceded with the path to the client current working directory. Specifying a relative remote pathname is not compatible with CLIENT_CURRENT_DIR SYNC. The status of SPOOLPATH and REMOTESPOOLPATH settings are displayed in response to the STATUS SUBSTITUTE command.

CHR$(6)

CHR$(6) is a field separator that displays as a space but causes the immediately preceding data to be right justified. This applies to both Native Windows Printing and PRINT FIELDS.

MAT2STR and STR2MAT

MAT2STR, STR2MAT changes to trim outside of quotes, but not inside of quotes and to always quote MAT2STR when quotes are present.

STATUS USERS

STATUS USERS will display the WSID and name of each user logged in on the network. The SQL statement SHOW USERS responds with the same information for ODBC users.

BRERR$

BRERR$ is a new system function that display the description of BR ERR value. BRERR$(error-code) returns the description of that code. Examples: When ERR returns 4270, BRERR$ will return “end of file”. BRERR$(0875) returns “unrecognized data after field specification”

ODBC

For making it easier to configure ODBC with BRconfig.sys and to setup common configuration files for multiple platforms we have added: @LINUX @WINDOWS @MAC @ODBC

For example, this could be important for DRIVE statements: @LINUX DRIVE C:,/unix/path,.,\ @WINDOWS DRIVE C:,\\server\path,.,\

Programs compiled with older versions of BR (3.3 – 3.8) can be listed accurately.


GRID AND LIST CHANGES

In list and grid controls, arrays are automatically resized when receiving data from 2D INPUT operations. This also applies to grouped arrays. Automatic resizing only applies to one dimensional arrays and does not occur when INPUTing into two dimensional arrays.

Example where all arrays are one dimensional and may have the incorrect number of elements:

INPUT FIELDS "row,col,LIST rows/cols, ROW, ALL" : ( MAT Array1$, MAT Array2$, MAT Array3, MAT Array4, MAT Array5$ )

Where all arrays are one dimensional and may have the incorrect number of elements.


Three New Read Types

Auto Resizing applies.

Selection Type must be ALL.

The original 2D INPUT read types are:

CNT - The number of cells specified.

SUB - Read the Cell Subscript Values.

CELL - Read each cell specified.

ROWCNT - The number of rows specified.

ROWSUB - The subscripts of the specified rows.

ROW - Read all cells in each specified row.

HEADERS - The original PRINT FIELDS HEADER values.

Example:

INPUT FIELDS "row,col,LIST rows/cols, HEADERS,,NOWAIT" :(MAT HEADINGS$,MAT WIDTHS, MAT FORMS$)

COLCNT - The number of columns established by the header arrays.

Example:

INPUT FIELDS "row,col,LIST rows/cols, COLCNT, ALL" : numeric-variable

These are for generalized library routines to inspect passed controls.

SORT_ORDER - Provides a value of zero for each unsorted column and gives the ascending sequence of column sorts that have occurred. If a column has been reversed (double sorted) it's value will be negative.

Example:

INPUT FIELDS "row,col,LIST rows/cols, SORT_ORDER, ALL" : numeric-array

Given the following history of sorting a four column GRID:

column 1 (descending most rescent)
column 2 (ascending first sorted)
column 3 (not sorted)
column 4 (sorted ascending)

SORT_ORDER would return

array(1) ->  -1
array(2) ->   3
array(3) ->   0
array(4) ->   2

Restoring a User Sorted 2D Control

The syntax for sorting an array is currently:

PRINT FIELDS "nn,nn,GRID 10/40,SORT": { column number }

This has been extended to allow a numeric array of instead of a scalar. If an array is given, it is assumed to be in the same format that SORT_ORDER returns. The new format is:

PRINT FIELDS "nn,nn,GRID 10/40,SORT": { column-number | numeric-array }

Where the numeric-array has one element for each column left to right. BR will resort the columns in the requested order.

The numeric array values indicating the order of column sorting to be performed do not need to exactly match the standard format. e.g Fractions are allowed, the values can fall within any range, and there does not need to be trailing zero elements for unsorted columns.

A new Read Qualifier is available.

The Displayed_Order list and grid read qualifier introduced in BR! 4.30. DISPLAYED_ORDER indicates that the read operation is to not restore the data into it's original order before returning the results to the program. For example:

INPUT FIELDS "row, col, LIST rows/cols, ROWSUB, ALL, DISPLAYED_ORDER, NOWAIT": numeric-array

This reads the original row subscripts for all rows in their present order. This qualifier works only with the ALL selection type. It may be used in conjunction with other qualifiers such as FKEY.


Masked 2D Display

LIST and GRID support the MASK operation-

PRINT FIELDS "row,col,LIST rows/cols,MASK" :  mask_array

This restricts the rows (for both LIST and GRID) previously displayed to those corresponding to a “true” value in mask_array. A true value is represented in a umeric array as a value greater than zero. Negative values are not allowed in mask arrays. A string mask array may also be used with “T” and “F” values. The MASK stays in effect until 1) a new MASK is specified or 2) the contents of the control are changed with PRINT ( =, +, - see Output Operations in New Console.DOC).

INPUT FIELDS "row,col,LIST rows/cols,MASK [,NOWAIT]" : mask_array This reads the display mask setting for a 2D control.

The mask array affects only the user presentation.. not the result set. Use RANGE processing or the CHG selection type to selectively read from a 2D control.

New Search Field Type: Filter

See Filter

New Config: Filter_Delimiters

See Filter_Delimiters

FIELDS CHARACTER BY CHARACTER KEYBOARD CONTROL

^KeyStroke and ^DataChg introduced.

RANGE SELECTION TYPE

Valid current selection types are:

SEL - Read one or more selected items.

SELONE - Select only one item.

ALL - Read all items in the control (except headings).

CUR - Current cell or row number.

CHG - All cells or rows who’s values have been changed by the operator.

BR now supports the following additional selection types:

RANGE - Specifies which portion of a 2D control is to be input.

CELL_RANGE – A special type of output range.


RANGE Input

In the following examples BR will redimension the receiving arrays as needed:

INPUT FIELDS "row, col, LIST rows/cols, CELL, RANGE": start, end, MAT Data$

This reads the specified range of cells. BR redimensions MAT Data$ as needed. Note that CELL may now be used with LIST. Previously, LISTs were only addressable by row.

INPUT FIELDS "row, col, LIST rows/cols, ROW, RANGE": (start:=7), (end:=11), ( MAT Array1$, MAT Array2, MAT Array3$ )

This reads the cells in rows 7 through 11. The receiving arrays are redimensioned as appropriate.

INPUT FIELDS "row, col, GRID rows/cols, ROW, RANGE": MAT start, MAT end, ( MAT Data1$, MAT Data2$, MAT Data3 )

This reads one or more ranges of rows.

A more detailed example of this is:

 100 ! create and populate a LIST control 
 200 MAT START(3) : MAT END(3)
 210 READ MAT START, MAT END
 220 DATA 7,21,33
 230 DATA 11,21,38
 240 INPUT FIELDS "row, col, LIST rows/cols, ROW, RANGE" : MAT START, MAT END, ( MAT Array1$, MAT Array2, MAT Array3$ )

This reads 12 rows of data ( row 7-11, row 21 and rows 33-38 ).

RANGE Output

By default, RANGE output refers to rows. The special keyword CELL_RANGE is used to denote the specification of cell ranges. Additionally, the use of scalars versus arrays for start and end values determines important characteristics of the output process.

Using Scalars For Range Specification

PRINT FIELDS "7, 8, GRID 10/75, RANGE": start, end, MAT Data$

This replaces the values in rows numbered 'start' through 'end' with the data in MAT Data$. The size of MAT Data$ must be a multiple of the number of columns in the GRID or an error is generated.

PRINT FIELDS "7, 8, LIST 10/75, RANGE": start, end, (MAT NAME$, MAT CITY$, MAT AGE, MAT WEIGHT)

This replaces the values in ROWs numbered 'start' through 'end' with the data from MATs NAME$, CITY$, AGE and WEIGHT. The data arrays must all be dimensioned the same.

Row Insertion and Deletion

The number of rows being output do not need to match the number of rows being replaced. To delete a range of rows, output one or more grouped arrays with zero elements.

Examples:

PRINT FIELDS "7,8,LIST 10/75, RANGE": start, end, (MAT NAME$, MAT CITY$, MAT AGE, MAT WEIGHT)

Start=7, end=11, and the arrays have been DIMed to nine elements

Result- Nine rows replace five, and the total content of the control is expanded by 4 rows.

Start=7, end=11, and the arrays are DIMed to zero elements

Result- Five rows are deleted, and the total size of the control is reduced by 5 rows.

Start=7, end=0 (anything less than 7), and the arrays are DIMed to support three rows

Result- Three rows are inserted ahead of row seven and the total content of the control is expanded by three rows

Start=5000, end={any value}, the control only has 482 rows, and the source arrays are DIMed to support eleven rows

Result- Eleven rows are appended to the end of the control and become rows 483 through 493.

Outputting Ranges of Cells

Ranges of cells may be output in conjunction with the CELL_RANGE keyword.

PRINT FIELDS "7,8,LIST 10/75, CELL_RANGE": start, end, (MAT NAME$, MAT CITY$, MAT AGE, MAT WEIGHT)

OR

PRINT FIELDS "7,8,GRID 10/75, CELL_RANGE": start, end, MAT Data$

In this case, start and end specify cells instead of rows. If insertion or deletion is indicated by dimensioning the data arrays to greater or fewer elements than are being replaced, then the data must be a multiple of the number of columns. Insertion and deletion is only valid in terms of rows, even when cell subscripts are used to specify ranges. In such cases, if the cell subscripts are not on row boundaries, an error is generated.

PRINT FIELDS "7,8,GRID 10/75, CELL_RANGE": start, start, Data$

In this example, the value in one cell is replaced with the content of a scalar.

Using Arrays For RANGE Specification

If the start and end specifications are arrays, denoting multiple ranges, there must be a one to one correspondence between the number of rows specified and those in the data. This method implies replacement only and insertion or deletion is not allowed.

The data flow that this feature was designed to support is one where the user is presented with a LIST or GRID where multiple rows have been either selected or changed before returning control to the program and the program is responding by updating something on those rows.

The program begins by presenting a 2D control to the user and reading the the control with type ROWSUB or SUB. Type SUB only works for GRIDs where all colmns have the same data type. Of course the subscripts are read into a numeric array which BR redimensions as appropriate. Then the program reads the changed or selected data with NOWAIT. (This resets the CHG flags in the control.) The program then changes either row (ROWSUB) or cell (SUB) data and outputs the results using the subscript array as both the start and end specification. Other scenarios are possible but this is the primary intended use.

An example of this is:

100 ! create and populate a GRID
150 ! Reading subscripts does not reset the CHG flags in the control
200 INPUT FIELDS "row,col,GRID rows/cols,ROWSUB,CHG": MAT Rowsubs
205 ! BR redimensions the receiving arrays as needed. Reading the data also resets the CHG flags in the control.
210 INPUT FIELDS "row,col,GRID rows/cols,ROW,CHG,NOWAIT": ( MAT Data1$, MAT Data2, MAT Data3$ )
220 ! process the changed rows now present in the data arrays --
300 PRINT FIELDS "row,col,GRID rows/cols,RANGE": MAT Rowsubs, MAT Rowsubs, ( MAT Data1$, MAT Data2, MAT Data3$ )

This outputs the updated rows.

FINE GRAIN FIELD POSITIONING

ROW/COL and ROWS/COLS in FIELDS operations may be expressed as decimal fractions.

LOGGING

As of 4.3, the debug versions of BR now expect you to use a LOGGING configuration statement. This enables BR to post exit messages during unexpected terminations.

The Logging config statement is provided for logging configuration errors, and should be placed in BRConfig.sys:

LOGGING <loglevel>, <native-OS-logfile-name> [, UNATTENDED] [, DEBUG_LOG_LEVEL=<integer>] [, +CONSOLE]


Loglevel is the maximum level of detail to be logged. The Logging Level is meant to specify the level of detail to be logged, with greater detail logged at higher log levels:

0 MAJOR_ERROR causes major problems during execution
1 NOTABLE_ERROR unexpected error likely to cause problems

System generated warning messages such as OS failures and abnormal exits.

2 MINOR_ERROR unexpected error that can be ignored

System generated warning messages such as OS failures and abnormal exits.

3 MAJOR_EVENT starting program, exiting, shelling ...

System generated warning messages such as OS failures and abnormal exits.

4 SECURITY_EVENT logons, logon attempts etc
5 MINOR_EVENT individual commands ...

User Logon data, including any attempts.

6 Starting a BR program, exiting.
8 Commands such as COPY plus shell calls with parameters.
9 DEBUGGING_EVENT added for debugging purposes
11 Any PRINT output that goes to the console is also logged (GUI ON only).
12 TRACE, and DISPLAY messages.
13 Lots of what the system is doing now messages.


Logfile denotes where the logging records will be kept. Note that Logfile is a native OS filename. Second and subsequent occurrences of the LOGGING statement may omit loglevel and logfile.

The UNATTENDED keyword will cause BR to run in unattended mode, without a startup screen and until a program begins to await operator input, when it will exit. Config LOGGING loglevel logfile [UNATTENDED] is now supported on linux (4.2) and this will exit BR if the program starts to wait for keyboard entry.

DEBUG_LOG_LEVEL (available as of 4.3) specifies the log level for debugging log messages independently of the standard log level. If not specified, the Debug_Log_Level is set to the standard loglevel.

+CONSOLE (4.3) applies only when GUI is ON and specifies that all logging messages also go to the console and the console is to be left visible when not attached to MyEditBR. (Console logging output is supressed when GUI is OFF.)

Examples

LOGGING 2, logfile

shows unsupported escape sequences encountered.

LOGGING 5, logfile

shows unsupported escape sequences encountered plus intentionally ignored escape sequences.

LOGGING 2, logfile ,UNATTENDED

shows unsupported escape sequences encountered, and runs BR in 'Unattended' mode, bypassing start-up screen and terminating BR at the end of processing or when input is required. Supported in 4.18 in Windows and 4.20 under Linux.

 LOGGING ,,UNATTENDED

runs in Unattended mode without log file.

Any config messages that occur after this config statement will be sent only to the logfile, mostly with NOTABLE_ERROR. It avoids displaying those REMed out statements in front of operators.

Any config messages that occur before the config statement logging will be sent only to the screen. These will cause BR to pause a few seconds so that the messages can be viewed.

Logging Messages (4.3)

Message Levels are compared with Log Levels during the filtering process. Like log levels, there is greater detail logged at higher log levels:

The following types of messages are written to the LOGGING file:

1. Config error messages based on their assigned level of importance.

2. DEBUG_STR() messages where message-level is equal to or less than the DEBUG_LOG_LEVEL:

Log levels 0, 1, 2 and 3 System generated warning messages such as OS failures and abnormal exits.
Log level 5 or above User Logon data, including any logon attempts.
Log level 6 or above Starting a BR program, exiting.

Any DEBUG_STR() calls with a level >10 are deemed to be message level 10.

Commands such as COPY plus shell calls with parameters are logged with system generated warning messages such as OS failures and abnormal exits.

LOGGING PDF printing events

Logging was added to PDF creation. Logging of minor events that happen during the printing process are logged at log level 8. Errors are logged at a lower level. Logging was also improved with respect to loading older versions of pdflib. Note- As a diagnostic, the following command is quite useful: DIR >PDF:/READER

The following messages are written to the LOGFILE:

Log level 11 or above Any PRINT output that goes to the console is also logged (GUI ON only).
Log level 12 or above TRACE, and DISPLAY messages.
Log level 13 or above Lots of what the system is doing now messages.
Examples

Log Level Indication is given in Log Messages The (6) here is the log level:

 (6) - 08/25/2011 11:33:53

Setting logging to log file logfile.txt log level 10.

 (6) - 08/25/2011 11:33:53

The BRConfig.sys file is C:\Users\dan\programs\cygwin\home\dan\br-wx\br\winbuild\dllbuild\output\brconfig.sys

See Also

Logging Abnormal Termination

A logging capability is provided for handling BRServer failures. An error log file in the BRServer directory is appended to when a BRServer process is abnormally ended. Also, a client msgbox is displayed when an assertion failure or program crash occurs. On Unix systems, the system error log is also updated. Keepalive failures are also logged here.



CSV AND XML PARSING ENHANCEMENTS

The STR2MAT and MAT2STR functions have been extended to ease parsing of CSV and XML data.

STR2MAT function splits a string into an array.

MAT2STR function joins an array into a string.

STR2MAT( str$, MAT zzz$ [, [MAT] Sep$ [, flags$]] )

Where Sep$ may be an array and flag$ is in the format:

[ quote-type ] [ :LTRM ] | [ :TRIM ] | [ :RTRM ]

Where quote-type can be Q, QUOTES, ('), or ("), case insensitive. Q and QUOTES denote standard BR quote processing. The trim flags denote post processing of extracted elements and the leading colon is only present when quote-type is specified.

When Sep$ is an array, then any or all of the specified values are deemed to represent a single separator with the qualification that any one separator, cannot occur more than once in a string of adjacent separators. To restate this, when elements of a Sep$ array occur adjacent to each other within the source string, they are grouped as a separator substring.

Sep$ elements cannot occur more than once in a separator substring. When they do, it denotes the specification of a null element. e.g. two successive commas or two successive occurrences of CR+LF both denote null elements. Essentially when Sep$ elements are 'consumed' by their recognition within the source string, then they cannot be re-recognized without inserting a null element into the output array.

Quote Processing

Quotation marks suppress the recognition of separators in accordance with the following rules.

Standard BR Quote Processing:

When examining str$ left to right, the first character (and the first character after each separator) is checked to see if is either (') or ("). If it is either of those then it activates quotation processing which suppresses the recognition of separators until quotation processing is deactivated. The first character thus becomes the governing quote type until quotation processing is deactivated.

The string is copied until it ends or until an odd number of successive occurrences of the governing quote type is encountered. During this processing, two adjacent occurrences of the governing quote character denote an embedded occurrence of the quote character.

Examples

"abc,def" -> abc,def    where the comma is not recognized as a separator and is part of the data
abc"def -> abc"def    naturally embedded quotes may occur anywhere within a string after the first character
"abc"def" -> abcdef"   quotation processing is deactivated by the center quote mark
"abcdef" -> abcdef   normal data
"abc'def" -> abc'def   the single quote is treated like any other character while double quotes govern
'abc"def' -> abc"def   double quotes are treated like any other character while single quotes govern
"abc""def" -> abc"def   pairs of governing quotes denote a single embedded quote
"abc"""def" -> abc"def"   the third successive occurrence deactivates quote processing which began with the first quote

MAT2STR( MAT zzz$, str$ [, sep$ [, flags$]] )

Where flag$ is in the format:

[ quote-type ] [ :LTRM ] | [ :TRIM ] | [ :RTRM ]

Where quote-type can be Q, QUOTES, ('), or ("), case insensitive. Quote-type denotes that each element should be enclosed in quotation marks. The trim flags denote pre-processing of array elements and the leading colon is only present when quote-type is specified.

If Q or QUOTES is specified then BR automatically determines which quote type to apply as follows: First the element is unpacked. That is, if it is contained in quotes, the quotes are stripped and embedded pairs are singled. Next the element is scanned left to right for either type of quote character ( single or double ). If a quote character is encountered the element is enclosed in the alternate quote type and embedded occurrences of that quote type are doubled. If no quote character is encountered then double quotes are applied.

Examples

Quote Type is Q or QUOTES

abcdef -> "abcdef"
abc'def -> "abc'def"
abc"def -> 'abc"def'
abc""def -> ‘abc""def’     embedded quotes are left intact when quotes are not active
'abcdef -> "'abcdef"

Quote Type is ' ( quote type single )

abcdef -> 'abcdef'
'abcdef -> ' ' 'abcdef'   single quotes get doubled when embedded in single quotes
"abcdef -> '"abcdef'   leading double quote is treated normally

Quote type double mirrors quote type single.

MAT2STR and STR2MAT trim outside of quotes but not inside of quotes. Also MAT2STR always adds quotes when quotes are present in the data. When using MAT2STR on a 2 dimensional array, the first delimiter is used for individual elements and the second delimiter at the end of each row. This principle also applies to three to seven dimensions. Example Given the following two dimensional array zzz$ containing the values-

   1            2
   3            4

The following statements-

   10 Sep$(1)=","
   20 Sep$(2)=hex$("0D0A") ! CRLF
   30 MAT2STR( MAT zzz$,  str$, MAT Sep$ )
   40 PRINT str$

Will produce-

   1,2
   3,4

CSV Parsing Example

Parsing CSV data files is now quite easy.

To run the next code sample, first save the folowing text in a file named Sample_File.tab in your BR directory.

First, Last, Age, City
"Stas", "Kalban", 99, "Las Vegas"
"Mike", "Dugas",98, "Buenos Buenos"
"John", "Bubon", 96, "Hong Kong"

This code snippet demonstrates how to open a CSV/Tab File, read in the fields from the header, and then loop through the records:

01000    dim CSV_LINE$*999,CSV_FILE$*256, CSV_DELIM$*1, CSV_HEADER$*999, CSV_FIELDS$(1)*40, CSV_DATA$(1)*60
01020    form C," "
01040    let CSV_FILE$="Sample_File.tab" : let TAB$=CHR$(9)
01060    open #(CSV_HANDLE:=10): "name="&CSV_FILE$&", shr", display,input 
01080    linput #CSV_HANDLE: CSV_HEADER$
01100    let CSV_DELIM$=TAB$
01120    if POS(CSV_HEADER$,TAB$) <= 0 then 
01140       let CSV_DELIM$=","
01160    end if 
01180    let STR2MAT(CSV_HEADER$, MAT CSV_FIELDS$, CSV_DELIM$, "QUOTES:TRIM")
01200    print using 1020: MAT CSV_FIELDS$
01220    do 
01240       linput #CSV_HANDLE: CSV_LINE$ eof Exit_Csv
01260       let STR2MAT(CSV_LINE$,MAT CSV_DATA$,CSV_DELIM$,"Q:trim")
01280       print using 1020: MAT CSV_DATA$
01300    loop 
01320 Exit_Csv: !

Alternatively, you could use any other valid CSV data, as long as the input file is named Sample_File.tab

XML Parsing Examples

STR2MAT may also be used to Parse XML data. This is a bit more complex than parsing CSV files, but remains a powerful tool. The following example will parse XML$ into "MAT XML_LINE$"

 10 DIM XML$*999999,XML_LINE$(1)*32000
 20 XML$="<XML><NODE><ITEM>ITEM VALUE</ITEM></NODE></XML>"
 100 LET Str2mat(XML$,Mat XML_LINE$,">","TRIM")

This makes the parsing of XML a bit more convenient. The following XML sample shows how the function will parse the data

Input:

 <XML><NODE><ITEM>ITEM VALUE</ITEM></NODE></XML>

Output:

 <XML
 <NODE
 <ITEM
 ITEM VALUE</ITEM
 </NODE
 </XML

While the above technique is useful, a more complete and useful technique can be performed if the Node names are known. You may use an array of SEP$ values to parse the data. Take the following example:

100    dim XML$*999999,XML_LINE$(1)*32000,SEP$(4)*32
110    let XML$="<XML><NODE><ITEM>ITEM VALUE</ITEM><ITEM2>ITEM2 VALUE</ITEM2></NODE></XML>"
120    read MAT SEP$
130    data </XML>,</NODE>,</ITEM>,</ITEM2>
140    let STR2MAT(XML$,MAT XML_LINE$,MAT SEP$,"TRIM")
150    print MAT XML_LINE$

This program would return the following results:

 <XML><NODE><ITEM>ITEM VALUE
 <ITEM2>ITEM2 VALUE

Notice that "Nested Nodes" are listed before the initial data, this may be used to identify the node.

NEW DLL STRUCTURE OF BUSINESS RULES!

As of Release 4.3 Business Rules! has been restructured into the following modules:

  • brserver.exe – The BR Server module accessed by Client-Server configurations. Brserver.exe also operates as what is now viewed as the Standard Model. If it is invoked by brlistener, then it act as brserver. If it is simply executed, it acts as brcombined. However, when operating as the standard model, it needs to have brclient.dll in the same directory as brserver.
  • brclient.exe – The program that the user accesses in Client-Server configurations
  • brclient.dll – The client processing program that correlates with the brserver edition.
  • npbrclient.dll - The standard (non-IE) browser plugin dll
  • iebrclient.dll – Internet Explorer plugin dll

Client installation is done by placing brclient.exe and brclient.dll on the client system and referencing brclient.exe in an icon. Server installation is done by placing brserver.exe and brclient.dll on the server and referencing brserver.exe in the brlistener.conf file. Exe files may be renamed as desired. The name of the released brclient.dll modules will be lengthy and must not be changed because BR relies on the DLL names for version identification.

You will need one of the following possible configurations:

  • Workstation Standard Model
    • Server executable
    • Workstation Client dll
    • Linux Terminal Support
    • Linux Client dll ( .so )
  • Client Server Model
    • On Client Machine-
      • Client executable
      • Workstation Client dll
    • On Server
      • Server executable
      • Workstation Client dll
      • BR Listener installed
      • [ Linux Client dll for Linux terminal access ]

The 32 and 64 bit versions of servers and clients can be intermixed. However dlls must be the in same bit class as the modules that call them. Put your BR bmp files ( drawsunk.bmp, startup.bmp etc. ) in the BR server executable directory.


Updates will pertain to Processor DLLs while the user interfaces will remain as installed. Client DLLs will be automatically uploaded when corresponding server DLLs are accessed in the event they are not already present on the client.

The client can be accessed from within a browser by initiating it with HTML which can specify an embedded window or a separate independent window. In all cases opening a window with PARENT=NONE creates a separate window.

BR Adjunctive Files

The BR executable is now considered to be where the BR server actually resides, irrespective of Drive statements and current working directories. 

The following files are located in the BR executable directory by default: BR server executable BRconfig.sys BRserial.dat BRserver.dat WBcmd.wbh - BR help files Server Dlls Client Dlls for uploading as needed System Image files – linedraw, etc. - typically BMPs

Exceptions

If WBcmd.wbh doesn't exist in the BR executable directory then BR looks for it in the initial directory specified by the first drive statement. ( deprecated – will be eliminated at some point) ONQPATH currently defaults to this initial path as well. ( this will remain )

If the BRconfig file is not present in the BR executable directory then BR looks for it in the current working directory at the time of BR invokation. 

The SPOOLPATH :OS-fullpath configuration statement specifies where print spool files are temporarily stored during printing. SPOOLPATH defaults to a spool directory that runs off of the BR root of the first drive statement. If no such spool directory exists and SPOOLPATH is not specified then BR creates one.

Example:

DRIVE   J:, C:\BR, x, \MYAPP   would result in spool files being placed in C:\BR\MYAPP\

SPOOLPATH @::client-OS-fullpath specifies where on the client spool files are to be placed.

Example:

SPOOLPATH  @::C:\BR\SPOOL  -or whatever other full path is desired-

The @: tells BR that this path is on the client. The second colon says the path is independent of drive specifications.

WORKPATH defaults to the BR root of the first drive statement: Example:

C:\BR\

BRconfig.sys INCLUDE statements are relative to the location of the file containing the INCLUDE statement ( the parent ). CONFIG command INCLUDE statements are relative to the current directory at the time the command is issued.


Licensing Restrictions

As of 4.20H, brserial files must be specific to the first decimal position of the release of BR that is being used. ( e.g. 4.2x versus 4.3x )

To accommodate more than one brserial level, BR first looks for its own suffix ( 42 or 43 ) before looking for a dat file. From now on it is most useful to name your brserial files either BRSERIAL.42 or BRSERIAL.43, etc.

CLIENT SERVER RECONNECT Configuration Statement

CLIENT_SERVER RECONNECT_AFTER=20 RECONNECT_TIME=120

BR sends idle packets between the client and the server every 2 seconds. This statement specifies that after 20 seconds of not receiving such packets BR will attempt to reconnect. This reconnect process can last up to a maximum of 120 seconds, after which BR will issue a “lost connection” error and begin processing in unattended mode.

You can change the above period lengths with the above CONFIG statement.

When BR runs unattended, it normally terminates processing if the program attempts to wait for keyboard input. However, after a lost connection error, if a library program attempts to wait for keyboard input the library function is terminated, the calling statement receives control, and the lost connection error is issued again. This supports error trapping in the calling program so an orderly shutdown can be performed.


AUTOIT SUPPORT

AutoIt is a free keyboard simulation program with very powerful automating capabilities. It can be used to access windows, read data from spreadsheets, write to display files and enter data in screens. There is a separate Window Information utility that comes with Autoit which displays what Autoit sees when windows are active. This has produced ambiguous information in the past.

R99C999 (BR row & col) now appears in the text field of BR labels.

Individual BR input fields may be referenced in Autoit as EditNN where NN is the INPUT FIELDS subscript (CURFLD) of the field.


ENVIRONMENT INTERROGATION

ENV$("STATUS [ .sub-keyword ] ... " [, mat config$ [, search-arg] ...] )

ENV$ returns a string or, in the event MAT CONFIG$ is provided, ENV$ redimensions and loads it. For a list of valid keywords issue a STATUS ENV command. If an array is specified, it may be followed by one or more case insensitive substrings which are regarded as restricting search arguments.

e.g. ENV$("SERVER_PLATFORM") returns “WINDOWS”

The following program displays all STATUS information that contains the word “file”:

00100    dim CONFIG$(1)*100
00120    let ENV$("STATUS",MAT CONFIG$,"file")
00140    print MAT CONFIG$

The above program produces the following output:

CHAINDFLT - Look for object files with source first.
EDITOR C:\PROGRAM FILES\MILLS ENTERPRISE\MYEDITBR\MYEDITBR.EXE
FILENAMES LOWER_CASE
OPTION 23 is OFF - prevent data conversion errors from moving file position
OPTION 25 is ON - make FILE$(0) be CON: if in windows
OPTION 26 is OFF - suppress creation of .BAK files
OPTION 29 is ON - save programs as .WB files
OPTION 33 is 64 - locking position for large file support
OPTION 49 is OFF - use relative path for spool file
OPTION 51 is OFF - recover deleted records for all files
SPOOLCMD prt.bat [SPOOLFILE] [COPIES] [PRINTER]
Server File: :c:\wbserver.dat
BR Config File: :C:\ADS\SYS\br.d\brconfig.sys
Executable File: :C:\ADS\SYS\br.d\ 
brserver-430beta+q-Win32-DebugEfence-2011-03-20.exe
Serial File: :C:\ADS\SYS\br.d\brserial.dat
Workfile path: :c:\ads
Open File #  0  :CON:

If I just want the options with the word file then I would use:

00100    dim CONFIG$(1)*100
00120    let ENV$("STATUS.CONFIG.OPTION",MAT CONFIG$,"file")
00140    print MAT CONFIG$

Which produces:

OPTION 23 is OFF - prevent data conversion errors from moving file position
OPTION 25 is ON - make FILE$(0) be CON: if in windows
OPTION 26 is OFF - suppress creation of .BAK files
OPTION 29 is ON - save programs as .WB files
OPTION 33 is 64 - locking position for large file support
OPTION 49 is OFF - use relative path for spool file
OPTION 51 is OFF - recover deleted records for all files 

Note that while keywords are case insensitive, they must be correctly specified, whereas search arguments are more “friendly”. For a complete list of valid keywords, issue the command:

STATUS ENV -p

Some of the new keywords supported are:

  • ENV$("CLIENT_PLATFORM") is "WINDOWS"
  • ENV$("CLIENT_PLATFORM.BR_BUILD_TYPE") is "DebugEfence"
  • ENV$("CLIENT_PLATFORM.BR_BUILD_DATE") is "2011-05-12"
  • ENV$("CLIENT_PLATFORM.BR_BITS") is "32"
  • ENV$("CLIENT_PLATFORM.OS_BITS") is "64"
  • ENV$("CLIENT_PLATFORM.OS_VERSION_NAME") is "Windows 7"
  • ENV$("CLIENT_PLATFORM.OS_VERSION_NUMBER") is "6.1"
  • ENV$("SERVER_PLATFORM") is "LINUX"
  • ENV$("SERVER_PLATFORM.BR_BUILD_TYPE") is "DebugEfence"
  • ENV$("SERVER_PLATFORM.BR_BUILD_DATE") is "2011-05-13"
  • ENV$("SERVER_PLATFORM.BR_BITS") is "64"
  • ENV$("SERVER_PLATFORM.OS_BITS") is ""
  • ENV$("SERVER_PLATFORM.OS_VERSION_NAME") is "#36-Ubuntu SMP Thu Jun 3 20:38:33 UTC 2010"
  • ENV$("SERVER_PLATFORM.OS_VERSION_NUMBER") is "2.6.32-22-server"
  • BR_MODEL “CLIENT/SERVER” or “COMBINED”

SQL SUPPORT

The following are examples of SQL connection strings which can be placed inside of brconfig.sys file or executed dynamically from BR command line:

CONFIG DATABASE db-ref  DSN=dsn-ref  [, USER= department | LOGIN_NAME | ? ] [, {PASSWORD= dept-password | BR_PASSWORD | ?} | PASSWORDD=encrypted-passwd ]

? indicates a login or password prompt

BR_PASSWORD indicates the password used during client login. If running the standard model ( not client-server ) then this is equivalent to “?”. encrypted-passwd is the DB password encrypted with the key stated in OPTION 66.

CONFIG DATABASE db-ref CONNECTSTRING="Driver={Microsoft Access Driver (*.mdb)};DBQ=C:\inetpub\wwwroot\BegASP\Chapter.14\Contact.mdb;Uid=Admin;Pwd=abcd1234"

The following will invoke the ODBC Manager to define or identify a file DSN.

CONFIG DATABASE ODBC-MANAGER

Here are 2 methods of opening an SQL connection and execute a query in BR:

1) OPEN #20: "DATABASE= db-ref" , SQL "sql-statement", OUTIN
2) OPEN #20: "DATABASE= db-ref, Name= filename" , SQL, OUTIN

In method 2, filename refers to a DISPLAY file containing an SQL statement that gets executed when a WRITE statement is processed -

Sequence of Operations

1. Begin processing with a WRITE statement.

2. If the WRITE contains an IO list of values then it is used to populate the 'filename' SQL before it is executed. In this process IO list values replace question marks in the original SQL, positionally left to right. These question marks only work with SQL arguments that refer to stored data. Question marks cannot be specified where SQL keywords or table column names appear.

3. This may or may not produce a result set. If it does, the result set may be processed like a BR file opened RELATIVE. Some operations that use file positioning may be slow since the whole result set may not be in memory immediately. Simple sequential access should be fairly quick.

4. Once SQL has been populated by an IOlist, it may be reused with the same values by issuing a WRITE with no IOlist.

5. READ IOlist variable associations are positional with each READ accessing one row of values.

SQL Date Format Functions

A$ = SQL_DATE$(BR-date-string,"format-mask")  ! format date for storage

B$ = BR_DATE$( SQL-date-string,"format-mask")  ! unpack DB date value

  • Note: SQL DATETIME fields are "Packed for Storage", but "DATE" fields are returned as a CCYY-MM-DD string in a SQL Query.

DATE returns "BLANK" for "Empty or Null Date"

SQL Table Interrogation

“ENV$ (STATUS)” has been extended to interrogate database connections and ODBC data sources. A program called ENVDB.BRS has been written to demonstrate how this extension works and to show how to setup linkage to a database or ODBC data source. Run the program as is to bring up the Microsoft ODBC manager. Then select a data source and look at the output from the program. This will also show you how to get and use connect strings. In this example lines 1900 and 2000 accomplish the same open as line 1800 in my environment.

Try it on your Windows workstation. As long as you have one or more ODBC drivers supported you can use it without having to install a database. You can even use it to interrogate Excel files because Microsoft provides an ODBC driver for that.

A sample program to demonstrate database interrogation entry is:

01000 ! Replace Envdb
01020    dim DATABASES$(1)*100
01040    dim DATABASE$*100
01060    dim TABLES$(1)*100
01080    dim TABLE$*100
01100    dim COLUMNS$(1)*100
01120    dim COLUMN$*100
01140    dim C$*100,FLD1$*40,FLD2$*40,FLD3$*40,FLD4$*40
01160    execute "CONFIG database testdb odbc-manager"
01180 !   Execute "CONFIG database testdb DSN='Accounts Payable'"
01220 !   Execute "CONFIG database testdb connectstring=""DSN=Excel Files;DBQ=L:\orders\Beneficial - A-PORCEL.xls;DefaultDir=L:\orders;DriverId=1046;MaxBufferSize=2048"""
01230 ! *****  Open Output File
01240    open #1: "name=envdb.txt,replace",display,output 
01420 Dump_Table: ! ***** Dump Table Layout
01440    let OUTFD = 1
01460    let ENV$("status.database.LIST", MAT DATABASES$)  !List of db's
01480    for DATABASE=1 to UDIM(DATABASES$)  !For each connected database
01500       let DATABASE$=DATABASES$(DATABASE)
01520       let FNSHOW_DATABASE(DATABASE$, "status.database."&DATABASE$)
01540    next DATABASE
01560    end 
01580 ! 
01600    def FNSHOW_DATABASE(DATABASE$*100, ST_PREFIX$*100)
01620       print #OUTFD: DATABASE$
01640       let OUT_PREFIX$=CHR$(9)
01660       print #OUTFD: OUT_PREFIX$&"DSN="&ENV$(ST_PREFIX$&".DSN")
01680       print #OUTFD: OUT_PREFIX$&"CONNECTSTRING="&ENV$(ST_PREFIX$&".CONNECTSTRING")
01700       print #OUTFD: OUT_PREFIX$&"Tables:"
01720       let ST_PREFIX$=ST_PREFIX$&".TABLES"
01740       let ENV$(ST_PREFIX$&".LIST", MAT TABLES$)
01760       for TABLE = 1 to UDIM(MAT TABLES$)
01780          let TABLE$=TABLES$(TABLE)
01800          let FNSHOW_TABLE(TABLE$, ST_PREFIX$&"."&TABLE$,OUT_PREFIX$&CHR$(9))
01820       next TABLE
01840    fnend 
01860 ! 
01880    def FNSHOW_TABLE(TABLE$*100, ST_PREFIX$*100, OUT_PREFIX$)
01900       print #OUTFD: OUT_PREFIX$&TABLE$
01920       let OUT_PREFIX$=OUT_PREFIX$&CHR$(9)
01940       print #OUTFD: OUT_PREFIX$&"Table remarks="&ENV$(ST_PREFIX$&".REMARKS")
01960       print #OUTFD: OUT_PREFIX$&"Table type="&ENV$(ST_PREFIX$&".TYPE")
01980       print #OUTFD: OUT_PREFIX$&"Columns:"
02000       let ST_PREFIX$=ST_PREFIX$&".COLUMNS"
02020       let ENV$(ST_PREFIX$&".LIST", MAT COLUMNS$)
02040       for COLUMN = 1 to UDIM(MAT COLUMNS$)
02060          let COLUMN$=COLUMNS$(COLUMN)
02080          let FNSHOW_COLUMN(COLUMN$, ST_PREFIX$&"."&COLUMN$,OUT_PREFIX$&CHR$(9))
02100       next COLUMN
02120    fnend 
02140 ! 
02160    def FNSHOW_COLUMN(COLUMN$*100, ST_PREFIX$*100, OUT_PREFIX$)
02180       print #OUTFD: OUT_PREFIX$&COLUMN$
02200       let OUT_PREFIX$=OUT_PREFIX$&CHR$(9)
02220       print #OUTFD: OUT_PREFIX$&"Column type="&ENV$(ST_PREFIX$&".TYPE")
02240       print #OUTFD: OUT_PREFIX$&"Column length="&ENV$(ST_PREFIX$&".LENGTH")
02260       print #OUTFD: OUT_PREFIX$&"Column decimals="&ENV$(ST_PREFIX$&".DECIMALS")
02280    fnend

BR DATA ENCRYPTION

Encryption encompasses a number of different operations. These operations can be used independently or in combination to meet different needs. We use industry standard encryption available through OpenSSL. Three technologies are widely used for encrypting data. BR supports the first two listed below through its ENCRYPT and DECRYPT functions.

Overview

  1. Symmetric key ciphers – where the same key is used to encrypt and decrypt data. You can specify a key to encrypt some data and later use the same key to decrypt the data.
  2. Hashing routines – one way routines that take data and convert it to a hash value. Sometimes these are thought of as checksums such as MD5 sum. Hash values are always the same length regardless of how big the hashed data is. A 10 gb file will have a hash result that is the same length as a 200 byte file. Hashing routines have a number of specific uses.
    1. Verify that data has not changed.
    2. Verifying that two files are the same.
    3. Validating passwords – this is based on the concept that if two values have the same hash value the values are equal. Using this technique improves security because it allows a server to store passwords in an unrecoverable format. Even the server software is unable to regenerate the original password. It is only capable of checking if the hash of a password matches the stored password hash.

Symmetric Key Ciphers

There are two encryption functions in the BR language, ENCRYPT$ and DECRYPT$.

ENCRYPT$(Data$ [,Key$ [,Encryption-type$, [,Initialization-vector$]]])
DECRYPT$(Data$ [,Key$ [,Encryption-type$, [,Initialization-vector$]]])

Data$ - The data to be encrypted

Key$ - The secret key to be used for encryption. If not specified this value will come from an OPTION 66 statement.

Encryption-type$ - The type of encryption to be done. If not specified, a common high strength encryption type will be employed. This is described in more detail below, but is generally only useful for interfacing with other typically non-BR programs.

Initialization-vector$ - This is an arcane part of encryption standards. It exists to prevent attackers from being able to tell whether the unencrypted data has changed. This is described in more detail below, but is general only needed when interfacing with other non-BR programs.


Interfacing With Other Programs (encryption type and initialization vector)

There are a number of different types of encryption that BR supports through OpenSSL: AES, BLOWFISH, DES, triple DES, RC4 and RC2. Most symmetric key ciphers are block ciphers meaning that they encrypt one block at a time. This means if you have a bit message, it is broken up into multiple blocks and each block is encrypted. The block size can be set as (128, 192, 256) bits. Some encryption types don't support all of these values so STATUS ENCRYPTION should be checked to see what encryption types are available in BR. Besides block size, there are also various schemes for blocking data. One might expect that using 256 bit blocking would simply take every 32 bytes and call it a block. This is not done though because there is a possibility that this would cause patterns in the encrypted data. To prevent this, there are various schemes known as codebooks which change the way data is blocked. Wikipedia explains this in more detail. If the encryption type is not specified AES:256:CBC:128 will be used. To be compatible with other programs the entire encryption type must be specified (cipher: key length: codebook: invitialization vector length).

Initialization-vector – this is used to cause the same data encrypted with the same key to have a different encrypted result. This is significant because otherwise an attacker looking at data seeing the same encrypted result twice would know that the key and the unencrypted data have not changed. Regardless of whether or not you are concerned about this potential security issue, the standard encryption methods require this value so interfacing with other programs may require you to use it. It is a common practice to use a random number for this value and store the value at the beginning of (ahead of) the encrypted result. This is what BR does if this parameter is omitted.

As an example:

ENCRYPT$(“test”, “key”) 

Produces a string containing “random number initialization vector”&”encrypted result”.

If the initialization vector is explicitly specified as in:

ENCRYPT$(“test”, “key”, “AES:256:CBC:128”, “RANDOM”) 

the result would be simply “encrypted result”.

DECRYPT$ has the same arguments as ENCRYPT$ with the exception of the first parameter which is the encrypted data. DECRYPT$ expects to be used with the same key$, encryption-type$, and initialization-vector$ as was used to encrypt the data. As with ENCRYPT$, if key$ is not specified, the value from the OPTION statement will be used. If encryption-type$ is not specified, “AES:256:CBC:128” will be used. If the initialization vector is not specified, it will be assumed that the encrypted data starts with an initialization vector.

Hashing Routines

Three common forms of hashing are allowed in BR. They are MD5, SHA, and SHA-1. These are also provided through the ENCRYPT$ function specifying a null key$ value:

ENCRYPT$(data$, “”, “MD5”)
ENCRYPT$(data$, “”, “SHA”)
ENCRYPT$(data$, “”, “SHA-1”)

Hashing is also referred to as Message Digests or digests. This is what the MD in MD5 means. There is no way to restore data that has been hashed. Hashing is a one way function so DECRYPT$ will yield an error.

Asymmetric Encryption

Asymmetric key encryption is also known as public/private key encryption.

Public/private keys are created as a pair by a key generator.  They are a pair, and it is not possible to have two public keys for the same private key or vice versa.  With regard to public/private key pairs, what one key encrypts the other key can decrypt, and neither key can decrypt what it has encrypted.  When a private key is used to encrypt data, the result is called a signature because everyone who has the public key can decrypt it.

This technique is used for:

Signing (using certificates) – A private key can be used to sign data. The result of such signing can be tested/validated with the corresponding public key.

Data encryption – A public key can be used to encrypt data. This data can then only be decrypted by the corresponding private key.

Hashes and signing are different but used together.  Rather than signing a large block of data which would create a large signature, only the hash is signed to create much smaller fixed length signature data.  When verifying a large block of signed data, the data is used to create a hash value and the hash value is compared to a decrypted signature.

Asymmetric encryption is not accessible through the BR ENCRYPT$, DECRYPT$ functions. However, it is used by our SSL client server connections and HTTPS. Certificates are most commonly used by SSL and HTTPS and are less useful for other application processes. In the Client Server model the client knows the server’s public key and the server uses its private key to encrypt and decrypt.

Encryption is invoked by Business Rules HTTP support as follows:

CONFIG HTTPS port-number   [ LOG file-pathname ] [CERT= cert-file-basename]
CONFIG OPTION  66   private-key-file-encryption-password
OPEN #400: “HTTP=SERVER”, DISPLAY, OUTIN

The BRSERVER executable directory must contain two files:

  • https-private.pem
  • https-cert.pem

These files are made by the following commands under Linux, MAC and cygwin for Windows:

openssl req -new -x509 -out httpserver.pem -days 10000

( this will prompt for the OPTION 66 password )

mv privkey.pem   https-private.pem
mv httpserver.pem   https-cert.pem

This port specific service can then be accessed with browsers. When the specified port is accessed through a browser, BR establishes an HTTPS connection rather than an HTTP connection.

Signing and Certificate Processing Industry Standards

Certain companies are authorized by the government to act as a Certificate Authority ( CA ). These companies ( e.g. Verisign ) issue electronic certificates which can be used to issue second level certificates. Certificates can have expiration dates and the line of authority extends from a CA to any number of levels (but a chain is only as strong as its weakest link). Certificates contain a list of signatures (described below) that trace back to a CA as follows:

When a company needs to obtain a certificate from a CA, it prepares its own certificate and sends it to the CA for signature. The CA provides the signature and the CA’s own public key for validating it. The text in such certificates will identify the signing authority ( CA ) and the recipient of the certificate. It also contains the public key of both the signer and the recipient.

Browsers know the CA identities and their public keys. A browser can verify a CA issued cert by hashing it, decrypting the signature with the known public key and matching the decrypted signature against the hash total. 

Any company that is issued a certificate by a CA can sign second level certificates issued to third parties. A second level cert contains the parent (CA issued) certificate, and includes the public keys of the issuer and the recipient. The signature is essentially the encrypted hash total of ‘itself plus all of its ancestors’. Additional levels each contain the chain of certificates leading from a CA issued cert to itself.

Ostensibly, a certificate cannot be counterfeited because it requires the signature of its parent which can only be produced with its parent’s private key. By providing both public keys ( signer and recipient ) in all certs along with signatures, a non-forgeable or alterable chain is established.

Example: CA public key – known to browser certificate 1 (signed by CA) certificate 2 (signed by second level - includes certificate 1) final certificate (signed by third level - includes certificate 2)   A browser would find the CA information in the certificate and check to see if it is in the browser’s internal list.  If not it fails.  Then it verifies that certificate 1 (which ends up being part of the final certificate) has been signed by the CA.  After that it checks certificate 2 and verifies that it has been signed with certificate 1.  Finally it checks the final certificate and verifies that it has been signed with certificate 2.   To assure the line authority of any certificate, the public keys are associated with signers, not with documents.

ODBC VERSION 4.3

Improved installation routines:

  • Easy to use
  • Compatible with Windows Vista/7
  • Compatible with 64 Bit Machines (both 32 and 64 bit drivers).
  • Easily create DNS entries from the CONTEXT using a BR program called CREATE_INI.BR. (You will need to tailor the resulting INI file to the target setting.)
  • Installation on a client can be done from a command line avoiding the need for human interaction at the client.

Other improvements:

  • Support for 64 bit Record Locking (No 2GB Limit!).
  • Implemented Dynamic (on the fly) Indexes.
  • The ODBC splash screen has been removed.

ODBC Logging:

  • Set Logging to level 6 or greater.
  • LOGGING 6, C:\ODBC-LOG.TXT
  • Log file will provide helpful information to analyze queries.
  • Actual SQL processed by Driver (As opposed to the SQL typed in MS-Access or MS-Excel)
  • Indexes used by the Query. (To help determine the "BEST Query" for performance).

More Robust:

  • Improved Date Handling (Sort/Filter, etc).
  • Improved Joins leverage &/or create indexes for performance.
  • Improved Group By queries
  • Improved "Like" filters.
  • Improved Multiple Filters in a single query


ODBC Licensing And Security

Licenses will be issued based on number of workstations or number of BR WSIDs.

The price per user for licensing based on the number of BR WSIDs is one half of the price based on the number of ODBC workstations.

The maximum license fee for ODBC is $4900.

Enforcement

If the ODBC license is based on the number of BR users, then the BRSERIAL.DAT file always specifies 999 users.

We assign a random number to each machine that uses the ODBC driver and another random number to each user of ODBC. These numbers are stored along with the date, encrypted in a table in the server and client registries. Each time a session is started, the client is checked for pre-existing control numbers and if they exist then the numbers are used for the session (along with the current date). If a client reports a pre-existing number less than 14 days old that is not in the server table, then an alarm is signaled. This indicates tampering with the server table.

When a control number pair is about to be added to the server table and the table is full then it is searched for an entry more than 14 days old for replacement. If no such entry exists, then a “maximum users exceeded” error message is presented.

When a computer is replaced, this can leave an unusable entry in the server table for up to 14 days. If this occurs, then the user can run a program on the server that writes an encrypted header with the current date to the server table indicating that the table has been cleared in a licensed manner. After this has been run, all entries in the table will be available for reuse. Clients that have pre-existing control numbers will not generate the tamper error when the license file is cleared in this manner unless the client last used date is greater than the encrypted header date. This program requires a password which is an encrypted form of the current date plus the serial number. Only the dealer has the password producing program so only the dealer can obtain the current day’s password.

When a client machine has more than two ODBC user entries, the entries greater than one are counted as separate workstations. e.g. 1 or 2 ->1, 3->2, 4->3, etc.


New Procedure for Utilizing MS Access ODBC Middleware 

A procedure has been established for greatly expanding the SQL capabilities of the BR ODBC driver by routing ODBC requests through MS Access. Using this technique one can create reusable queries that combine several tables. This procedure is described in the installation guide.

PRINT FONT STRETCHING

When we developed the PDF printing facility we encountered a problem getting PDF to print exactly like NWP and PCL. This was partly because early in NWP development we stretched the fixed width fonts vertically for maximum legibility. So in version 4.2 we adopted a default font that was more like PCL that we could print in both NWP and PDF.

However, we eventually returned to the older stretched fonts because of their superior legibility. This issue affects only fixed width fonts. This stretching can be disabled with OPTION 68.

We are now using Courier New as the default font. pdflib4-Win32.dll adds support for this stretching to our PDF capabilities.

Relative Font Heights ( height to width ratios ):

  • Native Courier New 1.6 - available in PCL
  • Native Letter Gothic 2.0 - available in PCL
  • Stretched Fonts 2.6 - NWP and PDF only

The 1.6, 2.0, 2.6 are ratios. For Courier New the 1.6 means that the font is 1.6 times as high as it is wide. PCL measures all fixed width fonts in width and calculates the height based on these ratios. So for Courier New a 10 CPI font would be 1.6 * (1 / 10)(CPI) * 72 (points per inch) = 11.52 points. Actually the ratio for Courier New appears to be 1.66666666. This would mean that 1.66666666 * (1/10) * 72 = 12 points.

EXTENDED DATE / TIME FUNCTIONS

Date numeric variables can now represent time of day in the fractional space (to the right of the decimal point). The DAYS and DATE masks have been extended as follows:

H#.## or H denotes hours [ with fractions ]. M#.### or M#.# denotes minutes. S#.####, S or S# denotes seconds.

M, to the right of H always denotes minutes, so H:M:S is sufficient. Either AM or PM, to the right of H denotes AM / PM output. The absence of AM and PM denote military hours (0 – 23). The maximum significant digits that can be represented in a numeric variable are 15. So if century, year, month and day are stored as a 5 digit day of century, then internally up to ten digits to the right of the decimal are available for time of day.

Extended Date Mask Examples:

DATE( “Month dd, ccyy at H#.## hours”)  ->  September 12, 2011 at 14.58 hours
DATE( “mm/dd/yy at H:M AM”)  ->  09/15/11 at 2:35 PM
DATE( “mon dd cy at H#:M# PM”)  ->  Sep 15 2011 at 02:35 PM


Example of using DATE$ to get time to 9 decimal places:

Date$("H#:M#:S#.#########") -> 14:06:22.968419347


When storing date/time combinations on disk, you should allow for all of the significant digits that your date mask supports on each side of the decimal point. A “BH 4” form supports nine significant digits, which is suitable for day of century plus a four digit fraction. To exceed that you can use either PD 6, PD 7, PD 8 or D 8 (double floating point) to store these values on disk. DATE() only works with day-of-century values along with an optional time fraction.

NEW DATE MASK INPUT PROCESSING

DATE(mask) can now be used as an INPUT FIELDS specification.

10 INPUT FIELDS “row, col, DATE(mask)  ,UH” : date-var

Special keyboard processing: Punctuation (commas, colons, slashes, semicolons, and dashes) is skipped during entry similar to PIC. Insert and delete are supported within subfields that are delineated by punctuation. Copy includes punctuation. Cut is Copy with redisplay of zero date. Paste causes BR to translate the date to DAYS format and then display the date. Excel and OpenOffice Calc application formats are supported. If a string is pasted, it is first converted to DAYS using the provided mask. If a zero DAYS value is displayed then Month, M3, Day and D3 mask positions contain dashes.

A date picker has been added.


A new configuration statement is provided to control the when the date picker appears:

DATE [ALWAYS] [INVALID] [NEVER]

Additionally, the leading attribute ^DATE_PICKER is available.

INVALID ( the default mode ) presents the date picker whenever the days value of the expressed date is zero.

ALWAYS and ^DATE_PICKER show the picker whenever the cursor is in the field until a date is selected from the picker. Leaving the field and reentering it actives the picker again.

When in the date picker the following keys are active: Shift- PgUp/PgDn – Go to the previous/next month Ctrl- PgUp/PgDn – Go to the previous/next year

A sample program to demonstrate date entry is:

01000 ! Rep Date_Input

01020 ! Demonstrate The New Date() Input Format

01040 ! Skip Punctuation (Commas, Colons, Slashes, Semicolons, And Dashes)

01060 ! Insert And Delete Within Subfields That Are Delineated By Punctuation

01080 ! Continue To Support Cut And Paste Including Punctuation

01100 !

01120 rinput fields "5,10,DATE(mm/dd/yy) ;6,10,c": DATE_VAR

01140 print fields "8,10,date(Month DD, CCYY)": DATE_VAR

01160 !

01180 rinput fields "12,10,date(month dd, ccyy)": DATE_VAR

01200 if NOT DATE_VAR then goto 1180

01220 print fields "15,10,date(yy/mm/dd)": DATE_VAR

01240 print fields "18,10,N 6": DATE_VAR !Show days format

NEW TEXT FIELD FORMAT

10 (R)INPUT FIELDS “row, col, TEXT rows/cols[/capacity], leading-attr, …”:

This format is similar to the C/V/G format with the ^ENTER_LF attribute except: No trailing space padding or trimming occurs. Rows and columns are specified. Field capacity or newlines can cause a vertical scrollbar to appear.

Supported leading attributes are ^ENTER_LF (the default), ^ENTER_CRLF and ^NOWRAP. The TEXT keyword will imply ^ENTER_LF unless ^ENTER_CRLF is specified.

^ENTER_LF (the default) causes the ENTER key to add LF characters to the data and to go to a new line left justified. The cursor will retrace the data when backspace or left-arrow is keyed, meaning the on-screen LF characters are represented by moving the cursor, instead of allowing it to rest on invisible LF characters.

^ENTER_CRLF may be specified in lieu of ^ENTER_LF. When that is the case, carriage returns entered are represented in the data as carriage-return-linefeed (CRLF) character pairs. ^NOWRAP may be specified to suppress word wrapping. When ^NOWRAP is active, data is entered on the current line until ENTER is keyed to go to the next line. Both horizontal and vertical scroll bars appear as needed.

Tabs are entered into the text. Shift-tab is ignored.

Home, End and the arrow keys all operate relative to the current line as opposed to operating on the text box as a whole.

Depressing the Control key causes the following keys to operate in the normal string entry mode:

  • Enter – Returns control to the BR program
  • Tab – Goes to the next control
  • Shift-Tab – Goes to the prior control
  • Home – Goes to the beginning of data or the first field
  • End – Goes to the end of data or the last field
  • Left-Arrow/Up-Arrow – Goes to the prior control
  • Right-Arrow/Down-Arrow – Goes to the next control



A sample program to demonstrate TEXT entry is:

01000 ! Rep Text
01020 ! Test New Text Fiueld Type
01040    dim TEXT$*300, TEXT$(1)*80
01060    print NEWPAGE
01080    rinput fields "3,10,text 4/40/300,uh": TEXT$
01100    print fields "10,10,c": TEXT$
01120    print TEXT$
01140    let STR2MAT(TEXT$, MAT TEXT$, CHR$(10))
01160    print MAT TEXT$

INPUT ACROSS MULTIPLE WINDOWS

10 (R)INPUT FIELDS #121: “10, 10, C 20, UH; 10, 12, PIC(##/##/##), UH;#124, 10, 10, C 30, UH”: aaa$, bbb$, ccc$

This will input the first two fields on window #121 and the third field on window #124. The ‘#window-number,’ prefix may appear in any row, col FIELDS specification and it overrides the window number that follows the PRINT/INPUT/RINPUT keyword.

CONFIG CONSOLE CHANGES

Console BRConfig.sys specification introduced.

BR IN A BROWSER

We have made it easy to setup BR in a Browser once you have Client Server working. Point your browser at ads.net/plugin for a demonstration. Located in that directory is a file called index.html which is also on the FTP site in the BETA release browser-plugin directory. Modify this file to setup your own web page.

This HTML file demonstrates activation of BR client server in a browser. It first checks to see if the plugin is installed and if not it installs it. If needed, it updates the plugin from the ads.net site. It then initiates a connection to the server just like the BR client does. See the HTML file for further instructions, including how to confine BR to a window on the launch page if desired.

A new OPTION 70 is provided which will default to being ON in the Browser version. OPTION 70 will do the same thing as 54 (exit if BR enters command console mode), but it will be configurable to: OPTION 70 OFF ! This can be set programmatically OPTION 70 ON ! Same as OPTION 54 – the default for browsers OPTION 70 RELAXED ! Mild security – enables some support

RELAXED mode is intended to allow some debugging but still provide some security. This means disabling commands such as COPY, DIR, etc., CONFIG commands, and preventing changes from being made to BR programs. However, the security can be defeated because all of these activities can be performed by programs or procedures. Use ON (the default) for high security.


NEW AND CHANGED ERROR CODES

  • 0000 Successful completion no error
  • 0050 Writing to BTREE2 file failed
  • 0059 DEPRECATED ERROR: attempt to rewrite over key
  • 0063 DEPRECATED ERROR: network locking error
  • 0417 MSG string it too long
  • 0419 Invalid MSG special char specification
  • 0436 Bad flags for MAT2STR or STR2MAT
  • 0620 DEPRECATED ERROR: duplicate OPEN for standard printer output
  • 0641 DEPRECATED ERROR: missing protection device
  • 0635 Error using SSL socket
  • 0717 Error deleting record from BTREE2 file
  • 0727 DEPRECATED ERROR: FORM variable not referenced
  • 0807 Border characters can no longer be specified
  • 0814 Bad or missing trailing attribute
  • 0818 DEPRECATED ERROR: number too large for PIC format
  • 0865 DEPRECATED ERROR: invalid attribute combination
  • 0887 Sort column is not valid
  • 0930 INPUT FIELDS "...RANGE" bad range variables
  • 0931 Invalid insert or delete change with range
  • 0940 Value does not match boolean format
  • 0941 NULL boolean value used where allow null is false
  • 0945 The length of the date format is excessively long
  • 1008 Invalid keyword in shell interpreter
  • 1033 Scalar variable in an array group
  • 2022 The given encryption method does not exist
  • 2024 The encryption method is only valid one way
  • 2026 Missing encryption key
  • 2030 Failed processing encryption
  • 2070 DEPRECATED ERROR: not enough memory
  • 2080 DEPRECATED ERROR: insufficient dimensioned storage
  • 2090 DEPRECATED ERROR: not enough compilation storage
  • 2100 Too many active procedures
  • 2101 Illegal line number
  • 2102 GO attempted without running program
  • 2103 Illegal PROC parameter
  • 2104 No active lines to run
  • 2108 Program is active
  • 2109 No program in memory to SAVE or REPLACE
  • 2111 Missing lines for a program in object code
  • 2116 Cannot SAVE during LOAD or MERGE
  • 2120 DEPRECATED ERROR: not enough compilation storage
  • 2130 Program changed since LOAD at another workstation
  • 3031 DEPRECATED ERROR: 0 bytes available on disk
  • 4002 SQL create statement failed
  • 4003 SQL free statement failed
  • 4004 SQL prepare failed
  • 4005 SQL clear old results failed
  • 4006 SQL execute direct failed
  • 4007 WRITE to SQL with incorrect number of data elements
  • 4008 SQL describe result set columns failed
  • 4009 SQL bind result set columns failed
  • 4010 SQL fetch row failed
  • 4011 SQL bind parameter failure
  • 4012 Prepared SQL execution failure
  • 4014 Error converting time stamp to string value or back
  • 4114 DEPRECATED ERROR: invalid disk or disk drive reference
  • 4115 The specified database has not been opened
  • 4120 Invalid Y2K data found in an index field
  • 4121 DEPRECATED ERROR: invalid use of key file
  • 4123 Corrupted BTREE index
  • 4128 DEPRECATED ERROR: invalid file name
  • 4135 DEPRECATED ERROR: volume ID invalid
  • 4137 DEPRECATED ERROR: not enough storage space to create file
  • 4138 Can't rename between client and server
  • 4140 DEPRECATED ERROR: shared memory problem
  • 4141 DEPRECATED ERROR: shared memory problem
  • 4142 DEPRECATED ERROR: too many opened file names
  • 4143 DEPRECATED ERROR: out of shared memory
  • 4144 DEPRECATED ERROR: network semaphore error
  • 4145 Time out while waiting for input from user or ASYNC file I/O
  • 4147 A file has been opened too many times at the share level
  • 4149 Different version of BR running with locking
  • 4159 DEPRECATED ERROR: volume not on line
  • 4160 Out of internal file handles
  • 4174 Attempted file reservation on non-local file
  • 4175 Multiple wbserver files detected
  • 4177 DEPRECATED ERROR: windows shell call without command
  • 4179 Failed to lock in progress on wbserver.dat
  • 4180 Bad drive statement
  • 4185 Setting the directory failed on the client side
  • 4194 REWRITE check for null bytes failed
  • 4195 READ check for null bytes failed
  • 4196 WRITE check for null bytes failed
  • 4200 DEPRECATED ERROR: DOS/Windows/Novell error 0
  • 4201 DEPRECATED ERROR: DOS/Windows/Novell error 1
  • 4202 DEPRECATED ERROR: DOS/Windows/Novell error 2
  • 4203 Path does not exist or is not a directory
  • 4204 Too many file handles open on the system level
  • 4205 Access is denied
  • 4206 Invalid file descriptor
  • 4207 DEPRECATED ERROR: DOS/Windows/Novell error 7
  • 4208 DEPRECATED ERROR: DOS/Windows/Novell error 8
  • 4209 DEPRECATED ERROR: DOS/Windows/Novell error 9
  • 4210 DEPRECATED ERROR: DOS/Windows/Novell error 10
  • 4211 DEPRECATED ERROR: DOS/Windows/Novell error 11
  • 4212 DEPRECATED ERROR: DOS/Windows/Novell error 12
  • 4213 DEPRECATED ERROR: DOS/Windows/Novell error 13
  • 4214 DEPRECATED ERROR: DOS/Windows/Novell error 14
  • 4215 Invalid drive reference
  • 4216 Cannot remove directory
  • 4217 DEPRECATED ERROR: DOS/Windows/Novell error 17
  • 4218 DEPRECATED ERROR: DOS/Windows/Novell error 18
  • 4219 I/O error on write protected floppy
  • 4220 DEPRECATED ERROR: DOS/Windows/Novell error 20
  • 4221 DEPRECATED ERROR: DOS/Windows/Novell error 21
  • 4222 DEPRECATED ERROR: DOS/Windows/Novell error 22
  • 4223 DEPRECATED ERROR: DOS/Windows/Novell error 23
  • 4224 File is too large for locking mode
  • 4225 DEPRECATED ERROR: DOS/Windows/Novell error 25
  • 4226 DEPRECATED ERROR: DOS/Windows/Novell error 26
  • 4227 DEPRECATED ERROR: DOS/Windows/Novell error 27
  • 4228 DEPRECATED ERROR: DOS/Windows/Novell error 28
  • 4229 DEPRECATED ERROR: DOS/Windows/Novell error 29
  • 4230 DEPRECATED ERROR: DOS/Windows/Novell error 30
  • 4231 DEPRECATED ERROR: DOS/Windows/Novell error 31
  • 4232 DEPRECATED ERROR: DOS/Windows/Novell error 32
  • 4233 DEPRECATED ERROR: DOS/Windows/Novell error 33
  • 4234 DEPRECATED ERROR: DOS/Windows/Novell error 34
  • 4235 DEPRECATED ERROR: DOS/Windows/Novell error 35
  • 4236 DEPRECATED ERROR: DOS/Windows/Novell error 36
  • 4237 DEPRECATED ERROR: DOS/Windows/Novell error 37
  • 4238 DEPRECATED ERROR: DOS/Windows/Novell error 38
  • 4239 Disk is full
  • 4240 DEPRECATED ERROR: DOS/Windows/Novell error 40
  • 4241 DEPRECATED ERROR: DOS/Windows/Novell error 41
  • 4242 DEPRECATED ERROR: DOS/Windows/Novell error 42
  • 4243 DEPRECATED ERROR: DOS/Windows/Novell error 43
  • 4244 DEPRECATED ERROR: DOS/Windows/Novell error 44
  • 4245 DEPRECATED ERROR: DOS/Windows/Novell error 45
  • 4246 DEPRECATED ERROR: DOS/Windows/Novell error 46
  • 4247 DEPRECATED ERROR: DOS/Windows/Novell error 47
  • 4248 DEPRECATED ERROR: DOS/Windows/Novell error 48
  • 4249 DEPRECATED ERROR: DOS/Windows/Novell error 49
  • 4250 DEPRECATED ERROR: DOS/Windows/Novell error 50
  • 4251 DEPRECATED ERROR: DOS/Windows/Novell error 51
  • 4252 DEPRECATED ERROR: DOS/Windows/Novell error 52
  • 4253 DEPRECATED ERROR: DOS/Windows/Novell error 53
  • 4254 DEPRECATED ERROR: DOS/Windows/Novell error 54
  • 4255 DEPRECATED ERROR: DOS/Windows/Novell error 55
  • 4256 DEPRECATED ERROR: DOS/Windows/Novell error 56
  • 4257 DEPRECATED ERROR: DOS/Windows/Novell error 57
  • 4258 DEPRECATED ERROR: DOS/Windows/Novell error 58
  • 4259 DEPRECATED ERROR: DOS/Windows/Novell error 59
  • 4260 DEPRECATED ERROR: DOS/Windows/Novell error 60
  • 4261 Printer queue full
  • 4262 DEPRECATED ERROR: DOS/Windows/Novell error 62
  • 4263 DEPRECATED ERROR: DOS/Windows/Novell error 63
  • 4264 DEPRECATED ERROR: DOS/Windows/Novell error 64
  • 4265 DEPRECATED ERROR: DOS/Windows/Novell error 65
  • 4266 DEPRECATED ERROR: DOS/Windows/Novell error 66
  • 4267 DEPRECATED ERROR: DOS/Windows/Novell error 67
  • 4268 DEPRECATED ERROR: DOS/Windows/Novell error 68
  • 4269 DEPRECATED ERROR: DOS/Windows/Novell error 69
  • 4270 End of file
  • 4271 Incomplete record
  • 4272 Key not found
  • 4273 Help keyword or topic not found
  • 4274 DEPRECATED ERROR: DOS/Windows/Novell error 74
  • 4275 DEPRECATED ERROR: DOS/Windows/Novell error 75
  • 4276 Lock does not exist
  • 4277 DEPRECATED ERROR: DOS/Windows/Novell error 77
  • 4278 DEPRECATED ERROR: DOS/Windows/Novell error 78
  • 4279 DEPRECATED ERROR: DOS/Windows/Novell error 79
  • 4280 DEPRECATED ERROR: DOS/Windows/Novell error 80
  • 4281 DEPRECATED ERROR: DOS/Windows/Novell error 81
  • 4282 Data does not match LINK=
  • 4283 Updating previous/next link failed
  • 4284 DEPRECATED ERROR: DOS/Windows/Novell error 84
  • 4285 DEPRECATED ERROR: DOS/Windows/Novell error 85
  • 4286 DEPRECATED ERROR: DOS/Windows/Novell error 86
  • 4287 DEPRECATED ERROR: DOS/Windows/Novell error 87
  • 4288 DEPRECATED ERROR: DOS/Windows/Novell error 88
  • 4289 DEPRECATED ERROR: DOS/Windows/Novell error 89
  • 4290 DEPRECATED ERROR: DOS/Windows/Novell error 90
  • 4291 DEPRECATED ERROR: DOS/Windows/Novell error 91
  • 4292 DEPRECATED ERROR: DOS/Windows/Novell error 92
  • 4293 DEPRECATED ERROR: DOS/Windows/Novell error 93
  • 4294 DEPRECATED ERROR: DOS/Windows/Novell error 94
  • 4295 DEPRECATED ERROR: DOS/Windows/Novell error 95
  • 4296 DEPRECATED ERROR: DOS/Windows/Novell error 96
  • 4297 DEPRECATED ERROR: DOS/Windows/Novell error 97
  • 4298 DEPRECATED ERROR: DOS/Windows/Novell error 98
  • 4299 Cannot copy or rename file to itself
  • 4300 Shell call return value
  • 4301 DEPRECATED ERROR: DOS/Windows/Novell error 101
  • 4302 DEPRECATED ERROR: DOS/Windows/Novell error 102
  • 4303 DEPRECATED ERROR: DOS/Windows/Novell error 103
  • 4304 DEPRECATED ERROR: DOS/Windows/Novell error 104
  • 4305 DEPRECATED ERROR: DOS/Windows/Novell error 105
  • 4306 DEPRECATED ERROR: DOS/Windows/Novell error 106
  • 4307 DEPRECATED ERROR: DOS/Windows/Novell error 107
  • 4308 DEPRECATED ERROR: DOS/Windows/Novell error 108
  • 4309 DEPRECATED ERROR: DOS/Windows/Novell error 109
  • 4310 DEPRECATED ERROR: DOS/Windows/Novell error 110
  • 4311 DEPRECATED ERROR: DOS/Windows/Novell error 111
  • 4312 DEPRECATED ERROR: DOS/Windows/Novell error 112
  • 4313 DEPRECATED ERROR: DOS/Windows/Novell error 113
  • 4314 DEPRECATED ERROR: DOS/Windows/Novell error 114
  • 4315 DEPRECATED ERROR: DOS/Windows/Novell error 115
  • 4316 DEPRECATED ERROR: DOS/Windows/Novell error 116
  • 4317 DEPRECATED ERROR: DOS/Windows/Novell error 117
  • 4318 DEPRECATED ERROR: DOS/Windows/Novell error 118
  • 4319 DEPRECATED ERROR: DOS/Windows/Novell error 119
  • 4320 Unknown system error see SYSERR function
  • 4321 DEPRECATED ERROR: DOS/Windows/Novell error 121
  • 4322 DEPRECATED ERROR: DOS/Windows/Novell error 122
  • 4323 DEPRECATED ERROR: DOS/Windows/Novell error 123
  • 4324 DEPRECATED ERROR: DOS/Windows/Novell error 124
  • 4325 DEPRECATED ERROR: DOS/Windows/Novell error 125
  • 4326 DEPRECATED ERROR: DOS/Windows/Novell error 126
  • 4327 DEPRECATED ERROR: DOS/Windows/Novell error 127
  • 4328 DEPRECATED ERROR: DOS/Windows/Novell error 128
  • 4329 DEPRECATED ERROR: DOS/Windows/Novell error 129
  • 4330 DEPRECATED ERROR: DOS/Windows/Novell error 130
  • 4331 DEPRECATED ERROR: DOS/Windows/Novell error 131
  • 4332 DEPRECATED ERROR: DOS/Windows/Novell error 132
  • 4333 DEPRECATED ERROR: DOS/Windows/Novell error 133
  • 4334 DEPRECATED ERROR: DOS/Windows/Novell error 134
  • 4335 DEPRECATED ERROR: DOS/Windows/Novell error 135
  • 4336 DEPRECATED ERROR: DOS/Windows/Novell error 136
  • 4337 DEPRECATED ERROR: DOS/Windows/Novell error 137
  • 4338 DEPRECATED ERROR: DOS/Windows/Novell error 138
  • 4339 DEPRECATED ERROR: DOS/Windows/Novell error 139
  • 4340 Unknown curl error - use -e to return OS error
  • 4341 DEPRECATED ERROR: DOS/Windows/Novell error 141
  • 4342 DEPRECATED ERROR: DOS/Windows/Novell error 142
  • 4343 DEPRECATED ERROR: DOS/Windows/Novell error 143
  • 4344 DEPRECATED ERROR: DOS/Windows/Novell error 144
  • 4345 DEPRECATED ERROR: DOS/Windows/Novell error 145
  • 4346 DEPRECATED ERROR: DOS/Windows/Novell error 146
  • 4347 DEPRECATED ERROR: DOS/Windows/Novell error 147
  • 4348 DEPRECATED ERROR: DOS/Windows/Novell error 148
  • 4349 DEPRECATED ERROR: DOS/Windows/Novell error 149
  • 4350 DEPRECATED ERROR: DOS/Windows/Novell error 150
  • 4351 DEPRECATED ERROR: DOS/Windows/Novell error 151
  • 4352 DEPRECATED ERROR: DOS/Windows/Novell error 152
  • 4353 DEPRECATED ERROR: DOS/Windows/Novell error 153
  • 4354 DEPRECATED ERROR: DOS/Windows/Novell error 154
  • 4355 DEPRECATED ERROR: DOS/Windows/Novell error 155
  • 4356 DEPRECATED ERROR: DOS/Windows/Novell error 156
  • 4357 DEPRECATED ERROR: DOS/Windows/Novell error 157
  • 4358 DEPRECATED ERROR: DOS/Windows/Novell error 158
  • 4359 DEPRECATED ERROR: DOS/Windows/Novell error 159
  • 4360 DEPRECATED ERROR: DOS/Windows/Novell error 160
  • 4361 DEPRECATED ERROR: DOS/Windows/Novell error 161
  • 4362 DEPRECATED ERROR: DOS/Windows/Novell error 162
  • 4363 DEPRECATED ERROR: DOS/Windows/Novell error 163
  • 4364 DEPRECATED ERROR: DOS/Windows/Novell error 164
  • 4365 DEPRECATED ERROR: DOS/Windows/Novell error 165
  • 4366 DEPRECATED ERROR: DOS/Windows/Novell error 166
  • 4367 DEPRECATED ERROR: DOS/Windows/Novell error 167
  • 4368 DEPRECATED ERROR: DOS/Windows/Novell error 168
  • 4369 DEPRECATED ERROR: DOS/Windows/Novell error 169
  • 4370 DEPRECATED ERROR: DOS/Windows/Novell error 170
  • 4371 DEPRECATED ERROR: DOS/Windows/Novell error 171
  • 4372 DEPRECATED ERROR: DOS/Windows/Novell error 172
  • 4373 DEPRECATED ERROR: DOS/Windows/Novell error 173
  • 4374 DEPRECATED ERROR: DOS/Windows/Novell error 174
  • 4375 DEPRECATED ERROR: DOS/Windows/Novell error 175
  • 4376 DEPRECATED ERROR: DOS/Windows/Novell error 176
  • 4377 DEPRECATED ERROR: DOS/Windows/Novell error 177
  • 4378 DEPRECATED ERROR: DOS/Windows/Novell error 178
  • 4379 DEPRECATED ERROR: DOS/Windows/Novell error 179
  • 4380 DEPRECATED ERROR: DOS/Windows/Novell error 180
  • 4381 DEPRECATED ERROR: DOS/Windows/Novell error 181
  • 4382 DEPRECATED ERROR: DOS/Windows/Novell error 182
  • 4383 DEPRECATED ERROR: DOS/Windows/Novell error 183
  • 4384 DEPRECATED ERROR: DOS/Windows/Novell error 184
  • 4385 DEPRECATED ERROR: DOS/Windows/Novell error 185
  • 4386 DEPRECATED ERROR: DOS/Windows/Novell error 186
  • 4387 DEPRECATED ERROR: DOS/Windows/Novell error 187
  • 4388 DEPRECATED ERROR: DOS/Windows/Novell error 188
  • 4389 DEPRECATED ERROR: DOS/Windows/Novell error 189
  • 4390 DEPRECATED ERROR: DOS/Windows/Novell error 190
  • 4391 DEPRECATED ERROR: DOS/Windows/Novell error 191
  • 4392 DEPRECATED ERROR: DOS/Windows/Novell error 192
  • 4393 DEPRECATED ERROR: DOS/Windows/Novell error 193
  • 4394 DEPRECATED ERROR: DOS/Windows/Novell error 194
  • 4395 DEPRECATED ERROR: DOS/Windows/Novell error 195
  • 4396 DEPRECATED ERROR: DOS/Windows/Novell error 196
  • 4397 DEPRECATED ERROR: DOS/Windows/Novell error 197
  • 4398 DEPRECATED ERROR: DOS/Windows/Novell error 198
  • 4399 File name is not a UNC path
  • 4501 OS function failure
  • 4513 Bad data on OS function
  • 4514 No memory on OS function
  • 4521 Device not ready
  • 4522 Bad system command
  • 4526 Not a dos disk
  • 4591 A shell call timed out
  • 4596 Process signaled
  • 4597 Process stopped
  • 4598 Process was terminated in an unknown manner
  • 4614 Invalid standard handle
  • 4616 PDF library initialization failed
  • 4618 An error that aborts further reconnect attempts has occurred
  • 4620 Client server connection failure
  • 4890 Temporary index creation failure
  • 6201 Spooling error while executing lp or lpr
  • 6213 Unknown windows printing error
  • 6214 Printing windlg find resource error
  • 6215 Printing windlg initialization error
  • 6216 Printing windlg load resource error
  • 6217 Printing windlg load string failure
  • 6218 Printing windlg lock resource failure
  • 6219 Printing windlg no memory
  • 6220 Printing windlg failed to lock memory
  • 6221 Printing windlg no hisntance
  • 6222 Printing windlg no hook
  • 6223 Printing windlg no template
  • 6224 Printing windlg struct size
  • 6225 Printing windlg create IC failure
  • 6226 Printing windlg default different
  • 6227 Printing windlg drag and drop mismatch
  • 6228 Printing windlg print dev mode failure
  • 6229 Printing windlg error initializing printer
  • 6230 Printing windlg error loading driver
  • 6231 Printing windlg no default printer
  • 6232 Printing windlg no devices
  • 6233 Printing windlg parse failure
  • 6234 Printing windlg printer not found
  • 6235 Printing windlg return default failure
  • 6236 Printing windlg setup failure
  • 6240 Failed opening printer DC
  • 6242 Invalid parametrized substitution format
  • 6243 Parameter count does not match using parametrized substitutions
  • 6244 Parametrized substitution result is too long
  • 6245 Unsupported escape sequence for printing
  • 6246 Passthrough printing error
  • 6247 Invalid NWP color specification
  • 6248 Invalid NWP picture specification or the image is not found
  • 6250 Invalid PDF import specification
  • 6252 Print PDF requires either READER or an output file name
  • 6254 Creating a new PDF document failed
  • 6255 Adding a page to a PDF document failed
  • 6256 Ending a PDF document failed
  • 6257 Adding an image to a PDF document failed
  • 6270 Spooling error
  • 6272 Bad initializer for PJL mode
  • 7600 Invalid or missing key start position
  • 7601 Invalid key length
  • 7602 Bad key
  • 7603 Duplicate keys found
  • 7604 Missing parameters for INDEX
  • 7605 Invalid index parameter
  • 7606 INDEX records in does not match records out
  • 7607 Not enough memory for INDEX
  • 7609 Attempt to INDEX a file that is not an internal file
  • 7610 Invalid INDEX file name
  • 7611 INDEX file already exists
  • 7612 Invalid INDEX work path
  • 7636 INDEX interrupted by user
  • 7699 Bad internal record size for INDEX
  • 7801 Invalid sort keyword
  • 7804 Syntax error in SORT - FILE specification
  • 7805 Syntax error in SORT - RECORD specification
  • 7806 Syntax error in SORT - ALTS specification
  • 7807 Syntax error in SORT - MASK specification
  • 7809 Syntax error in SORT - SUM specification
  • 7810 Attempt to SORT a file that is not an internal file
  • 7811 Not enough memory for SORT
  • 7812 Invalid SORT output file type
  • 7821 ALTS value is too large
  • 7823 Missing MASK specification
  • 7825 Too many RECORD statements
  • 7828 SORT specifications out of order
  • 7829 RECORD specification too long or too many RECORD specifications
  • 7830 RECORD lower limit is greater than upper limit
  • 7831 Output file record length is too short
  • 7832 Output file not empty
  • 7853 SORT control file not found
  • 8001 DEPRECATED ERROR: number too long
  • 8002 Window too small for input
  • 9000 Out of memmory
  • 9001 work stack is full
  • 9002 RPN stack is full
  • 9003 Flow stack is full
  • 9004 FOR/NEXT stack is full
  • 9005 RPN stack is empty
  • 9006 Too many nested IF, FOR/NEXT or DO/LOOP structures
  • 9100 DEPRECATED ERROR: compiler error
  • 9111 Code byte count is incorrect
  • 9112 Source byte count is incorrect
  • 9201 Invalid access for opening a file
  • 9203 Invalid create for opening a file
  • 9301 Invalid number of RPN entries
  • 9302 Function error
  • 9303 Invalid function
  • 9304 User defined function error
  • 9305 User defined function error
  • 9306 User defined function stacking error
  • 9307 No editor defined or invalid ON error statement
  • 9308 Utility open file channel is not open
  • 9309 Corrupt .BR/.WB program file encountered
  • 9310 Variable index outside of variable table
  • 9400 DEPRECATED ERROR: output file corrupted
  • 9401 BTREE verification failed
  • 9502 DEVELOPMENT ERROR: Actual error code not assigned yet
  • 9503 DEVELOPMENT ERROR: Actual error code not assigned yet
  • 9504 DEVELOPMENT ERROR: Actual error code not assigned yet
  • 9505 DEVELOPMENT ERROR: Actual error code not assigned yet
  • 9506 DEVELOPMENT ERROR: Actual error code not assigned yet
  • 9507 DEVELOPMENT ERROR: Actual error code not assigned yet
  • 9508 DEVELOPMENT ERROR: Actual error code not assigned yet
  • 9985 DEPRECATED ERROR: work file missing
  • 9987 No source exists for the given file
  • 9988 DEPRECATED ERROR: source line greater than 800 bytes
  • 9990 This version was made without HTTP support
  • 9992 DEF statement compiler error
  • 9994 Line reference indicates library, but no libraries active
  • 9995 DEPRECATED ERROR: RPN stack failure
  • 9996 Library program not found or internal line not found
  • 9997 Unbalanced parenthesis or flow stack error
  • 9998 Corrupt DIM source