Project

General

Profile

File System and Environment Access

This chapter will describe how 4GL provides access to operating system environment and file system details. For each function or statement, this will describe how they are available in the converted application code and what is the level of support provided by FWD. The next table shows what 4GL functions and statements can be used in converted application, and the FWD level of runtime support.

4GL Function/Statement Description Notes Supported
CURRENT-LANGUAGE Returns the current version of the Progress language. Get or set the name of the current language being used for session. Yes
FILE-INFO A handle which provides information about a file or directory. Only some of the possible attributes are supported at this time. Partially
OPSYS Returns a string describing the operating system on which the Progress environment is running. The possible return values are UNIX or WIN32 Yes
OS-APPEND Appends the content of the source file to the target one. The parameters can either be the explicit string or values computed from a complex expression. Yes
OS-COPY Copies the source file to the target one. The parameters can either be the explicit string or values computed from a complex expression. Yes
OS-CREATE-DIR Creates the specified directory, if it does not already exist. The call does not generate an error if the directory we want to create already exists. Yes
OS-DRIVES Gets a string containing a comma separated drive letter list. Works on systems which support drive letter concept, like Windows. Yes
OS-ERROR Gets the error code of the last operating system command. Every subsequent file system related command will override this value. Yes
OS-DELETE Removes one or more files or directories. It is possible to remove non-empty directories. Use with caution. Yes
OS-GETENV Gets the value of a system environment variable. Currently the FWD runtime returns a Java system property value or a variable which was explicitly defined with the -D option with the client starting command. Yes
OS-RENAME Renames the source file or directory to target name. Before executing file renaming the target file must not exist on the file system. Yes
PROGRAM-NAME Returns the name of the program where this statement is called. The index value input parameter is 1 based. The up-most level and maximum index value will always have the main starting procedure of the application if it has several nested procedure calls. Yes
PROGRESS Returns the Progress run time subsystem type currently in use. The only value currently returned by the FWD runtime is Full. Partially
PROMSGS Gets the name of the current message source being used by the Progress environment. Always returns the promsgs value. Yes
PROPATH function Returns the Progress search path used by the FWD run time environment. It can be overridden using the PROPATH statement. Yes
PROPATH statement Redefines the Progress search path used by the FWD run time environment. Sets the Progress search path on the target system. Yes
PROVERSION Returns the Progress version on which the application is running. The current default version is 10.2B. Can be overridden in the directory. Yes
SEARCH Performs file search using the path returned by the PROPATH function. In the current implementation the PROPATH is a read only feature. Yes
SESSION System handle to get and set different session properties. Currently FWD supports only some read-only features. Partially

Conceptually, these functions, statements and system handles can be divided into three subdivisions: system environment access tools, FWD compatible environment access tools and file system tools. Detailed description and usage examples will be presented further in this chapter.

Environment Access tools

Sometimes it is useful to know at run time what is the operating system behind the scene. For example if we need to make a directory listing we need to know what command to use, either “ls” or “dir”. Or maybe we need to know the Progress search path or any other system environment variable values. This section will present how 4GL's environment access tools work in the converted FWD code.

OPSYS Function

This function returns the operating system type in character format. Its syntax is:

OPSYS

and FWD emits this API call:

EnvironmentOps.getOperatingSystem()

The current possible returned value is either UNIX or WIN32. The value returned may have been found via a search algorithm that is account specific (user or process) or group specific within the current server or a global default for all servers.

Example 1:

message "Operating system is: " opsys.

Converted code:

message(new Object[]
{
   "Operating system is: ", EnvironmentOps.getOperatingSystem()
});

Details:

After application starts on Linux system the screen is:

Note the name UNIX is returned for the real OS name Linux. This will be true also for the different Linux versions, including AIX, SOLARIS, SUNOS, HP-UX, FREEBSD and MAC OS X. The string WIN32 will be returned for any windows version - 95, 98, NT, 2000 or XP.

SESSION Handle

This special handle allows the user to get and set different system features in the application context. Currently, only a few attributes are supported in FWD conversion environment, only in read-only mode. The syntax of this handle is:

SESSION [ :attribute | :method ]

where only the following attributes are supported:

Attribute EnvironmentOps API Details
SESSION:BATCH-MODE isBatchMode() Reports if the current context is running in batch mode.
The value returned may have been found via a search algorithm that is account (user or process) specific or group specific within the current server or a global default for all servers.
The implementation iteratively looks up the directory node under:
/server/<serverID>/runtime/<account_or_group>/batchMode
If no user/process or group nodes are present, then this is checked:
/server/<serverID>/runtime/default/batchMode
If no /server/<serverID>/runtime node exists, this is checked (it is the global default area for all servers):
/server/default/runtime/<account_or_group>/batchMode
Finally, if no user/process or group nodes are present in the global default area, then this is checked:
/server/default/runtime/default/batchMode
If no value is found via this lookup, then the default value of false will be returned.
SESSION:CHARSET getCharset() Reports the default character set name. Since the Progress default charset is ISO-8859-1, when the JVM reports that UTF-8 is the default, this method will return the "ISO-8859-1" string instead.
The assumption (possibly not always correct) is that UTF-8 is not a valid Progress charset and instead, to provide a proper default, we must override with a compatible charset. Note that if the default charset name is not UTF-8, it is assumed that the charset has been overridden already (at JVM startup). In this case, the default is returned unchanged.
SESSION:TEMP-DIRECTORY getTempDirectory() Gets the name of the directory where temporary files are stored.

Example 2:

message "The current batch mode value is:" session:batch-mode.

Converted code:

message(new Object[]
{
   "The current batch mode value is:", EnvironmentOps.isBatchMode()
});

Details:

After application starts the screen is:

The return value is logical and the value no means the application is started in interactive mode.

Example 3:

def var chCharset as character.
chCharset = session:charset.
message "The current charset value is:" chCharset.

Converted code:

character chCharset = new character("");
...
chCharset.assign(EnvironmentOps.getCharset());
message(new Object[]
{
   "The current charset value is:", chCharset
});

Details:

After application starts the screen is:

Note the returned value is ISO-8859-1. This is the default value if the current charset is UTF-8, and is used because ISO-8859-1 is the Progress default charset and there is an assumption that UTF-8 is not a valid charset for Progress. If the returned JVM charset is other than UTF-8, it will be used as the return value for the EnvironmentOps.getCharset() method.

Example 4:

def var chTempDir as character.
chTempDir = session:temp-directory.
message "The current temp directory is:" chTempDir.

Converted code:

character chTempDir = new character("");
...
chTempDir.assign(EnvironmentOps.getTempDirectory());
message(new Object[]
{
  "The current temp directory is:", chTempDir
});

Details:

After application starts the screen is:

This method has been implemented to return the Java java.io.tmpdir runtime property.

File System Operations

The other part of the tools are related to the commands accessing or using the file system. The goal of these statements is to provide a mechanism of executing external commands that are specific to the current operating systems behind the 4GL runtime. In the FWD runtime, these statements access the file system using Java's facilities.

FILE-INFO Handle

This special handle allows the user to get system information about a resource on the file system. Not all features are supported and currently only some attributes are available, in read-only mode. The syntax of the FILE-INFO handle is:

FILE-INFO [ :attribute ]

The attribute FILE-INFO:TYPE is not fully supported. All attribute access is read-only mode, except the FILE-NAME attribute; when set, this attribute initializes all the attributes in the FILE-INFO handle with the values which describe the specified file. The following table lists the supported attributes and map them to the appropriate API in the FileSystemOps class. Also, the table specifies the returned value and the support level in the FWD environment.

4GL Attribute FileSystemOps API FWD Return Value Support Level
FILE-CREATE-DATE fileInfoGetCreationDate() date Partially. Supported for Windows only. For Unix the current return value is unknown date.
FILE-CREATE-TIME fileInfoGetCreationTime() integer Partially. Supported for Windows only. For Unix the current return value is an unknown integer.
FILE-MOD-DATE fileInfoGetModDate() date Yes
FILE-MOD-TIME fileInfoGetModTime() integer Yes
FILE-NAME (access) fileInfoGetName() character Yes
FILE-NAME (setter) initFileInfo(<file>) n/a Yes
FILE-SIZE fileInfoGetSize() integer Yes
FILE-TYPE fileInfoGetType() character Partially. S, M and L, P attributes are not supported.
FULL-PATHNAME fileInfoGetFullPath() character Yes
PATHNAME fileInfoGetPathName() character Yes

Example 1:

def var chFileName as character.
file-info:file-name = "remove.me".
chFileName = file-info:file-name.
message "The file-info:file-name is:" chFileName.

Converted code:

character chFileName = new character("");
...
FileSystemOps.initFileInfo(new character("remove.me"));
chFileName.assign(FileSystemOps.fileInfoGetName());
message(new Object[]
{
   "The file-info:file-name is:", chFileName
});

Details:

Before accessing the FILE-INFO attributes, we need to initialize it, by setting the FILE-NAME attribute. For this, the initFileInfo call is emitted. Initialization is mandatory and will be used in every example we have in this paragraph. If the return value can not be obtained or file structure initialization has failed, all attributes will be set to unknown.

The targeted file must exist on the file system at the time the initFileInfo call is executed; if it does not exist or it can't be accessed, all attributes will be set to unknown, except FILE-NAME, which remains set to the targeted file. After application starts the screen is:

Note how different APIs are emitted when FILE-NAME's setter and getter is used. This attribute can be used with directories too.

Example 2:

def var fileModDate as date.
fileModDate = file-info:file-mod-date.
message "The file-info:file-mod-date is:" fileModDate.

Converted code:

date fileModDate = date.instantiateUnknownDate();
...
fileModDate.assign(FileSystemOps.fileInfoGetModDate());
message(new Object[]
{
   "The file-info:file-mod-date is:", fileModDate
});

Details:

The following example demonstrates how to access the FILE-MOD-DATE attribute. After application starts the screen is:

Example 3:

def var fileModTime as integer.
fileModTime = file-info:file-mod-time.
message "The file-info:file-mod-time is:" string(fileModTime, "HH:MM:SS").

Converted code:

integer fileModTime = new integer(0);
...
fileModTime.assign(FileSystemOps.fileInfoGetModTime());
message(new Object[]
{
   "The file-info:file-mod-time is:", valueOf(fileModTime, new character("HH:MM:SS"))
});

Details:

This example gets the file modification time. After application starts the screen is:

The time is returned as seconds from midnight. We use the STRING conversion function to convert it to the HH:MM:SS time format.

Example 4:

def var fileSize as integer.
fileSize = file-info:file-size.
message "The file-info:file-size is:" fileSize.

Converted code:

integer fileSize = new integer(0);
...
fileSize.assign(FileSystemOps.fileInfoGetSize());
message(new Object[]
{
   "The file-info:file-size is:", fileSize
});

Details:

To get the file size the attribute FILE-SIZE is to be used. Start the application. The screen is:

Example 5:

def var fileType as character.
fileType = file-info:file-type.
message "The file-info:file-type is:" fileType.

Converted code:

character fileType = new character("");
...
fileType.assign(FileSystemOps.fileInfoGetType());
message(new Object[]
{
   "The file-info:file-type is:", fileType
});

Details:

To get the type of the file the attribute FILE-TYPE is used. The return value is character. After application starts the screen is:

Several notes and constraints for using this attribute. The return value consist of the two parts. The first is one of the mutually exclusive attribute D, F or X meaning directory, file or unknown respectively. The attributes S - UNIX special device and M - procedure library members are not supported at this time. Then to this first letter the following one or more letters will be appended: H, R, W meaning hidden, readable and writable respectively. So in our example we have a not-hidden file with ability to read from and write to. The attributes L - UNIX symbolic links and P - pipes are not supported at this time.

Example 6:

def var chFileName as character initial "remove.me".
def var fileFullPath as character.
file-info:file-name = chFileName.
fileFullPath = file-info:full-pathname.
message "The file-info:full-pathname for" chFileName "is:" fileFullPath.

Converted code:

character chFileName = new character("remove.me");
character fileFullPath = new character("");
...
FileSystemOps.initFileInfo(chFileName);
fileFullPath.assign(FileSystemOps.fileInfoGetFullPath());
message(new Object[]
{
   "The file-info:full-pathname for", chFileName, "is:", fileFullPath
});

Details:

Sometimes it is required to get the full pathname for the given file. The attribute FULL-PATHNAME must be used for this purpose. After application starts the screen is:

Note the input file name has been extended to the full path specification.

Example 7:

def var chFileName as character initial "remove.me".
def var filePathname as character.
...
filePathname = file-info:pathname.
message "The file-info:pathname for" chFileName "is:" filePathname.

Converted code:

character chFileName = new character("remove.me");
character filePathname = new character("");
...
filePathname.assign(FileSystemOps.fileInfoGetPathName());
message(new Object[]
{
   "The file-info:pathname for", chFileName, "is:", filePathname
});

Details:

The remaining supported attribute PATHNAME is similar to FILE-NAME, except the fact that this attribute can be used for files only. Attempting to use it with directories will get the unknown value. After application starts the screen is:

If the relative file name was passed as input the return value will be the relative path, if the absolute path was passed the return value will be the absolute path.

OS-APPEND Statement

This statement is used to append the content of one file to another one. The syntax of the statement is:

OS-APPEND
   { source-filename | VALUE( expression ) }
   { target-filename | VALUE( expression ) }

The source and target file names can either be explicitly defined string constants or the result of an expression evaluated at runtime. If the file name is not fully qualified, the current directory (from where the client was started) is assumed as the location where to search or create files. FWD implements this statement by emitting the following API call, from the FileSystemOps class:

FileSystemOps.append(java.lang.String source, java.lang.String target)

Example 8:

os-append "source0.txt" "target0.txt".

Converted code:

FileSystemOps.append("source0.txt", "target0.txt");

Details:

This example appends the content of the soucer0.txt file to the target0.txt file. If the content of the source and target files are:

source file A

for source0.txt and

target file B

for target0.txt, after application is executed the target file is changed to the following:

target file B
source file A

Example 9:

def var chSrc as char initial "source0".
def var chDst as char initial "target0".
def var chExt as char initial "txt".
os-append value( chSrc+"."+chExt ) value( chDst+"."+chExt ).

Converted code:

character chSrc = new character("source0");
character chDst = new character("target0");
character chExt = new character("txt");
...
FileSystemOps.append((concat(chSrc, ".", chExt)).toStringMessage(),
                     (concat(chDst, ".", chExt)).toStringMessage());

Details:

This example shows how the file names are computed when complex expressions are used. The result of the running application is the same as in the previous example. It is possible to use the first parameter as an explicit file name and the second passed using the VALUE ( expression ) clause or vice versa.

OS-COPY Statement

This statement is used to execute an operating system copy command, from 4GL code. The syntax of the command is:

OS-COPY
   { source-filename | VALUE( expression ) }
   { target-filename | VALUE( expression ) }

The source and target file names can either be explicitly defined string constants or the result of an expression evaluated at runtime. If the file name is not fully qualified the current directory is assumed as the location for searching or creating files. The FWD API emitted for this statement is defined in the FileSystemOps class:

FileSystemOps.copy( java.lang.String source, java.lang.String target )

Example 10:

os-copy "source0.txt" "target1.txt".

Converted code:

FileSystemOps.copy("source0.txt", "target1.txt");

Details:

This example copies the source file source0.txt to the file target1.txt, which is overwritten if it already exists.

Example 11:

def var chSrc as char initial "source0".
def var chDst as char initial "target1".
def var chExt as char initial "txt".
os-copy value( chSrc+"."+chExt ) value( chDst+"."+chExt ).

Converted code:

character chSrc = new character("source0");
character chDst = new character("target1");
character chExt = new character("txt");
...
FileSystemOps.copy((concat(chSrc, ".", chExt)).toStringMessage(),
                   (concat(chDst, ".", chExt)).toStringMessage());

Details:

This example uses the VALUE( expression ) version to specify the target and source files. The result of this example is the same - source file is copied to the target one, no matter if it exists or not. If the target file already exists it is deleted first before creating the new one.

OS-CREATE-DIR Statement

This statement is used to create a new directory, directly from the 4GL code. The syntax of the statement is:

OS-CREATE-DIR  { directory-name | VALUE( expression ) } ...

where the directory-name is the name of the directory to create. If the directory already exists, no error is generated and the command ends silently. The FWD implementation for this statements is:

FileSystemOps.mkdir( java.lang.String[] dirname )

Note that the implementation assumes that multiple directories can be created in a single call.

Example 12:

os-create-dir "RemoveMe".

Converted code:

FileSystemOps.mkdir(new String[]
{
   "RemoveMe" 
});

Details:

After application is finished, the new directory RemoveMe has been created, as a subdirectory of the folder from where the client was started.

Example 13:

def var chRemove as char initial "RemoveMe".
def var chTmp as char initial "/Tmp".
os-create-dir value( chRemove ).
os-create-dir value( chRemove+chTmp ).

Converted code:

character chRemove = new character("RemoveMe");
character chTmp = new character("/Tmp");
...
FileSystemOps.mkdir(new String[]
{
   (chRemove).toStringMessage()
});
FileSystemOps.mkdir(new String[]
{
   (concat(chRemove, chTmp)).toStringMessage()
});

Details:

This example demonstrates how the VALUE( expression ) clause is converted when used with the OS-CREATE-DIR statement. Note before creating the Tmp subdirectory, we need to create the parent directory or make sure it already exists. If the directory exists and we call OS-CREATE-DIR to create it, the statements just silently returns.

Example 14:

os-create-dir value( chRemove ) value( chRemove+chTmp ).

Converted code:

FileSystemOps.mkdir(new String[]
{
   (chRemove).toStringMessage(),
   (concat(chRemove, chTmp)).toStringMessage()
});

Details:

This example demonstrates how a directory hierarchy can be created with a single OS-CREATE-DIR call. The result will be the same as in previous example, as each (sub)directory will be created, in the given order. This means the system calls will be performed sequentially for the items specified in the OS-CREATE-DIR parameter list.

OS-DELETE Statement

This statement is used to delete one or several files or directories, using the OS tools, from the 4GL environment. It is possible to delete an entire directory with all its sub-directories. The syntax of this statement is:

OS-DELETE
   { filename | VALUE( expression ) } ...
   [ RECURSIVE ]

where the filename parameter is the name of the file(s) or directory(s) to be deleted and the RECURSIVE clause deletes the specified non-empty directory, with all its (sub)directories.

The FWD implementation for this statements is:

FileSystemOps.delete( java.lang.String[] list, boolean recursive )

Note the multiple items can be specified in a single call. If non-empty directory should be deleted, the recursive parameter value must be TRUE.

Example 15:

os-copy "source0.txt" "remove_me.txt".
pause.
os-delete "remove_me.txt".

Converted code:

FileSystemOps.copy("source0.txt", "remove_me.txt");
pause();
FileSystemOps.delete(new String[]
{
   "remove_me.txt" 
}, false);

Details:

This example creates a new file by copying the existing one and then deletes it. In this case, the recursive parameter is set to FALSE. After the application is started, first the the new remove_me.txt file is created (as a copy of source0.txt). Check the current directory to see this file, then press spacebar to continue. The file will be removed. Check the file system to check if this was done.

Example 16:

def var chRemove as char initial "RemoveMe".
def var chSep as char initial "/".
def var chFileName as char initial "remove_me.txt".

os-create-dir value( chRemove ).
os-copy "source0.txt" value( chRemove+chSep+chFileName ).
pause.
os-delete value( chRemove+chSep+chFileName ) value( chRemove ).

Converted code:

character chRemove = new character("RemoveMe");
character chSep = new character("/");
character chFileName = new character("remove_me.txt");
...
FileSystemOps.mkdir(new String[]
{
   (chRemove).toStringMessage()
});
FileSystemOps.copy("source0.txt", (concat(chRemove, chSep, chFileName)).toStringMessage());
pause();
FileSystemOps.delete(new String[]
{
   (concat(chRemove, chSep, chFileName)).toStringMessage(),
   (chRemove).toStringMessage()
}, false);

Details:

This example demonstrates how several items can be deleted in one call. After application starts, it creates the directory, copies the file to it and waits for key to be pressed to continue. The second stage removes the file and then the empty directory. The order in the delete list important. First we need to make the directory empty then remove the empty directory. That's because the option RECURSIVE is not used here. Check the current directory in the file system to see each stage of the process.

Example 17:

def var chRemove as char initial "RemoveMe".
def var chSep as char initial "/".
def var chFileName as char initial "remove_me.txt".

os-create-dir value( chRemove ).
os-copy "source0.txt" value( chRemove+chSep+chFileName ).
pause.
os-delete value( chRemove ) recursive.

Converted code:

character chRemove = new character("RemoveMe");
character chSep = new character("/");
character chFileName = new character("remove_me.txt");
...
FileSystemOps.mkdir(new String[]
{
   (chRemove).toStringMessage()
});
FileSystemOps.copy("source0.txt", (concat(chRemove, chSep, chFileName)).toStringMessage());
pause();
FileSystemOps.delete(new String[]
{
   (chRemove).toStringMessage()
}, true);

Details:

This is a similar example, but with RECURSIVE option turned on. The result of running this application is the same as in the previous one, with the difference that now we remove the non-empty directory directly, using the RECURSIVE option (which sets the second parameter for FileSystemOps.delete() call to TRUE)

OS-DRIVES Function

This function returns the list of the available drives separated by a comma. It is supported only by Windows operating system environments. If the drive letter concept does not exist in the operating system, the function returns an empty string. The syntax of this statement is:

OS-DRIVES

and is implemented in FWD by:

FileSystemOps.getRootList()

which returns a character value.

Example 18:

def var chDrives as character.
chDrives = os-drives.

Converted code:

character chDrives = new character("");
...
chDrives.assign(FileSystemOps.getRootList());

Details:

The drive list is saved in a separated variable, for future usage. The FWD runtime uses the Java's listRoots() API in the java.io.File class, to determine the root list.

OS-ERROR Function

This function is used by Progress to return an integer error code, associated with the last operation which accessed the file system or the operating system. This codes can be set by the following statements: OS-APPEND, OS-COPY, OS-CREATE-DIR, OS-DELETE, OS-RENAME. The syntax of the function is:

OS-ERROR

and is implemented in FWD by:

integer FileSystemOps.getLastError()

Example 19:

def var intErr as integer.
def var chFilename as character label "Enter a file to delete" format "x(20)".
chFilename = "remove.me".
...
os-delete value( chFilename ).
intErr = os-error.
if intErr <> 0 then
   case intErr:
   when 1 then
      message "Insufficient rights to perform operation".
   when 2 then
      message "The object does not exist".
   otherwise
      message "The error code is:" intErr.
   end.
message "The error code is:" intErr.

Converted code:

FileSystemOps.delete(new String[]
{
   (chFilename).toStringMessage()
}, false);
itErr.assign(FileSystemOps.getLastError());
if (_isNotEqual(itErr, 0))
{
   switch ((itErr).intValue())
   {
      case 1:
      {
         message("Insufficient rights to perform operation");
         break;
      }
      case 2:
      {
         message("The object does not exist");
         break;
      }
      default:
      {
         message(new Object[]
         {
            "The error code is:", itErr
         });
         break;
      }
   }
}
message(new Object[]
{
   "The error code is:", intErr
});

Details:

Start the application. The first time - do not update the name of the file to delete. The operation will perform without errors (return code 0):

Start the application again. Modify the name of the file so that it does not exist on the file system. The error will be generated:

So the error code value is now 2, corresponding to “no such file or directory” error. The following table maps the error code and its meaning and it shows all the error codes supported by Progress.

Integer code Description
0 No error encountered
1 Not the owner of the file object
2 No such file or directory
3 Interrupted system call
4 I/O error
5 Bad file number
6 No more processes
7 Not enough core memory
8 Permission denied
9 Bad address
10 File exists
11 No such device
12 Not a directory
13 Is a directory
14 File table overflow
15 Too many open files
16 File too large
17 No space left on device
18 Directory not empty
999 Unknown error

OS-GETENV Statement

This statement is used to determine various system properties, at the operating system level. The syntax of the statement is:

OS-GETENV ( environment-variable )

The environment-variable is the name of the environment variable to get. It can either be a character variable, expression or constant. If there is no such variable defined in the system the statement and it's implementation will return the ”?” char. FWD implements this by emitting one of the the following calls in the converted code:

FileSystemOps.getProperty( character key )

when a character variable or expression is used to specify the environment variable to get or

FileSystemOps.getProperty( java.lang.String key )

when the environment variable to get is specified by a constant.

The FWD runtime will call the System.getProperty(String key) API to determine the environment variable's value. Because the System.getProperty(String key) returns only the value of a property available to the Java runtime, this means FWD does not currently have support for getting the environment variable directly from the OS.

Although this support is not fully available, it can be simulated by passing the needed environment variable to the Java process which starts the client, directly in the command line, using Java properties. For example, if we want the LANG variable to be retrieved in the FWD converted code, just add the following string to the FWD Client command line script:

props=”-DLANG=$LANG”

and insert this value to the client execution command before calling the client class:

cmd="exec $prog $srvr ... $props com.goldencode.p2j.main.ClientDriver ...”

Example 20:

def var chTmp as character format "x(16)".
def var chVarName as character initial "os.name".
update chVarName.
chTmp = os-getenv( chVarName ).
message "OS-GETENV() result for variable "+chVarName+" = "+chTmp.

Converted code:

character chTmp = new character("");
character chVarName = new character("os.name");
...
FrameElement[] elementList0 = new FrameElement[]
{
   new Element(chVarName, frame0.widgetChVarName())
};
frame0.update(elementList0);
chTmp.assign(FileSystemOps.getProperty(chVarName));
message(concat("OS-GETENV() result for variable ", chVarName, " = ", chTmp));

Details:

After application starts, the screen will display the initial value for the variable we want to get. Do not modify anything and press ENTER key. The screen is:

We have got the respective Java property on Linux machine. Start application once again. Now type the LANG word into the entry field and press enter. The screen is:

We see the value of the real environment variable manually merged with the -D option before. Now start once again and type the value of the variable not previously defined with -D option, for example MACHTYPE for Linux. The screen becomes:

As access to the OS environment variable is not available, the variable is unknown and the *”*?@”@ char is returned.

OS-RENAME Statement

This statement is used to execute file or directory rename using the OS, from 4GL code. The syntax of the command is:

OS-RENAME
   { source-filename | VALUE( expression ) }
   { target-filename | VALUE( expression ) }

The source and target names can either be explicitly defined using string constants or the result of an expression evaluated at time. If the file name is not fully qualified, the current directory is assumed as the location for searching or creating files. The FWD implementation for this statement is:

FileSystemOps.rename( java.lang.String source, java.lang.String target )

Example 21:

os-rename "source1.txt" "target2.txt".

Converted code:

FileSystemOps.rename("source1.txt", "target2.txt");

Details:

This example renames the source file source1.txt to the file target2.txt.

Example 22:

def var chSrc as char initial "source1".
def var chDst as char initial "target2".
def var chExt as char initial "txt".
os-rename value( chSrc+"."+chExt ) value( chDst+"."+chExt ).

Converted code:

character chSrc = new character("source1");
character chDst = new character("target2");
character chExt = new character("txt");
...
FileSystemOps.rename((concat(chSrc, ".", chExt)).toStringMessage(),
                     (concat(chDst, ".", chExt)).toStringMessage());

Details:

Here, the source and target names are specified using a complex expression. If the target file already exists, the rename operation will fail.

Example 23:

def var chRemove as char initial "RemoveMe".
def var chSep as char initial "/".
def var chFileName as char initial "remove_me.txt".

os-create-dir value( chRemove ).
os-copy "source0.txt" value( chRemove+chSep+chFileName ).
pause.
os-rename value( chRemove ) value( chRemove+"Too" ).

Converted code:

character chRemove = new character("RemoveMe");
character chSep = new character("/");
character chFileName = new character("remove_me.txt");
...
FileSystemOps.mkdir(new String[]
{
   (chRemove).toStringMessage()
});
FileSystemOps.copy("source0.txt", (concat(chRemove, chSep, chFileName)).toStringMessage());
pause();
FileSystemOps.rename((chRemove).toStringMessage(), (concat(chRemove, "Too")).toStringMessage());

Details:

With this statement, it is possible to rename/move directories. Start the application. On the first stage it creates the new directory, copies a file to it, then waits for a key to be pressed. Check the file system to ensure the directory RemoveMe has been created and there is a file inside before proceeding. Press a key and check the file system to see the new, renamed, directory, RemoveMeToo.

FWD Compatible Environment Access Tools

This set of tools provides access to various settings related to the Progress environment on which the application is running. In other words, the statements/functions described here do not make sense outside the FWD runtime, as they are 4GL specific.

CURRENT-LANGUAGE Function

This function is used to detect the current version of the Progress language in use. The syntax of the function is:

CURRENT-LANGUAGE

The function returns the ”?” character value, if it can't be determined. The FWD implementation of this function is:

EnvironmentOps.getCurrentLanguage()

The method searches the server directory and returns the first value found, in the following node paths (in this order):

/server/<serverID>/runtime/<account_or_group>/currentLanguage

/server/<serverID>/runtime/default/currentLanguage

/server/default/runtime/<account_or_group>/currentLanguage

/server/default/runtime/default/currentLanguage

If the value is not found in the nodes above the unknown value is returned by this function.

PROGRAM-NAME Function

This function is used to get the name of the program where this function was called. Its syntax is:

PROGRAM-NAME( n )

and FWD emits this call in the converted code:

EnvironmentOps.getSourceName( integer index )

The index (and the n parameter in the 4GL syntax) is a 1-based position in the call stack, where value 1 refers the currently running program.

Example 1:

def var chProName as character.
def var intIndx as int initial 1.
update intIndx.
chProName = program-name( intIndx ).
message "The Programe name for index" intIndx " is:" chProName.

Converted code:

character chProName = new character("");
integer intIndx = new integer(1);
...
FrameElement[] elementList0 = new FrameElement[]
{
   new Element(intIndx, frame0.widgetIntIndx())
};
frame0.update(elementList0);
chProName.assign(EnvironmentOps.getSourceName(intIndx));
message(new Object[]
{
   "The Programe name for index", intIndx, " is:", chProName
});

Details:

This example helps to understand how this function works. Start application and leave the update field as is pressing ENTER key. The screen is:

Now start the application again and change the index value to 2. The screen becomes:

As the callstack contains only the starting procedure, any value greater than 1 will return an unknown value.

Example 2:

run "file_system_training21.p".

Converted code:

FileSystemTraining21 filesystemtraining210 = new FileSystemTraining21();
filesystemtraining210.execute();

Details:

This wrapper just executes the previous procedure. So, this example increases the nesting level in the call stack for the previous example. Executing the example by leaving the update field untouched, the screen is:

which shows the currently executed external procedure. Now start the application again and change the index value to 2. The screen becomes:

which shows the name of the external procedure for this example. Now start the application once again and change the index value to 3. The screen becomes:

The conclusion is that the 1-based index starts with the currently executed procedure and goes up the call stack, with each increment targeting the external procedure at that level. So, the starting index 1 gives the program name containing this function itself, value 2 is one level up - the name of the “parent” application related to one that calls the function, and so on. In our case, there are only 2 levels of nesting, and that's why value 3 gives the unknown value.

PROGRESS Function

This function is used to get the string identifying the type of the Progress run time subsystem currently in use. The syntax of the function is:

PROGRESS

The implementation of the function in FWD is:

EnvironmentOps.getRuntimeType()

The FWD implementation of this function is to return value Full for any call, while in Progress the possible returns values are: Full, Query, Run-Time or COMPILE, COMPILE-ENCRYPT in case of using the Developer Toolkit or run-time Compiler.

Example 3:

def var chProgress as character.
chProgress = progress.
message "The Progress run-time type:" chProgress.

Converted code:

character chProgress = new character("");
...
chProgress.assign(EnvironmentOps.getRuntimeType());
message(new Object[]
{
   "The Progress run-time type:", chProgress
});

Details:

After application starts the screen is:

This is the only value returned by this call.

PROMSGS Function

This function is used to get the string identifying the current message source for the 4GL compatible environment. The syntax of the function is:

PROMSGS

and the FWD implementation is:

character EnvironmentOps.getMessageSource()

Example 4:

def var chMsgSrc as char.
chMsgSrc = promsgs.
message "The message source is:" chMsgSrc.

Converted code:

character chMsgSrc = new character("");
...
chMsgSrc.assign(EnvironmentOps.getMessageSource());
message(new Object[]
{
   "The message source is:", chMsgSrc
});

Details:

After starting application the screen is:

The value promsgs is the only value currently returned by this call.

PROPATH Function

This function is used to get the current value of the PROPATH environment variable. In context of the converted code, this is the Progress search path on the TARGET FWD system which is used for the Progress compatible environment. The syntax of this function is:

PROPATH

The implementation of the function in Java is:

EnvironmentOps.getSearchPath()

Unlike the other Progress compatible variable this is not read-only. It is possible to change this value on run-time (see the PROPATH Statement section in this chapter).

This must be distinguished from the original Progress SOURCE system's PROPATH which must be maintained for certain runtime translations of dynamically generated names (the algorithms of which were designed with that path assumed) but which is not necessarily a valid path on the system on which this is running. The original PROPATH can be obtained via the EnvironmentOps.getLegacySearchPath method.

If a specific PROPATH has been assigned in this user's context, then that "override" will be returned. Otherwise, the directory will be consulted for the stored version.

The value returned from the directory may have been found via a search algorithm that is account (user or process) specific or group specific within the current server or a global default for all servers.

The implementation iteratively looks up the directory node under:

/server/<serverID>/runtime/<account_or_group>/searchpath

If no user/process or group nodes are present, then this is checked:

/server/<serverID>/runtime/default/searchpath

If no /server/<serverID>/runtime node exists, this is checked (it is the global default area for all servers):

/server/default/runtime/<account_or_group>/searchpath

Finally, if no user/process or group nodes are present in the global default area, then this is checked:

/server/default/runtime/default/searchpath

If no value is found via this lookup, then the default value of &quot;.:" will be returned.

Example 5:

def var chPropath as character format "x(70)".
chPropath = propath.
display chPropath.

Converted code:

character chPropath = new character("");
...
chPropath.assign(EnvironmentOps.getSearchPath());
FrameElement[] elementList0 = new FrameElement[]
{
   new Element(chPropath, frame0.widgetChPropath())
};
frame0.display(elementList0);

Details:

After application starts the screen is:

Note the PROPATH value is “.:”. This value is taken from the current configuration directory file on the server side:

<node class="string" name="propath">
  <node-attribute name="value" value=".:"/>
</node>

And will be delivered to the client. This is where the initial value is set up.

PROPATH Statement

Sets the Progress search path on the TARGET FWD system which is used for the Progress compatible environment. This corresponds to the assignment of the PROPATH variable in Progress and represents a mechanism to override the default that is available from the directory.

The PROPATH is also used in the implementation of FileSystemOps.searchPath. The actual I/O operations when executed via the Progress compatible interface (see FileSystemOps and Stream APIs) for a FWD system are executed on the FWD client. This is the TARGET system on which this path is valid.

This must be distinguished from the original Progress SOURCE system's PROPATH which must be maintained for certain runtime translations of dynamically generated names (the algorithms of which were designed with that path assumed) but which is not necessarily a valid path on the system on which this is running. The original PROPATH can be obtained via the EnvironmentOps.getLegacySearchPath method.

The syntax of the statement is:

PROPATH = expression

The expression is the new value to be used for the Progress search path variable. This statement is currently not supported on the conversion level but FWD provides an API which can be used to redefine the PROPATH variable content:

EnvironmentOps.setSearchPath( java.lang.String newPropathValue )

As it is not supported by the conversion rules, this API can be used only in hand-written, compatible, 4GL code, using the FWD APIs directly in Java.

PROVERSION Function

This function is used to get the version of the currently running Progress system. The syntax of the function is:

PRVERSION

and its FWD implementation is:

EnvironmentOps.getVersion()

The value returned may have been found via a search algorithm that is account (user or process) specific or group specific within the current server or a global default for all servers.

The implementation iteratively looks up the directory node under:

/server/<serverID>/runtime/<account_or_group>/version

If no user/process or group nodes are present, then this is checked:

/server/<serverID>/runtime/default/version

If no /server/<serverID>/runtime node exists, this is checked (it is the global default area for all servers):

/server/default/runtime/<account_or_group>/version

Finally, if no user/process or group nodes are present in the global default area, then this is checked:

/server/default/runtime/default/version

If no value is found via this lookup, then the default value of 10.2B will be returned.

Example 6:

def var chProVer as character.
chProVer = proversion.
message "The Progress version currently in use:" chProVer.

Converted code:

character chProVer = new character("");
...
chProVer.assign(EnvironmentOps.getVersion());
message(new Object[]
{
   "The Progress version currently in use:", chProVer
});

Details:

After application starts, the screen is:

Note the value returned. The 10.2B is the current default value returned when the searching algorithm is failing to find a configured value .

SEARCH Function

This function is used to search for the specified file, using the path returned by the PROPATH function. The syntax of the function is:

SEARCH( filename )

and the implementation of this function is:

FileSystemOps.searchPath( java.lang.String filename )

or

FileSystemOps.searchPath( com.goldencode.p2j.util.character filename )

depending on how the file name is specified (as as character constant or as a variable).

If the file system object exists and is a file, then the filename is returned. If the path contains an empty string or a '.', then the current directory is searched, otherwise only the listed directories are searched.

Special processing is provided in case the original Progress code was checking for the availability of an external procedure. In this case the filename is checked using the SourceNameMapper.convertName method. If it exists, the Java class name is returned. This will "fake" the converted code into thinking that the external procedure still exists.

Example 7:

def var chSearch as character format "x(20)" initial "remove.me".
def var chSearchRes as character.
update chSearch.
chSearchRes = search( chSearch ).
message "The search result for file" chSearch "is:" chSearchRes.

Converted code:

character chSearch = new character("remove.me");
character chSearchRes = new character("");
...
frame0.update(elementList0);

chSearchRes.assign(FileSystemOps.searchPath(chSearch));
message(new Object[]
{
   "The search result for file", chSearch, "is:", chSearchRes
});

Details:

Start the application and leave the updated field as is, press the ENTER key and assume the file does exist in the directory under search. The screen is:

Now start the application again and change the file name to one that does not exist in the current search path. The screen becomes:

Note the returned value. If the file can not be found the method returns an unknown value. If the name of the file to search is fully qualified the returned value will also be fully qualified even the file is located in the current directory, as on the screen below:


© 2004-2017 Golden Code Development Corporation. ALL RIGHTS RESERVED.