I needed to make a job that would display a list of files in an IFS directory, allow a user to select one, copy contents of the file in the IFS directory to a file in the IBM i, and process the data. Always hearing the mantra KISS, Keep It Simple Simon, in my mind I searched for alternatives.
The person who taught me this mantra always made last the 'S' interchangeable between 'Simon' and 'Stupid', which left me thinking if I was being stupid? She always refused to elaborate.
I could use the 'Display Object links' DSPLNK, command. Alas, the output from this either display or print. If I output to print I could then copy the spool file to a physical file, and… that is unnecessarily complicated for something that should be simple.
There are the C APIs OPENDIR, STRUCT, and CLOSEDIR.
There is the 'Retrieve Directory Information', RTVINF, command. That looked promising. But when I tried it I found that its output could not be placed in QTEMP. The command produces two files, QAEZD0001D and QAEZD0001O. The one end with the 'O' (O the letter not zero) contains the information, but when I view the file the output is not in the CCSID I could read. I would need to use CAST function in SQL to make it appear readable to me.
RTVDIRINF DIR('/myfolder/') INFLIB(MYLIB) select cast(qezobjnam as char(100) ccsid 37) from qaezd0001o
What I really wanted was just to use the Unix command ls, which lists the directory contents. Fortunately, on the IBM i we can execute many Unix commands using Qshell. There are two CL commands to start Qshell, STRQSH and QSH, which are identical. I just prefer to use QSH as it is less characters to type, KISS. If I could direct the output of LS to a file I would have exactly what I want.
Rather than show parts of the CL program, this is small enough that I am going to show the whole thing and then describe what the various parts do.
01 PGM PARM(&PATH &ERROR) 02 DCL VAR(&PATH) TYPE(*CHAR) LEN(50) 03 DCL VAR(&ERROR) TYPE(*CHAR) LEN(10) 04 CHGVAR VAR(&ERROR) VALUE(' ') 05 CD DIR(&PATH) 06 MONMSG MSGID(CPFA09C) EXEC(DO) 07 CHGVAR VAR(&ERROR) VALUE('NOT_AUTH') 08 RETURN 09 ENDDO 10 DLTF FILE(QTEMP/DIRLIST) 11 MONMSG MSGID(CPF0000) 12 OVRDBF FILE(STDOUT) TOFILE(QTEMP/DIRLIST) + OVRSCOPE(*CALLLVL) 13 QSH CMD('ls -lt *.*') 14 DLTOVR FILE(STDOUT) LVL(*) 15 ENDPGM
Line 1-4 should be familiar to everyone. Line 1 marks the start of the program and that there are two parameters passed to the program, &PATH which is the IFS directory and &ERROR which will return a code to the calling program if an error is encountered. Those variables are declared in lines 2 and 3. On line 4 &ERROR is blanked, i.e. no error was encountered.
I decided to change the directory, using the CD command. This way if the user is not authorized to the directory then this can be captured by a MONMSG, line 6, and an "error" returned to the calling program, lines 7 and 8.
Line 10 deletes the file is going to contain the output from the LS.
When you use Qshell its output is written to your display, which is known as the STDOUT. As I want the output to be written to a file I can override STDOUT to a file, line 12.
Line 13 is where I execute the ls command in Qshell, QSH. Notice that ls is followed by -lt, these are arguments used by the command, like parameters, to describe the type of output I want. Do remember Qshell is Unix-like, therefore, it is case sensitive. Lower case 'l' is not the same as upper case 'L'. 'l' means I want a long listing format, and 't' sorted by file modification time.
Line 14 deletes the override of the STDOUT, and the program ends on line 16.
The file produced is a source file. All source files have the same three fields:
Data Field Field Type Length SRCSEQ ZONED 6 2 SRCDAT ZONED 6 0 SRCDTA CHAR 254
The data we are interested in is in the SRCDTA field:
....+....1....+....2....+....3....+....4....+....5....+....6....+....7....+....8 SRCDTA -rwxrwxrwx 1 MYLIB 0 4 Oct 3 09:54 test.txt
|Link count (file)||12||2|
|File date stamp||47||12|
If there are no files in the directory the SRCDTA field looks like:
....+....1....+....2....+....3....+....4....+....5....+....6....+....7....+....8....+....9 SRCDTA ls: 001-2113 Error found getting information for object *.*. No such path or directory.
For testing I created an RPGLE to extract the data I want from SRCDTA:
if (%subst(SRCDTA:5:9) = '001-2113') ; Error = 'No files' ; else ; User = %subst(SRCDTA:15:8) ; DateTime = %subst(SRCDTA:47:12) ; FileName = %subst(SRCDTA:60:100) ; endif ;
With this information now I can write my program to present the user with a subfile that will allow them to select the file they want to process.
You can learn more about these on the IBM website:
- Change Directory CL command CD
- Qshell CL command QSH
- Retrieve Directory Information CL command RTVDIRINF
And not from IBM:
This article was written for IBM i 7.2, and it should work with earlier releases too.