The NetRexx Tutorial
- Additional Instructions
NetRexx Tutorial - Additional Instructions


Additional Instructions

Introduction.

We collect here all those instructions that have we have not so far had the pleasure to comment on or show, because they did not fall into any of the categories we looked at. This does not imply that they are any less important.

Arrays

The xarray function package

 
+----------------------------------------------------------------------+
| -- method......: dump                                                |27
| -- purpose.....: dump array's contents                               |28
| --                                                                   |29
|   method dump(a=rexx[],name) public static                           |30
|     len = a.length                                                   |31
|     fil = name'(dim='len')'                                          |32
|     fil = fil.left(10)                                               |33
|     oval  = 'DUMMY'                                                  |34
|     skip  = 0                                                        |35
|     dosay = 0                                                        |36
|     loop i = 0 to len-1                                              |37
|       if a[i] = NULL                                                 |38
|         then val = 'NULL'                                            |39
|         else val = a[i]                                              |40
|       dosay = 0                                                      |41
|       if val = oval                                                  |42
|         then skip = skip+1                                           |43
|         else dosay = 1                                               |44
|       if i = len-1 then dosay = 1                                    |45
|       if dosay then                                                  |46
|         do                                                           |47
|           if skip > 0 then                                           |48
|             do                                                       |49
|               if (i = len - 1) then skip = skip - 1                  |50
|               if skip > 0 then say fil '(...' skip 'lines not display|51
|               if i <> len-1 then say fil '['i-1']' oval              |52
|               skip = 0                                               |53
|             end                                                      |54
|           say fil '['i']' val                                        |55
|         end                                                          |56
|       oval = val                                                     |57
|       fil = ' '.copies(10)                                           |58
|     end                                                              |59
|     say                                                              |60
|                                                                      |61
+----------------------------------------------------------------------+
                                                 xarray.nrx(Method:dump)
Download the complete source for the xarray.nrx library

 
+----------------------------------------------------------------------+
| -- method......: copy                                                |51
| -- purpose.....: copy array's contents                               |52
| --                                                                   |53
|   method copy(a=rexx[],b=rexx[]) public static                       |54
|     System.arraycopy(a,0,b,0,a.length)                               |55
|                                                                      |56
+----------------------------------------------------------------------+
                                                 xarray.nrx(Method:copy)
Download the complete source for the xarray.nrx library

Code example no.1

Let's use the routines we've built in the xarray library.

 
+----------------------------------------------------------------------+
| -- arrex1.nrx                                                        |01
| -- Simple example of array handling                                  |02
| --                                                                   |03
|                                                                      |04
| a = rexx[10]            -- define array dimentions                   |05
| b = rexx[12]            --                                           |06
|                                                                      |07
| xarray.init(a,")       -- initialize array a                        |08
| a[0] = 'line1'          -- with some values                          |09
| a[1] = 'line2'                                                       |10
|                                                                      |11
| xarray.dump(a,'a')      -- look at a and b                           |12
| xarray.dump(b,'b')                                                   |13
|                                                                      |14
| xarray.copy(a,b)        -- copy a to b                               |15
|                                                                      |16
| b[0] = 'XXXXXXXXXXXX'                                                |17
| xarray.dump(a,'a')      -- look at a and b                           |18
| xarray.dump(b,'b')                                                   |19
|                                                                      |20
| exit 0                                                               |21
+----------------------------------------------------------------------+
                                                              arrex1.nrx
Download the source for the arrex1.nrx example

Non NetRexx Arrays

In this small example we consider how to deal with non NetRexx (Rexx) arrays.

 
+----------------------------------------------------------------------+
| -- tstring.nrx                                                       |01
| -- small example of String[] handling                                |02
| --                                                                   |03
|                                                                      |04
| class tstring1 public                                                |05
|                                                                      |06
|   method t1() returns String[] public static                         |07
|     s = String[2]                                                    |08
|     s[0] = 'Francesca'                                               |09
|     s[1] = 'Elisabetta'                                              |10
|     say s.length                                                     |11
|     return s                                                         |12
|                                                                      |13
|   method main(args=String[]) public static                           |14
|     arg = rexx(args)                                                 |15
|     parse arg .                                                      |16
|                                                                      |17
|     in = String[100]                                                 |18
|     in = t1()                                                        |19
|     loop i = 0 to in.length - 1                                      |20
|       say in[i]                                                      |21
|     end                                                              |22
|                                                                      |23
|     line = rexx(in)                                                  |24
|     say line                                                         |25
|     exit 0                                                           |26
+----------------------------------------------------------------------+
                                                            tstring1.nrx
Download the source for the tstring1.nrx example

Byte Arrays conversion methods

Byte array handling is a bit tedious. This is the motivation of the methods described in xarray.

In a byte array, infact, the quantities are, from the NetRexx point of view, stored as signed integer, so it will be:

 
  a[0] = '01'       1
  a[1] = '81'    -127
  a[2] = 'FE'      -2
  a[3] = '41'      65
 

In order to convert it to HEX, for example, you'll need to follow the procedure:

 
  ch = rexx a[2]   -> -2
  ch = ch.d2x(2)   -> FE
 

The methods we've developed are:

 
 xarray.ba2x(array,start,length)
 xarray.ba2c(array,start,length)
 xarray.ba2d(array,start,length)
 xarray.bagrepx(array,HEX,start)
 

Using the a[] array, we can look at some simple examples, like:

 
                              will give:
                              ----------
xarray.ba2x(a,1,2)         -> 81FE

xarray.ba2c(a,3,1)         -> A

xarray.bagrepx(a,'81FE',0) -> 2

 

REMARK: those methods are SLOW! I should probably find a faster way to implement them. Suggestions are welcome!

Some sample routines

 
+----------------------------------------------------------------------+
| -- method......: ba2x                                                |57
| -- purpose.....: ByteArray to HEX                                    |58
| --                                                                   |59
|   method ba2x(a=byte[],start=rexx,length=rexx) public static         |60
|     ostr = ''                                                        |61
|     loop i = start to start + length - 1                             |62
|       ch = rexx a[i]                                                 |63
|       xch = ch.d2x(2)                                                |64
|       ostr = ostr||xch                                               |65
|     end                                                              |66
|     return ostr                                                      |67
|                                                                      |68
+----------------------------------------------------------------------+
                                                 xarray.nrx(Method:ba2x)
Download the complete source for the xarray.nrx library

The following method will search an ARRAY for an HEX quantity, which you write in the form (for example):

 
  'A0FF'
 

the methods returns the value of the FIRST occurrence (from the start) of the HEX string.

 
+----------------------------------------------------------------------+
| -- method......: bagrepx                                             |89
| -- purpose.....: grep an HEX qty in a ByteArray                      |90
| --                                                                   |91
|   method bagrepx(a=byte[],search=rexx,start=rexx) public static      |92
|     l = search.length()                                              |93
|     b = byte[l/2]                                                    |94
|                                                                      |95
|     -- convert the HEX string                                        |96
|     -- to decimal                                                    |97
|     --                                                               |98
|     list = search                                                    |99
|     i = 0                                                            |00
|     loop while list <> ''                                            |01
|       parse list nb +2 list                                          |02
|       b[i] = nb.x2d(2)                                               |03
|       i = i+1                                                        |04
|     end                                                              |05
|                                                                      |06
|     lend = a.length - 1                                              |07
|     match = 0                                                        |08
|     loop i = start to lend                                           |09
|       if a[i] == b[0] then                                           |10
|         do                                                           |11
|           match = 1                                                  |12
|           loop j = 1 to b.length - 1                                 |13
|             if b[j] <> a[i+j] then                                   |14
|               do                                                     |15
|                 match = 0                                            |16
|                 leave                                                |17
|               end                                                    |18
|           end                                                        |19
|           if match then leave                                        |20
|         end                                                          |21
|     end                                                              |22
|     if match                                                         |23
|       then return i                                                  |24
|       else return -1                                                 |25
|                                                                      |26
+----------------------------------------------------------------------+
                                              xarray.nrx(Method:bagrepx)
Download the complete source for the xarray.nrx library

Example: a JPEG info grabber

To apply the methods described above, let's write a small program that finds the size, in pixels, of a JPEG picture file.

Without going into details, we say that a JPEG (Joint Photographic Experts Group) file is a binary file. The header looks like:

 
  Marker: FF D8
        : FF E0 00 10
      ID: 4A 46 49 46 (== JFIF)
 

JFIF stands for JPEG File Interchange Format. The marker we look at is 'FFC0' that contains the image size.

 
+----------------------------------------------------------------------+
| -- grab info on JPEG file                                            |01
| --                                                                   |02
| parse arg fn .                                                       |03
| if fn = '' then                                                      |04
|   do                                                                 |05
|     say 'usage: java jpginfo FILEID'                                 |06
|     exit 1                                                           |07
|   end                                                                |08
|                                                                      |09
| -- read input file;                                                  |10
| -- if ERROR, abort                                                   |11
| --                                                                   |12
| fid = xfile(fn)                                                      |13
| rc = fid.readbuf()                                                   |14
| if rc <> 0 then                                                      |15
|   do                                                                 |16
|     say 'Error reading file "'fn'".'                                 |17
|     exit 2                                                           |18
|   end                                                                |19
| buf = fid.buffer                                                     |20
|                                                                      |21
| -- check for signature                                               |22
| --                                                                   |23
| si = xarray.ba2c(buf,6,4)                                            |24
| if si <> 'JFIF' then                                                 |25
|   do                                                                 |26
|     say 'Unable to find signature.'                                  |27
|     exit 3                                                           |28
|   end                                                                |29
|                                                                      |30
| -- find the marker                                                   |31
| --                                                                   |32
| p = xarray.bagrepx(buf,'FFC0',0)                                     |33
| if p = -1 then                                                       |34
|   do                                                                 |35
|     say 'Could not locate "FFC0" mark.'                              |36
|     exit 4                                                           |37
|   end                                                                |38
|                                                                      |39
| -- all OK,                                                           |40
| -- get the info                                                      |41
| --                                                                   |42
| w  = xarray.ba2d(buf,p+7,2)                                          |43
| h  = xarray.ba2d(buf,p+9,2)                                          |44
| say h'*'w                                                            |45
|                                                                      |46
| exit 0                                                               |47
+----------------------------------------------------------------------+
                                                             jpginfo.nrx
Download the source for the jpginfo.nrx example

Additional Readings.

 
For the graphics formats, look at:

http://wsspinfo.cern.ch/faq/graphics/fileformats-faq/part3

The Independent JPEG Group archive on ftp.uu.net contains an on-line
copy of the JFIF specification and additional JPEG information. Look at:

ftp://ftp.uu.net/graphics/jpeg/jfif.ps.gz
ftp://ftp.uu.net/graphics/jpeg/jpeg.documents.gz

 

The xsys.time() function.

We use the xsys.time() function to get the local time in the format "hh:mm:ss" (hours, minutes, seconds). The xsys.time() function can be called with arguments that change the output format a little. The complete list of arguments is:

 
  N  -   hh:mm:ss          - Normal (the default);
  C  -   hh:mmxx           - Civil
  L  -   hh:mm:ss.uuuuu    - Long
 
  H  -   hh                - Hours
  M  -   mmmm              - Minutes
                             (minutes since midnight)
  S  -   ssss              - Seconds
                             (seconds since midnight)
 
 

The best way to see all those options is to write a small program that shows all of them. The small timeexa1 program does it.

 
+----------------------------------------------------------------------+
| -- simple test of the xsys.time()                                    |01
| -- function                                                          |02
|                                                                      |03
| list = 'N C H M S Z'                                                 |04
| loop while list <> ''                                                |05
|   parse list kind list                                               |06
|   say xsys.time(kind)                                                |07
| end                                                                  |08
| exit 0                                                               |09
+----------------------------------------------------------------------+
                                                            timeexa1.nrx
Download the source for the timeexa1.nrx example

Here is what you get if you run it. The output will of course depends on the time at which you run it.

 
....................................................................
rsl3pm1 (68)  eti1
Option "N" returns:  17:46:30
Option "H" returns:  17
Option "M" returns:  1066
Option "S" returns:  63990
Option "L" returns:  17:46:30.121
Option "C" returns:  5:46pm
Option "Z" returns:  GMT
rsl3pm1 (69) 
....................................................................

Time your programs with a timer class.

The problem

You usually need to measure time intervals in your programs. In this way you can measure how long an operation takes to perform.

You can use the Java System class System.currenttimemillis()time method, and measure the time differences yourself.

 
  now = System.currenttimemillis  
 

This method returns the current time in milliseconds GMT since the EPOCH (00:00:00 UTC, January 1, 1970).

The numbers returned are BIG

The idea.

We define then a timer class. The two basic instructions are:

 

(...)
-- define a timer
timer1 = timer()
(...)

(...)
-- get the elapsed time
elapsed = timer1.elapsed()
   (to get the elapsed time since the LAST reset)
(...)

(...)
-- reset the timer
zero = timer1.reset()
   (to reset the timer)
(...)

 

The timer class implementation

 
+----------------------------------------------------------------------+
| -- method......: elapsed
                                            |46
| -- purpose.....: returns the elapsed time in SSSS.MMM
               |47
| --
                                                                  |48
|   method elapsed() public returns Rexx
                              |49
|     current = System.currenttimemillis
                              |50
|     numeric digits 16
                                               |51
|     delta = current - start
                                         |52
|     delta = delta/1000
                                              |53
|     numeric digits 9
                                                |54
|     delta = delta.format(NULL,3)
                                    |55
|     return delta
                                                    |56
| 
                                                                    |57
+----------------------------------------------------------------------+
                                                xsys.nrx(Method:elapsed)
Download the complete source for the xsys.nrx library

 
+----------------------------------------------------------------------+
| -- method......: reset
                                              |29
| -- purpose.....: reset the timer; returns '0.000' seconds
           |30
| --
                                                                  |31
|   method reset() public returns Rexx
                                |32
|     start = System.currenttimemillis
                                |33
|     return '0.000'
                                                  |34
| 
                                                                    |35
+----------------------------------------------------------------------+
                                                  xsys.nrx(Method:reset)
Download the complete source for the xsys.nrx library

The date() function.

 
*
* WARNING:
*   REXX's date function
*   will be implemented in xsys v2.000.
*
 

Use the date() instruction to get the current local date in the format 'dd Mmm yyyy'. As we saw for time() also date() has many options. These are:

 
 N  -  dd Mmm yyyy      - Normal;
 
 E  -  dd/mm/yy         - European;
 U  -  mm/dd/yy         - USA;
 O  -  yy/mm/dd         - Ordered;
 
 C  -  ddddd            - days (so far)
                          in this century;
 D  -  ddd              - say (so far)
                          in this year;
 
 S  -  yyyymmdd         - Standard;
 

As for time(), we do the same exercise also for date(). I simply write the results, since the program is easily modified from eti1.

 
....................................................................
rsl3pm1 (75) eda1
Option "N" returns:  () 5 Feb 1995
 
Option "E" returns:  () 05/02/95
Option "U" returns:  () 02/05/95
Option "O" returns:  () 95/02/05
 
Option "S" returns:  () 19950205
Option "C" returns:  () 34734
Option "D" returns:  () 36
 
Option "M" returns:  () February
Option "W" returns:  () Sunday
 
rsl3pm1 (76) 
....................................................................
                                                            eda1.out

The xdate() function

The NetRexx xsys function xdate (for eXtended DATE) is the function for performing all imaginable operations related to date. The original code was developed for VM/CMS by Bernard Antoine of CERN/CN in IBM/370 assembler code. The version I describe here is a porting of that code done by its original author in pure NetRexx.

This code is totally platform independent, and is available on the WWW NetRexx Tutorial page (in the xsys library). xdate can be used in two ways:

 
 
 - to display a certain date
   in a given output format
   (ex: xsys.xdate('TODAY','U') )
 
 - to perform a conversion of a date
   from one format to another
   (ex: xsys.xdate('E','01/12/95','J') )
 
 

The valid input formats are:

 
  D,ddd             - number of days since the beginning of the year
                      format;

  J,[yy]yyddd       - julian format;

  S,[yy]yymmdd      - sorted format;

  O,[[yy]yy/]mm/dd  - ordered format;

  E,dd/mm[/[yy]yy]  - European format;

  U,mm/dd[/[yy]yy]  - USA format;

  B,nnnn            - number of days since  the January 1st, 0001
                      format;

  C,nnnn            - number of days since the beginning of the
                      century format;

  K,[yy]yyww        - format according to ISO 2015 & 2711;

  I,nnnn            - incremental format;

  I,+nnnn

  I,-nnnn
 

Output_format may be any single character accepted by the REXX DATE function:

 
  O   to obtain the date in ordered form, i.e. yy/mm/dd

  U   to obtain the date in USA form, i.e. mm/dd/yy

  E   to obtain the date in European form, i.e. dd/mm/yy

  S   to obtain the date in 'sorted' form, i.e. yyyymmdd

  J   to obtain the date in julian form, i.e. yyddd

  B   to obtain the number of days since  the January 1st, 0001

  C   to obtain the number of days since the beginning of
      the century

  D   to obtain the number of days since the beginning of the year

  M   to obtain the month name

  W   to obtain the weekday name
 

In addition, XDATE also accepts:

 
  I   to obtain the date in increment form Ñ i.e. relative to today

  K   to return the id of the current  week, in the form yyyyww
      (according to ISO 2015 & 2711)

  L   a logical value to tell if the year is a leap one or not

  N   to obtain the month num (instead of name as in M) in the range 1Ð12

  X   to obtain the weekday num (instead of name as in W) in the range 1Ð7
 

small xdate example

Here is a small example of the xdate function (look at the comments to see what the program really does):

 
+----------------------------------------------------------------------+
| -- xdt0                                                              |01
| -- Exercise a bit the XDATE functions                                |02
| --                                                                   |03
|                                                                      |04
| -- Get today's date                                                  |05
| --                                                                   |06
| say xmisc.xdate('TODAY')                                             |07
|                                                                      |08
| -- Get next monday's                                                 |09
| --                                                                   |10
| say xmisc.xdate('NEXT','MONDAY')                                     |11
|                                                                      |12
| -- convert 31 DEC 1994 in from European to Julian Format             |13
| --                                                                   |14
| say xmisc.xdate('E','31/12/94','J')                                  |15
|                                                                      |16
| -- find out which weekday I was born                                 |17
| --                                                                   |18
| say xmisc.xdate('E','28/09/67','W')                                  |19
|                                                                      |20
| -- find out which date will be in 1000 days                          |21
| --                                                                   |22
| say xmisc.xdate('I',1000,'E')                                        |23
|                                                                      |24
| -- find out how many days I have                                     |25
| --                                                                   |26
| say xmisc.xdate('TODAY','C') - xmisc.xdate('E','28/09/67','C')       |27
|                                                                      |28
| -- find out when I'll have 20000 days                                |29
| --                                                                   |30
| nn = xmisc.xdate('TODAY','C') - xmisc.xdate('E','28/09/67','C')      |31
| nn = 20000 - nn                                                      |32
| say xmisc.xdate('I', nn , 'S')                                       |33
|                                                                      |34
| say 'Today is:' xmisc.date('E')                                      |35
| say '         ' xmisc.date('W')                                      |36
|                                                                      |37
| exit                                                                 |38
+----------------------------------------------------------------------+
                                                                xdt0.nrx
Download the source for the xdt0.nrx example

NOTEs: And here is the output:

 
....................................................................
rsl3pm1 (39) java xdt0
5 Feb 1995
94365
Thursday
01/11/97
9992
20220701
rsl3pm1 (40) 
....................................................................
                                                            xdt0.out

If you are wondering about all the possible output formats, here is a program for showing them:

 
+----------------------------------------------------------------------+
| -- xdt1.nrx                                                          |01
| -- exercise all XDATE formats                                        |02
| --                                                                   |03
|                                                                      |04
| kind = 'O U S J B C D M W I K L N X'                                 |05
| loop while kind <> ''                                                |06
|    parse kind item kind                                              |07
|    date = xmisc.xdate('TODAY',item)                                  |08
|    say 'Format "'item'" is: 'date'.'                                 |09
| end                                                                  |10
| exit 0                                                               |11
+----------------------------------------------------------------------+
                                                                xdt1.nrx
Download the source for the xdt1.nrx example

And this is what you will get if you run the program:

 
....................................................................
rsl3pm1 (43) java xdt1
Format "O" is: 95/02/05.
Format "U" is: 02/05/95.
Format "S" is: 19950205.
Format "J" is: 95036.
Format "B" is: 728328.
Format "C" is: 34734.
Format "D" is: 36.
Format "M" is: February.
Format "W" is: Sunday.
Format "I" is: 0.
Format "K" is: 199505.
Format "L" is: 0.
Format "N" is: 2.
Format "X" is: 7.
rsl3pm1 (44) 
....................................................................
                                                            xdt1.out

The xsys.sleep() function.

It is often usefull to sleep() N seconds. The easyest way is to call the Thread.sleep() function:

 
-- just pause MILLISEC
Thread.sleep(MILLISEC)
 

where MILLISEC is the time you want to sleep (expressed in milliseconds).

Complex Data Structures

As we saw in the previous chapters, there is ONLY one native data type in NetRexx, and that is the string. NetRexx considers even the numbers as strings. Indeed, you can build yourself data types, the most useful one being the following:

 
 list (string)       (stem)
   =
 'ITEM1' ,     --->  value[ITEM1]
 'ITEM2' ,     --->  value[ITEM2]
 'ITEM3' ,     --->  value[ITEM3]
 (...)
 'ITEMN'       --->  value[ITEMN]
 
 

We have a string that holds a list of items, which are in their turn pointers for an array (or for many arrays) holding the data for that particular array.

A case study: printer accounting

We want to see how this data structure works in practice. An accounting program may be the best way. Supposing we are producing some accounting records whenever an user prints something on a printer, an accounting record is generated. The format of these records would be the following:

 
  date userid nodeid printerid no_of_pages
 

where:

 
  date.......: the date in the format YYMMDDhhmmss;
  userid.....: the user identifier;
  nodeid.....: the node he used to print from;
  printerid..: the name of the printer;
  no_of_pages: how many pages he printed.
 
 

Here is a small (usually this kind of files is MUCH bigger) example of such a file:

 
+------------------------------------------------------------------+
| 110195110233 mount slil308.cern.ch prt21 200                     |
| 110195120000 marchesi rsl3pm1.cern.ch prt56 82                   |
| 120195120340 marchesi rsl3pm1.cern.ch prt56 20                   |
| 120195123030 mount hpl3sn1.cern.ch prt11 1                       |
| 120195123400 clare shift31.cern.ch prt11 25                      |
+------------------------------------------------------------------+
                                                       printer.CARDS

The structure of our accounting program will be:

 
  READ the accounting file
  REDUCE the data
  POST processing (if any)
  DISPLAY results
 

First Version

In our first version for this program, we simply want to see how many pages a user has printed. The following program (called pracc) will do it. In the first portion of the code, we check for the input argument and read a file. We will not go into the details: what we do is simply get the lines of the accounting cards into the array infid.line[].

 
+----------------------------------------------------------------------+
| /* prologue                                                          |01
|  */                                                                  |02
| parse arg fid .                                                      |03
| if fid = '-h' then                                                   |04
|   do                                                                 |05
|     say 'usage pacc <fid>'                                           |06
|     exit 3                                                           |07
|   end                                                                |08
| if fid = '' then fid = 'printer.CARDS'                               |09
| if \xfile.fexist(fid) then                                           |10
|   do                                                                 |11
|     say 'file "'fid'" does not exist.'                               |12
|     exit 4                                                           |13
|   end                                                                |14
| infid = xfile(fid)                                                   |15
| rc = infid.read()                                                    |16
| if rc <> 0 then                                                      |17
|   do                                                                 |18
|     say 'RC:' rc 'from READ.'                                        |19
|     exit 3                                                           |20
|   end                                                                |21
|                                                                      |22
+----------------------------------------------------------------------+
                                                               pracc.nrx
Download the source for the pracc.nrx example

We are now ready to analyse our data ,i.e. the lines contained in the stem CARDS. As you can see, we loop over the accounting cards Ñ from the first over to the last one. We parse the information contained in a card line 28. We check if the user contained in the card is known. If not, we add the user to the 'known users' list (user_list), and just for double security, we initialise the number of pages printed to 0 (line 32). We then add the pages for this accounting card to the total for the user.

 
+----------------------------------------------------------------------+
| /* Data Collection                                                   |23
|  */                                                                  |24
| user_list = ''                                                       |25
| pages_printed_by = 0                                                 |26
| loop i = 1 to infid.lines                                            |27
|   parse infid.line[i] date user node printer pages                   |28
|   if user_list.wordpos(user) = 0 then                                |29
|     do                                                               |30
|       user_list = user_list user                                     |31
|     end                                                              |32
|   pages_printed_by[user] = pages_printed_by[user] + pages            |33
| end                                                                  |34
|                                                                      |35
+----------------------------------------------------------------------+
                                                               pracc.nrx
Download the source for the pracc.nrx example

If we take the data we showed in the example printer.CARDS, this is what we get at the end of the code:

 
  user_list = 'mount marchesi clare'
 
  pages_printed_by.mount = 201
  pages_printed_by.marchesi = 102
  pages_printed_by.clare = 25
 

Now that the raw data is reduced in this format, we can do whatever we want over it: order by name of the user the user_list, order by number of printed pages, etc. We can even do nothing, such as here:

 
+------------------------------------------------------------------+
| /* post process                                                  |37
|  */                                                              |38
+------------------------------------------------------------------+

Now we can display the 'reduced' data. This is just a loop over the users, and each time we will display the user and the pages printed.

 
+----------------------------------------------------------------------+
| /* display                                                           |36
|  */                                                                  |37
| list = user_list                                                     |38
| loop for list.words()                                                |39
|   parse list item list                                               |40
|   say item.left(12,'.')':' pages_printed_by[item].right(7)           |41
| end                                                                  |42
|                                                                      |43
| /* end                                                               |44
|  */                                                                  |45
| exit 0                                                               |46
+----------------------------------------------------------------------+
                                                               pracc.nrx
Download the source for the pracc.nrx example

That is all. Here is what you get from the program itself:

 
....................................................................
rsl3pm1 (23) java pracc2
mount.......:     201
marchesi....:     102
clare.......:      25
rsl3pm1 (24) 
....................................................................
                                                            pacc.out

A second version

Suppose that now your manager asks you to have the report not only for users, but ALSO for printers. The modifications are quite trivial you simply need to create a new list for the printers, and clone the logic you used so far:

 
+----------------------------------------------------------------------+
| /* prologue                                                          |01
|  */                                                                  |02
| (LIKE ABOVE)                                                         |03
|                                                                      |22
| /* Data Collection                                                   |23
|  */                                                                  |24
| user_list = ''                                                       |25
| printer_list = ''                                                    |26
| pages_printed_by = 0                                                 |27
| loop i = 1 to infid.lines                                            |28
|   parse infid.line[i] date user node printer pages                   |29
|   if user_list.wordpos(user) = 0 then                                |30
|     do                                                               |31
|       user_list = user_list user                                     |32
|     end                                                              |33
|   if printer_list.wordpos(printer) = 0 then                          |34
|     do                                                               |35
|       printer_list = printer_list printer                            |36
|     end                                                              |37
|   pages_printed_by[user] = pages_printed_by[user] + pages            |38
|   pages_printed_by[printer] = pages_printed_by[printer] + pages      |39
| end                                                                  |40
|                                                                      |41
| /* display                                                           |42
|  */                                                                  |43
| list = user_list                                                     |44
| loop for list.words()                                                |45
|   parse list item list                                               |46
|   say item.left(12,'.')':' pages_printed_by[item].right(7)           |47
| end                                                                  |48
|                                                                      |49
| list = printer_list                                                  |50
| loop for list.words()                                                |51
|   parse list item list                                               |52
|   say item.left(12,'.')':' pages_printed_by[item].right(7)           |53
| end                                                                  |54
+----------------------------------------------------------------------+
                                                              pracc2.nrx
Download the source for the pracc2.nrx example

And this is what you will get on your screen:

 
....................................................................
rsl3pm1 (58) pacc2
Users:
clare.......:      25
marchesi....:     102
mount.......:     201
Printers:
prt11.......:      26
prt21.......:     200
prt56.......:     102
rsl3pm1 (59) 
....................................................................
                                                           pacc2.out

Linked Lists

Another kind of data structure are linked lists. With NetRexx you can easily simulate a linked list data structure. I remind you of what a linked list is:

 
POINTER  --->  data.1   +-->  data.2
                        |
               info.1   |     info.2
                        |
               next.1 --+     next.2 --> NULL
 

Case study: a ps tree.

A good case study for the linked lists is a program for building a ps command tree. The UNIX ps command is used to show the current status of processes running on your machine. Each process has an id (the processid) and a parent process (also called ppid). The output of the ps command does not immediately show how a process is "linked" in terms of parent process to the previous ones. Here is a typical example:

 
....................................................................
rsl3pm1 (226) ps -f
    USER   PID  PPID   C    STIME    TTY  TIME CMD
marchesi  8161 13399   6 20:35:42  pts/4  0:00 rexx ps1
marchesi 10723 13026   3 20:35:42  pts/4  0:00 bsh bsh bsh
marchesi 13026  8161   1 20:35:42  pts/4  0:00 rexx ps1
marchesi 13399  9555   1   Jan 25  pts/4  0:06 -usr/local/bin/tcsh
marchesi 14564 10723   8 20:35:42  pts/4  0:00 ps -f
rsl3pm1 (227) 
....................................................................
                                                             ps1.out

For our discussion, the important columns are the second and the third: the process that started all is the PID 13399; it generated PID 8161; which generated 13026; which executed 10723; which finally executed 14564 (and fortunately for us, nothing else other than printing what you see here). This is an "easy" case: if we had done a 'ps -ef', you would have got even more than 100 processes in no particular order. Our pstree wants to make order in this 'mess', and see how each process is linked by the parental relationship. The following code does the job. We skip all the 'unrelevant' portion of the program, since it does not add anything to our discussion. The first thing we do is execute the ps command with the proper options, depending on whether we want to see all the processes of the system ps -ef or just the ones belonging to us ps -f.

 
+------------------------------------------------------------------+
| if all                                                           |42
|   then rc = xexec('ps -ef' , 'ARRAY' , 'ABORT')                  |43
|   else rc = xexec('ps -f'  , 'ARRAY' , 'ABORT')                  |44
+------------------------------------------------------------------+

We reorder copy the array out[] into the array ps[]. We skip the very first line of the ps command output.

 
+------------------------------------------------------------------+
| j = 0                                                            |45
| loop i = 2 to out[0]                                             |46
|   j = j+1                                                        |47
|   ps[j] = out[i]                                                 |48
| end                                                              |49
| ps[0] = out[0] -1                                                |50
+------------------------------------------------------------------+

We now create two lists: the pidl is a string containing all the process_ids, while the ppidl is a string containing all the processes that are parents. The full information about the process is stored in the array info[PID] and the parent for each process is in ppid[PID]

 
+------------------------------------------------------------------+
| pidl  = ''                                                       |52
| ppidl = ''                                                       |53
| do i = 1 to ps[0]                                                |54
|   parse ps[i] . pid ppid .                                       |55
|   pidl = pidl pid                                                |56
|   ppidl = ppidl ppid                                             |57
|   info[pid] = ps[i]   -- full process info                       |58
|   ppid[pid] = ppid    -- parent                                  |59
| end                                                              |60
+------------------------------------------------------------------+

We loop over the process list. We look for the processes that are not parents of other processes. Those processes are saved in lastl: they are the last in a chain of processes.

 
+------------------------------------------------------------------+
| list  = pidl                                                     |62
| lastl = ''                                                       |63
| loop list.words()                                                |64
|   parse list item list                                           |65
|   if ppidl.wordpos(item) = 0 then                                |66
|     do                                                           |67
|       lastl = lastl item                                         |68
|     end                                                          |69
| end                                                              |70
+------------------------------------------------------------------+

Now the most tricky part. We start from all the processes in lastl and go backwards. This is where we use the pseudo linked list. For each process in lastl we build the chain with the processes in order of generation.

 
+------------------------------------------------------------------+
| list = lastl                                                     |72
| loop list.words()                                                |73
|   parse list item list                                           |74
|   titem = ppid[item]                                             |75
|   chain[item] = titem item                                       |76
|   loop forever                                                   |77
|     titem = ppid[titem]                                          |78
|     if pidl.wordpos(titem) = 0 then leave                        |79
|     chain[item] = titem chain[item]                              |80
|   end                                                            |81
| end                                                              |82
+------------------------------------------------------------------+

Et voila': we have now only to print this chain.

 
+------------------------------------------------------------------+
| list = lastl                                                     |84
| loop list.words()                                                |85
|   parse list item list                                           |86
|   llist = chain[item]                                            |87
|   say ' '                                                        |88
|   loop llist.words()                                             |89
|     parse llist item2 llist                                      |90
|     parse info[item2] owner p1 p2 . rest                         |91
|     say p1.left(6) p2.left(6) '['owner']'left(,10) rest.left(50) |92
|   end                                                            |93
| end                                                              |94
+------------------------------------------------------------------+

A short output example:

 
....................................................................
rsl3pm1 (231) pstree -a
 
(...)
 
1      0      [root]       Jan 19      -  9:28 /etc/init
2584   1      [marchesi]   Jan 19  hft/0  0:01 -tcsh
5668   2584   [marchesi]   Jan 19  hft/0  0:00 xinit
6698   5668   [marchesi]   Jan 19  hft/0  0:19 mwm
7220   6698   [marchesi]   Jan 19      -  0:16 aixterm
8765   7220   [marchesi]   Jan 19  pts/0  0:01 -tcsh
12329  8765   [marchesi]   Jan 24  pts/0  0:00 rlogin sgil301 -l f
13610  12329  [marchesi]   Jan 24  pts/0  0:00 rlogin sgil301 -l f
 
1      0      [root]       Jan 19      -  9:28 /etc/init
9555   1      [marchesi]   Jan 25  hft/0  1:16 aixterm
13399  9555   [marchesi]   Jan 25  pts/4  0:06 -usr/local/bin/tcsh
8174   13399  [marchesi] 20:59:12  pts/4  0:00 rexx pstree -a
13039  8174   [marchesi] 20:59:13  pts/4  0:00 rexx pstree -a
10736  13039  [marchesi] 20:59:13  pts/4  0:00 bsh bsh bsh
14577  10736  [marchesi] 20:59:13  pts/4  0:00 ps -ef
 
1      0      [root]       Jan 19      -  9:28 /etc/init
7746   1      [marchesi]   Jan 19  hft/0  6:15 aixterm
9030   7746   [marchesi]   Jan 19  pts/2  0:03 -usr/local/bin/tcsh
15292  9030   [marchesi] 20:14:31  pts/2  0:48 x rxuser.texinfo
rsl3pm1 (231) 
....................................................................
                                                          pstree.out

Additional information on Data Structures

You can find additional information about data structures in Java at those URLs:

 
http://www.geocities.com/SiliconValley/Way/7650/javadata.html

http://www.objectspace.com/jgl/
 
 
 *** This section is: 
  
 *** and will be available in next releases

Summary

A resume' of the main concepts encountered in this chapter.

 
 *** This section is: 
  
 *** and will be available in next releases


File: nr_26.html.

The contents of this WEB page are Copyright © 1997 by Pierantonio Marchesini / ETH Zurich.

Last update was done on 18 May 1998 21:48:01(GMT +2).