How Do I?

Why is this Job suddenly failing?

A customer e-mailed us with a report saying that suddenly their job started failing on a blank line after exiting a program. The blank line had always been there but it suddenly started to be a problem.

Here is the job stream source.

!job jtest01,mgr.acct,neil                                
!comment blank line after exit from query
!purge file1x
!query
exit

!showjcw jcw
!showjcw cierror
!purge file1x
!eoj
Fails:
:JOB JTEST01,MGR.ACCT,NEIL.
Priority = DS; Inpri = 8; Time = UNLIMITED seconds.
Job number = #j15161.
TUE, FEB  9, 2010, 12:04 PM.
HP3000  Release: C.70.00   User Version: C.70.00
MPE/iX  HP31900 C.39.06  Copyright Hewlett-Packard 1987.
All rights reserved.
STREAMED BY NEIL,MGR.ACCT (#S240) ON LDEV# 5
   STREAM DATE:   TUE, FEB  9, 2010, 12:03 PM
********************* CALVIN  A400 *************************
***   This is a private system operated for Robelle's    ***
***   company business.  Authorization from Robelle is   ***
***   required to use this system.                       ***
***   Use by unauthorized persons is prohibited.         ***
************************************************************
:comment blank line after exit from query
:purge file1x
      ^
File "FILE1X.NEIL.ACCT" not found.  No purge done. (CIWARN 383)
:query


HP32216N.03.18  QUERY/NM  TUE, FEB  9, 2010, 12:04 PM
COPYRIGHT HEWLETT-PACKARD CO. 1976

exit


END OF PROGRAM

Missing colon before command name. (CIERR 981)
REMAINDER OF JOB FLUSHED.
CPU sec. = 2.  elapsed min. = 1.  TUE, FEB  9, 2010, 12:04 PM.
Doesn't fail?
:JOB JTEST01,MGR.ACCT,NEIL.
Priority = DS; Inpri = 8; Time = UNLIMITED seconds.
Job number = #j15163.
TUE, FEB  9, 2010, 12:09 PM.
HP3000  Release: C.70.00   User Version: C.70.00
MPE/iX  HP31900 C.39.06  Copyright Hewlett-Packard 1987.
All rights reserved.
STREAMED BY NEIL,MGR.ACCT (#S240) ON LDEV# 5
   STREAM DATE:   TUE, FEB  9, 2010, 12:07 PM
********************* CALVIN  A400 *************************
***   This is a private system operated for Robelle's    ***
***   company business.  Authorization from Robelle is   ***
***   required to use this system.                       ***
***   Use by unauthorized persons is prohibited.         ***
************************************************************
:comment blank line after exit from query
:purge file1x
      ^
File "FILE1X.NEIL.ACCT" not found.  No purge done. (CIWARN 383)
:query

HP32216N.03.18  QUERY/NM  TUE, FEB  9, 2010, 12:09 PM
COPYRIGHT HEWLETT-PACKARD CO. 1976

exit

:showjcw jcw
JCW = 0
:showjcw cierror
CIERROR = 383
:purge file1x
      ^
File "FILE1X.NEIL.ACCT" not found.  No purge done. (CIWARN 383)
:eoj
CPU sec. = 2.  elapsed min. = 1.  TUE, FEB  9, 2010, 12:09 PM.
So the question is what is the difference between the two jobs. Why does one fail and not the other?

The difference between the two jobs is actually Query. In the first instance where the job does fail is the run of query is done via a file command.

In the second instance where Query does not fail, the run of query is done via path resolution.

The tricky part of this is of course that their is no way to tell from the job stream.

You can use help to tell the difference:

Path Resolution or Implied run.

:help query
PROGRAM FILE:  QUERY.PUB.SYS
Command File / UDC
:help query
USER DEFINED COMMAND FILE:  QUERY.NEIL.GREEN

run querynm.pub.sys

So we know that the difference in the two jobs is that the one that failed is the run of Query thru the command file. But Why?

Are blank lines Allowed?

Well first of all the trick here is to make sure a blank line is or isn't allowed. A quick test shows that any job with a blank line fails:

:comment blank line after comment

Missing colon before command name. (CIERR 981)
REMAINDER OF JOB FLUSHED.
CPU sec. = 1.  elapsed min. = 1.  TUE, FEB  9, 2010, 12:40 PM.

So we know for certain that a blank line does cause an abort in a job stream.

With this information, the real question becomes why didn't the job with the blank line after the exit fail, but rather why didn't it fail before?

The answer is that the lines are never executed. As shown below note the lines after the exit.

!comment lines after exit
!query
exit
Hi this is text after the run of query
it would be surprising to know
that this job still runs.
!showjcw jcw
!eoj
These lines never show up in the job stream when it is streamed.
:comment lines after exit
:query

HP32216N.03.18  QUERY/NM  TUE, FEB  9, 2010, 12:49 PM
COPYRIGHT HEWLETT-PACKARD CO. 1976

exit

:showjcw jcw
JCW = 0
:eoj
CPU sec. = 2.  elapsed min. = 1.  TUE, FEB  9, 2010, 12:49 PM.

Why?

So why are these lines ignored from $stdin (standard input).

What is happening is that in the job stream after the exit, the job doesn't really know where it is in the $stdin, the input commands to query, so it keeps reading until it sees the ! character.

This means that the lines after the exit and before the !showjcw are essentially thrown away. This re-orientation on where you are on the $stdin saves the job from failing on the blank lines or lines with garbage.

Why is my task with Dates not working?

Customers have been contacting us saying that task with $stddate and other date functions where a century needs to be assumed are no longer working or finding the incorrect records:
BASE mybase,5,pass
G SHIP-DATA
ITEM SHIP-DATE,DATE,MMDDYY
IF (($STDDATE(SHIP-DATE)>= 20100101 AND $STDDATE(SHIP-DATE)<= 20100131))
OUT TEMPSHIP,LINK
X
Well the reason for this is that the DEFAULT value for "cutoff" on what century to assume is 10. Therefore if you date field is January 15,2010, but in the form 011510, the year portion being 10 will have an assumed century of 19, because the default value for the cutoff year is 10.

The solution to this is to issue the command:

set date cutoff 15
or a similar number that will be greater than the oldest year of data that you want to have a 20 for the century.

Happily you do not need to add this command to every task but rather just add to your suprmgr files. On MPE this is suprmgr.pub.sys and on HP-UX this is /opt/robelle/suprmgr.

Why was the Cutoff at 10?

In 1998 when we did these changes we had to consider every type of date involved and we have a large number of customers that still had six digit dates with birthdates of 1913 etc. We also had real estate and Title dates that were in the 1910's as well and most customers said that 10 years it would be no problem for them to convert all their dates to including the century.

How Do I Convert CM Ksam to NM KSAM?

Suprtool can't/won't create a new NM KSAM file for you. You will have to create the new NM file first using the MPE BUILD command (or some other method, see below), then use Suprtool to copy the records from the old file to the new file.

But Suprtool should definitely be able to copy the data *much* faster than MPE's FCOPY utility could.

The trick, of course, is getting a new NM KSAM file built correctly first. You could use a complicated BUILD command or you could do this:

 :file n=newfile; disc=
 :fcopy from=oldfile; to=(*n); subset=0,1

That will create a new NM KSAM file called NEWFILE with the FLIMIT equal to the FLIMIT of your current CM file, and with all the keys set up correctly, but will copy only a single record into it. Then use Suprtool:

 :suprtool
 >in oldfile
 >out newfile, erase
 >xeq

Finally, if it's a big KSAM file you may wish to create it as temporary first, then SAVE it after you're done, to squeeze even more speed out of the process:

 :file n=newfile; disc=; temp     <<-- Note the temp designation
 :fcopy from=oldfile; to=(*n); subset=0,1
 :suprtool
 >in oldfile
 >out newfile, erase
 >exit
 :save newfile

How Do I print on HP-UX in Suprtool?

I recently came into my office this past Thursday morning to find two support e-mails asking very similar questions. How do I get output to print on a Unix device using Suprtools list command. While I certainly knew the answers in terms of Suprtool I had forgotten many of the other commands to figure out what printers I had available and some of the parameters to the lp command.

But let's backup and discuss the functionality that MPE and the Suprtool list command could provide thru file equations as this is the main question that users ask, which is How do I get the output from the list command to either a file or a device.

On MPE you can either do:

file suprlist;dev=lp
or
file suprlist=myfile;rec=-132;disc=100000;dev=disc

The first would send the output from the list command to the device LP and the second file equation would re-direct the output from the list command to a disc file. Well on HP-UX the concept of file equations doesn't exist. There is I/O re-direction but this can be cumbersome when you have to input the commands and filter the output so we specifically added options on the list command to allow for the same functionality.

How do I print a file on HP-UX?

To understand printing in Suprtool, it is beneficial to understand some methods to print on HP-UX. The most common method for printing a file is the lp command. You can get details on the command by doing a "man lp" .

A sample of an lp command that prints to a printer device called dragon:

 lp -ddragon t1.cc
request id is dragon-1387 (1 file)

What printers do I have?

This is all well and good, but how do I know what devices do I have on my system? One method is to do an:
lpstat -p
which means to output all printers. From that output you can determine the device names for various printers. lpstat -d prints your default printer and lpstat -a prints out all devices that are accepting output requests, which may be your best bet on a system with a large LP subsystem. Keep in mind that this assumes that the CUPS system is installed and enabled. If you want to know more about CUPS you can start with the wiki page at:
http://en.wikipedia.org/wiki/CUPS

The bottom line is that you can use lpstat to determine the device printer names that are on your system.

How do I Print to a device in Suprtool for HP-UX.

There are two ways to print to a device using Suprtool for HP-UX, these are very similar but are worth noting. The first is thru the Suprtool directly:
>in bla4
>list device dragon standard
>xeq
request id is dragon-1388 (standard input)
IN=272, OUT=272. CPU-Sec=1. Wall-Sec=1.
Suprtool opens a pipe to the device dragon and sends the output from the list command to that device and uses the lp command/program to output the file. So essentially when you enter the command list device dragon, Suprtool is sending the output to lp with the device of dragon, as in:
/usr/bin/lp -ddragon.
We also provide an environment variable to change the lp program from being used which by default is /usr/bin/lp to being whatever you to use specifying the ROBELLE_LP environment variable with the value of the other third party program:
export ROBELLE_LP=/usr/thirdparty/lp

How do I print to a file in Suprtool?

You can print to a file using Suprtools file option, what you can also do is append multiple reports:
>set list formfeed on
>in bla4
>list file myreport standard
>xeq      
IN=272, OUT=272. CPU-Sec=1. Wall-Sec=1.

>in bla3
>list file myreport append standard
>xeq
IN=272, OUT=272. CPU-Sec=1. Wall-Sec=1.
In addition with the set list formfeed on command you can put multiple reports in one file and have them print and do the page eject(s) between each report. So in the above example the list of bla4 would print out and then bla3 would print on a new page. As always if you have any feedback, questions or advice, please feel free to e-mail me at neil at robelle.com.

Move my Qedit for Windows Settings to a new PC?

A customer e-mailed us with the following question:

Is there any way to export the connections and other settings from QEDIT on one PC and load onto another?

Thanks.

Yes. The steps are very easy:

  1. Install Qedit on New PC.
  2. Run Qedit on New PC.
  3. Quit Qedit on New PC.
  4. Quit Qedit on the Old PC."
  5. Go to old PC and look for where QWIN.INI is on old PC.
  6. Look for QWIN.INI on NEW PC.
  7. Copy the following files from the OLD PC they will be in the same directory that you found QWIN.INI: QWIN.INI, QEDCONN.DAT,QWINDDB.DAT to the new PC, replacing them in the directory that you found them in.
  8. Start Qedit on the New PC, your settings etc should be there.
As a side bar it is probably a good idea to install the same version on each machine before moving files.

Find the Difference between two Dates in Months?

A customer called and asked how to find the difference between a Maturity date and Todays date.

First step, I change the matdate to be ccyymm and create a ccyymm for $today. Note that the Maturity date or matdate, is a dat field in the format of ccyymmdd and is in an I2 container.

 >in mature
 >form
     File: mature     (SD Version B.00.00)  Has linefeeds
        Entry:                     Offset
           MATDATE              I2      1
     Entry Length: 4  Blocking: 1
 >ext matdate=matdate / 100
 >def todaydt,1,4,double
 >item todaydt,date,ccyymm
 >ext todaydt=$today
 >out mature2,link
 >xeq
IN=20, OUT=20. CPU-Sec=1. Wall-Sec=1.
So the data now looks like this:
 >in mature2
 >list
 >xeq
 >IN mature2 (0) >OUT $NULL (0)
MATDATE         = 200906         TODAYDT         = 200907


 >IN mature2 (1) >OUT $NULL (1)
MATDATE         = 200907         TODAYDT         = 200907


 >IN mature2 (2) >OUT $NULL (2)
MATDATE         = 200908         TODAYDT         = 200907


 >IN mature2 (3) >OUT $NULL (3)
MATDATE         = 200909         TODAYDT         = 200907


 >IN mature2 (4) >OUT $NULL (4)
MATDATE         = 200910         TODAYDT         = 200907


 >IN mature2 (5) >OUT $NULL (5)
MATDATE         = 200911         TODAYDT         = 200907


 >IN mature2 (6) >OUT $NULL (6)
MATDATE         = 200912         TODAYDT         = 200907


 >IN mature2 (7) >OUT $NULL (7)
MATDATE         = 201001         TODAYDT         = 200907


 >IN mature2 (8) >OUT $NULL (8)
MATDATE         = 201002         TODAYDT         = 200907
Now the final step converts the dates to a month number and calculates the difference. :
SUPRTOOL/UX/Copyright Robelle Solutions Technology Inc. 1981-2009.
(Version 5.2 Internal)  WED, JUL 01, 2009,  8:12 PM  Type H for help.
in mature2
ext matdate
ext todaydt
def mmdiff,1,4,double
ext mmdiff=(($truncate(matdate / 100) * 12) + matdate mod 100) - &
     (($truncate(todaydt / 100) * 12) + todaydt mod 100)
list
xeq
 >IN mature2 (0) >OUT $NULL (0)
MATDATE         = 200906         TODAYDT         = 200907
MMDIFF          = -1


 >IN mature2 (1) >OUT $NULL (1)
MATDATE         = 200907         TODAYDT         = 200907
MMDIFF          = 0


 >IN mature2 (2) >OUT $NULL (2)
MATDATE         = 200908         TODAYDT         = 200907
MMDIFF          = 1


 >IN mature2 (3) >OUT $NULL (3)
MATDATE         = 200909         TODAYDT         = 200907
MMDIFF          = 2


 >IN mature2 (4) >OUT $NULL (4)
MATDATE         = 200910         TODAYDT         = 200907
MMDIFF          = 3


 >IN mature2 (5) >OUT $NULL (5)
MATDATE         = 200911         TODAYDT         = 200907
MMDIFF          = 4


 >IN mature2 (6) >OUT $NULL (6)
MATDATE         = 200912         TODAYDT         = 200907
MMDIFF          = 5


 >IN mature2 (7) >OUT $NULL (7)
MATDATE         = 201001         TODAYDT         = 200907
MMDIFF          = 6


 >IN mature2 (8) >OUT $NULL (8)
MATDATE         = 201002         TODAYDT         = 200907
MMDIFF          = 7


 >IN mature2 (9) >OUT $NULL (9)
MATDATE         = 201003         TODAYDT         = 200907
MMDIFF          = 8


 >IN mature2 (10) >OUT $NULL (10)
MATDATE         = 201004         TODAYDT         = 200907
MMDIFF          = 9


 >IN mature2 (11) >OUT $NULL (11)
MATDATE         = 201005         TODAYDT         = 200907
MMDIFF          = 10


 >IN mature2 (12) >OUT $NULL (12)
MATDATE         = 201006         TODAYDT         = 200907
MMDIFF          = 11


 >IN mature2 (13) >OUT $NULL (13)
MATDATE         = 201007         TODAYDT         = 200907
MMDIFF          = 12


 >IN mature2 (14) >OUT $NULL (14)
MATDATE         = 201008         TODAYDT         = 200907
MMDIFF          = 13


 >IN mature2 (15) >OUT $NULL (15)
MATDATE         = 201009         TODAYDT         = 200907
MMDIFF          = 14


 >IN mature2 (16) >OUT $NULL (16)
MATDATE         = 201010         TODAYDT         = 200907
MMDIFF          = 15


 >IN mature2 (17) >OUT $NULL (17)
MATDATE         = 201011         TODAYDT         = 200907
MMDIFF          = 16


 >IN mature2 (18) >OUT $NULL (18)
MATDATE         = 201012         TODAYDT         = 200907
MMDIFF          = 17


 >IN mature2 (19) >OUT $NULL (19)
MATDATE         = 201101         TODAYDT         = 200907
MMDIFF          = 18


IN=20, OUT=20. CPU-Sec=1. Wall-Sec=1.

Fix all of My Zip codes

Recently a customer asked how they could fix some of the Zip codes which were in the form of:

	123450000

and are stored in a numeric J2 field.

The customer wanted to normalize those zip codes that had the four trailing zeroes to be 12345 instead of 123450000.

The first step we wanted to do was to determine all of the codes that needed to be updated and what the old zip would be and what the new zip would be.

 >base membrs
 >get member-file
 >def new-zip,1,4,double
 >if zip > 99999 and (zip mod 10000) = 0
 >ext account
 >ext zip
 >ext new-zip = zip / 10000
 >list
 >xeq

So what is the above doing?

Well the if command looks at all records that are greater than 99999 and ends in the four zeroes, which is what the (zip mod 10000) = 0 is doing. This should isolate just those records that the customer wanted to fix!

Once we determined that we had the correct records selected we easily updated them with:

 >base membrs
 >get member-file
 >if zip > 99999 and (zip mod 10000) = 0
 >update
 >ext new-zip = zip / 10000
 >list
 >xeq

Import Data Using Suprtool

One of the more recent questions that has come up lately is How Do I Import data with Suprtool. Let's say we have the following data layout, Image, Eloquence or SD file, it doesn't matter. The purpose of this small white paper would be to extract data to a ".csv" file, and then import that same data back. Closing the loop so to speak.

To begin our project we will extract the data from a sample data source and output to an SD file and then use STExport to create a CSV file.

>get d-inventory
>out dinv,link
>xeq
IN=13, OUT=13. CPU-Sec=1. Wall-Sec=1.

:run stexport.pub.robelle
$in dinv
$out dinvcsv
$xeq
In=13. Out=13. CPU-Sec=1. Wall-Sec=1.
$listf dinvcsv,2

ACCOUNT=  GREEN       GROUP=  NEIL
FILENAME  code  ------------LOGICAL RECORD-----------  ----SPACE----
                  SIZE  TYP        EOF      LIMIT R/B  SECTORS #X MX

DINVCSV           152B  VA          13         13   1       16  1  *
So at this point we know have a file, typically how a customer would want to import using Suprtool for adding to a database etc. Note that Suprtool does not handle variable-length files so the first step is to convert the Variable length file to fixed length.

Step One: Convert to Fixed Length

On MPE you can convert using Fcopy:

/file dinvcsvf;rec=-152,1,f,ascii
/fcopy from=dinvcsv; to=*dinvcsvf;new
On HP-UX you can use Qedit:
/t dinvcsv
/set keep var off
/k dinvcsvf
Or Awk: (Thanks to Barry Lake from Allegro for fixify.sh)
#!/bin/sh
#
# Script to turn a typical bytestream file (variable length
# records) into a file with fixed length records by padding
# records with spaces as needed. The resulting record length
# will be that of the longest record in the file.

export INFILE=$1
OUTFILE=$(mktemp)

# Step 1: Find the length of the longest record in the input file
#         file and store it in a variable for use in the next step.

export MAXLEN=$(awk 'BEGIN { len = 0; }
  { if (length > len)
       len = length; }
  END { print len; }' $INFILE )

echo Maximum record length in \"$INFILE\" is $MAXLEN.

# Step 2: Get the MAXLEN variable; use it to create a string
#         of that many blanks; then use that to pad each input
#         record as needed to make it the same length as the
#         longest record.

awk 'BEGIN { "echo $MAXLEN" | getline maxlen; spaces = "";
             for(i=0; i < maxlen * 1; i++)
                spaces = " "spaces; }
  { print substr($0 spaces, 1, maxlen) }' $INFILE >$OUTFILE

# Step 3: awk can't edit a file in place so its output was
#         written to a new file which we then pour back into the
#         original file. Note: we could just as easily have done
#         cp $OUTFILE $INFILE or mv $OUTFILE $INFILE, but in that
#         case we'd lose the original file's creator and
#         permission bits.

cat $OUTFILE > $INFILE
rm $OUTFILE

You can run the above script:
$./fixify.sh datafile

At this point Suprtool can now read what is essentially variable-length data in a fixed length file.

Now remember what a typical CSV file looks like! Byte fields are surronded by quotes and separated or delimited with commas:

159,19910827,1,50532001,5053,9449,"Test index","Test index","Test index","Test index"

Step Two: Split out the Fields

The first step is to separate out each field from the record based on the delimeter, which in this case is the comma. I use byte lengths for each number field based on the rules for output ,ascii table.

Duplicated below:

  I1 J1 06 bytes      
  I2 J2 11 bytes
  I3 J3 16 bytes      
  I4 J4 20 bytes
  K1    05 bytes      
  K2    10 bytes
  Zn    n+1 bytes     
  Pn    n bytes

in dinvcsvf
{define targets}
def bin-x,1,6
def last-x,1,11
def qty-x,1,11
def prod-x,1,9
def supp-x,1,9
def cost-x,1,8
def desc1-x,1,22 {Note room for quotes}
def desc2-x,1,22
def desc3-x,1,22
def desc4-x,1,22

{define source}
def record,1,152

{extract using split }
 
ext bin-x=$split(record,first,",")
ext last-x=$split(record,",",1,",")
ext qty-x=$split(record,",",2,",")
ext prod-x=$split(record,",",3,",")
ext supp-x=$split(record,",",4,",")
ext cost-x=$split(record,",",5,",")
ext desc1-x=$split(record,",",6,",")
ext desc2-x=$split(record,",",7,",")
ext desc3-x=$split(record,",",8,",")
ext desc4-x=$trim($split(record,",",9,last))

{where?}
out myfile,link
xeq

Step Three: Closing the Loop

Now we just need to "close the loop" and extract the individual byte type fields into their appropriate data types. In this step we also "clean" the data of the double quotes.

Keep in mind that the data format that we want:

The defines for the above are in the section starting with the comment {Actual targets}

in myfile

{re-define number in display format}
def bin-z,bin-x,display
def last-z,last-x,display
def qty-z,qty-x,display
def prod-z,prod-x,display
def supp-z,supp-x,display
def cost-z,cost-x,display

{Actual targets}

{number}
def bin ,1,2,integer
def last,1,4,double
def qty ,1,4,double
def prod,1,8,display
def supp,1,8,display
def cost,1,4,packed

{bytes}
def desc1,1,20 
def desc2,1,20
def desc3,1,20
def desc4,1,20 

ext bin=$number(bin-z)
ext last=$number(last-z)
ext qty=$number (qty-z)
ext prod=$number(prod-z)
ext supp=$number(supp-z)
ext cost=$number(cost-z)

clean '"'
ext desc1=$trim($clean(desc1-x))
ext desc2=$trim($clean(desc2-x))
ext desc3=$trim($clean(desc3-x))
ext desc4=$trim($clean(desc4-x))

out loop,link
xeq

The SD file (loop) is now in the same format and layout of the original Dataset extraction prior to the STExport task. We've now closed the loop.

>form loop
    File: LOOP.NEIL.GREEN     (SD Version B.00.00)
       Entry:                     Offset
          BIN                  I1      1
          LAST                 I2      3
          QTY                  I2      7
          PROD                 Z8     11
          SUPP                 Z8     19
          COST                 P8     27
          DESC1                X20    31
          DESC2                X20    51
          DESC3                X20    71
          DESC4                X20    91
    Limit: 13  EOF: 13  Entry Length: 110  Blocking: 37

So to summarize the first step is to split out the data into separate fields with byte data types. Then to convert by re-defining with a new name to reference the data as display and use $clean and $number to extract into the final targets.

Generate Three Random Characters

A customer recently asked how they could use Suprtool to generate some random data. The answer is you can't. But Barry Durand came up with a reasonable Unix shell script, using something he found on the net.

Here is a script that called rand3:

a[0]=a; a[1]=b; a[2]=c; a[3]=d; a[4]=e; a[5]=f; a[6]=g; a[7]=h a[8]=i;
a[9]=j; a[10]=k;a[11]=l; a[12]=m; a[13]=n; a[14]=o; a[15]=p a[16]=q;
a[17]=r; a[18]=s; a[19]=t; a[20]=u; a[21]=v; a[22]=w a[23]=x; a[24]=y; 
a[25]=z; a[26]=1; a[27]=2; a[28]=3; a[29]=4 a[30]=5;
a[31]=6; a[32]=7; a[33]=8; a[34]=9; a[35]=0 
echo ${a[$RANDOM%36]}${a[$RANDOM%36]}${a[$RANDOM%36]}
./rand3.sh
gtj
./rand3.sh
7o2

Remove Trailing spaces

Someone asked how to remove trailing spaces on HP-UX. Here is one way:

pr -t INFILE >INFILE.spaces

Solving Floating Point Exception Errors

One of the more common tech calls we get is: my job aborted with Floating Exception(coredump) what is wrong?

First what is a Floating Point Exception.

A Floating point exception is an HP-UX specific arithmetic trap which occurs when the system encounters a character that it cannot deal with when converting to/from Floating Point. These errors occur in Suprtool and STExport for HP-UX, mainly because Suprlink just matches bytes, it doesn't try to transform the data in any manner. It is the transformation or coercion from one form to another where these FPEs occur. In Suprtool, it could be from nearly any type to nearly any other type. An FPE in Suprtool is typically a coercion error from one type TO floating point/display or packed.

Why?

This article will attempt to show how to find these errors and common reasons for these errors. The most significant and really the main reason for a coercion error is that we have bad data for the area defined for a given field that is being coerced. Now essentially there is only one reason for an FPE and that is that the low level routine that converts data from one type to another encounters a character that it cannot handle.

One of two possibilities exist:

  1. You've defined either the record size or the field position incorrectly such that you are pointing to the wrong spot.
  2. You really have bad data.

Most of the time we see that there is an incorrect definition of a field or record.

Wrong record size on Input file

in baddisp,rec 80,lf
def a,1,5,display
>if a=65312
>ext a
>out *
>xeq
65312
IN=6, OUT=1. CPU-Sec=1. Wall-Sec=1.
If we do essentially the same job, but get the record size wrong by one, we see the dreaded:

>in baddisp,rec 81,lf
>def a,1,5,display
>if a=65312
>out *
>xeq
Floating exception(coredump)

Remember that on Unix files are just a series of bytes, there is no record structure. So in the case above we read the first record and it lines up ok, however, the next record will start at the wrong spot and the coercion will fail.

Bad Field Definition:

Consider the following data:
more baddisp
01234                                                                           
21222                                                                          
00345                                                                     
12345                                                                           
54321xx                                                                    
65312xx

Note that the last two records have characters right beside them so if we get the definition of the beginning display field incorrect we will end up trying to interpret the record with the 4321x as display data, which will of course fail.

Now we show an incorrect field definition:

>in baddisp,rec 80,lf
>def a,2,5,display  {obviously wrong}
>if a<>65312
>out *
>ext a
>xeq
1234
1222
0345
2345
Floating exception(coredump)

We actually have bad data!

Once we've investigated the layout for the record and for the field there is the possibility that we may have bad data. Hidden characters or escape sequences or more often than not nulls. In Suprtool you can list the data in Hex format and look for Null (00), Tab (09), CR (0D) or Line Feed (0A). These are common "bad" characters found in fields. You can use the $clean function to clean out this data, or you would have to trace the bad data to the source.

How to find what is happening?

Where do I look first?

In any given task, really the first place to look is at the fields referenced in the if command. Concentrate on the Display and packed fields referenced in the if command.

You can see each record as it is read by using the out * command instead of output to some file. (Hint: Out * just means out to stdlist so it may not be useful if you have lots of fields). The List command to a file may be more useful, you could then tail the file to see where the problem was.

It is advisable at first to limit the number of records with the numrecs command while investigating these errors. Typically if a record definition and/or field definition are incorrect, then the abort will occur in the first few records so numrecs 10 command could save you waiting for a long listing to go to the screen.

It might not be the current task

It is important to note that the problem may not be in the current task. Consider again the following data:
more baddisp
01234                                                                           
21222                                                                           
00345                                                                           
12345                                                                           
54321xx                                                                         
65312xx 
In the first step below we just read the data and put into a self-describing file:
>in baddisp,rec 80,lf
>def a,2,5,display
>ext a
>out mydata,link
>xeq
IN=6, OUT=6. CPU-Sec=1. Wall-Sec=1.
Now in a later step we may reference the bad field and the abort will then occur. So sometimes you have to trace back a step to the one that created the file you are reading:
>in mydata
>form
    File: mydata     (SD Version B.00.00)  Has linefeeds
       Entry:                     Offset
          A                    Z5      1
    Entry Length: 5  Blocking: 1
>if a<>65213
>list
>xeq
>IN mydata (0) >OUT $NULL (0)
A               = 1234?

>IN mydata (1) >OUT $NULL (1)
A               = 1222?

>IN mydata (2) >OUT $NULL (2)
A               = 345?

>IN mydata (3) >OUT $NULL (3)
A               = 2345?
Floating exception(coredump)

Note that the "?" is a clue that you have a bad definition as Suprtool can handle spaces after numbers, but it aborts when it encounters the "x". Hopefully this gives you information on what a Floating exception is.

We are working on catching SIGFPE and trying to give more information about the circumstances in a future version of Suprtool, but for now the above are some of the techniques that you would likely need to use to find the bad data or bad definitions.

Comparing Files in Groups

I've been working on projects that requires that I have two copies of some of our source code modules and I want to compare all the files for the given groups to monitor the changes.

Here is an MPE/Qedit command file that will compare all the files in two groups. Keep in mind that this is dependent on the groups having the same number of files in the group and the same filenames.

parm group_one group_two                               
purge fg1,temp >$null
purge fg2,temp >$null
purge fgout,temp >$null
echo Comparing !group_one against !group_two
listf @.!group_one,6 >fg1
listf @.!group_two,6 >fg2
build fgout;rec=-256,1,f,ascii;disc=20000;temp
file fgout;acc=append
/set totals off   { No totals listed }
/tq fg1,text
/set length 256
/set right 256
/appendq "~" @
/addq last=fg2
/lsortq all
/glueq "~" @
/changeq 1 "compare " @
/changeq "~"," @
/changeq " ,"," @
/changeq " ,"," @
/changeq " ,"," @
/changeq " ,"," @
/changeq " ,"," @
/changeq " ,"," @
/changeq " ,"," @
/appendq ",tempout >$null" @
/appendq "~:if compareoutcount <> 0 then" @
/divideq "~" @
/changeq "~"" @
/appendq "~:fcopy from=tempout; to=*fgout >$null" "compareoutcount"
/divideq "~" @
/changeq "~"" @
/appendq "~:endif" "fgout"
/divideq "~" @
/changeq "~"" @
/useq *
reset fgout
/textq fgout,yes
/listq $r @
/set totals on
The command file essentially builds a list of compare commands and then if differences are found in the files, then the compare output is copied to a single file, which is listed on my attached printer at the end.

This is specific to my needs but is easily customizable. Feel free to send any comments or improvements to neil@robelle.com.

Control Where Temp Sort Space is Allocated

Occasionally we get calls and e-mails asking about sort scratch space on HP-UX and where Suprtool puts its Sort Scratch space. This is usally due to some job failing due to an out of disc spaces on a particular volume.

By default, Suprtool typically puts the temporary space it needs on /var/tmp. If this volume runs out of space when sorting data you may receive an error similar to this:

Error:  Failure in ROBSORT'INPUT routine
ROBSORT'INPUT Error 12
Unable to write to the RSORTSCR file (length = 27657)
No space left on device


Error:  ROBSORT'END Failed
ROBSORT'END Error 19
File system error
Error 0
You can control what directory/volumeset that Suprtool puts its temp sort scratch files by setting the TMPDIR variable prior to running Suprtool.
export TMPDIR=/home/bigsortspace
The above will cause Suprtool to create Suprtool temp file in the directory space /home/bigsortspace.

Installing Suprtool for Testing

Some customers have asked recently how to install the latest version of Suprtool without making it the production version.

An example of customers that are looking for this are some of the Ecometry customers that are migrating off of the HP 3000 and don't want to upgrade their production version of Suprtool or STExport but they want to use the clean features available in either Suprtool or STExport for migrating data off the 3000.

This HowDoI article will address these issues in the following manner:

  1. Discuss how to Install the most recent version of Suprtool without making it the production version.
  2. How to use the various clean features inside Suprtool and STExport.

Installing Latest Suprtool/Suprlink/STExport to Test

The following instructions are ONLY to give a method for users on MPE to install the program files from Suprtool to TEST or use new features. This can be done by anyone that wants to test the latest version of Suprtool, STExport and Suprlink.

The steps to do this are:

  1. Request codes:
    http://www.robelle.com/forms/request-prod-release.php
  2. Download the install packages from the next page:
    After you have requested codes you will be taken to a page to download the installation package. Once you have downloaded the Suprtool file you can follow the instructions for uploading the file to your HP3000, once that step is done you can use the following steps to just restore and enable the software for testing.
  3. Restore files
    Logon (or stay logged on) as manager.sys,pub to do the restore.
    :hello manager.sys,pub
    :file t=stprod;dev=disc
    :restore *t;@nm.pub.robelle;create;show=short
    :purge stprod
    :stream robelle.job.robelle
    
    Wait for the job to send you a completion message:

    ========= Robelle.Pub.Sys  =================
    =           Robelle account structure ready.
    ============================================
    

  4. Enable the Software

    :hello mgr.robelle,pub
    :Run extend.pub
    Please enter the Product Verification code : n
    Please enter the Verification code         : n
    Please enter the Second Verification code  : n
    

    Extend will cycle thru all the files and patch the files. You may get an error message such as:

    Error: Unable to open SUPRTOOL.PUB.ROBELLE
    EXCLUSIVE VIOLATION: FILE BEING ACCESSED (FSERR 90)
    

    This message just means that someone is running the program that extend tried to open this is not a problem unless it is one of the three files that need to be patched by this process which are:

    suprnm.pub.robelle
    linknm.pub.robelle
    stexpnm.pub.robelle

Once you have applied the codes you should be able to run Suprtool/STExport on their own.

run suprnm.pub.robelle
run stexpnm.pub.robelle.

When you restore the files you will get six files restored, but the other files will not impact anything. Please note that the methods above will not load the latest help files, which is typically what most customers want, and since the latest manuals are now available on line, it makes the most sense.

Again this is for only those customers that want to try just the Suprtool, Suprlink and STExport binaries.

Clean Features

The main reason for most Ecometry customers to install the latest version is to get the clean features of either Suprtool or STExport.

While the clean features of each product do the same thing, they are implemented in slightly different ways.

STExport

When STExport cleans data, it just very simply removes all offending characters from each byte field, for all those characters specified in the clean command. STExport takes an SD file and creates a "PRN" file so to speak, but it allows you to control more about the file being created, such as delimiters and format of the numbers etc.

For example if you wanted to remove any extraneous Tab characters in byte fields the stexport task would be:

   $ in mysdfile
   $clean "^9"
   $set cleanchar " "
   $out myexport
   $xeq

You can have the Clean function clean the field, and instead of replacing with a space, STExport will essentially shift characters to the left by Setting the CleanChar in the following manner:

  >Set Cleanchar “

STExport will pad the field that was cleaned with the appropriate amount of characters with a space at the end of the field.

STExport has other easy to use features such as Clean SPECIAL which automatically cleans all byte type fields with characters ranging from Decimal 0 to Decimal 31.

Suprtool

The Suprtool implementation of Clean is more focused and will allow you to actually fix the Source data as opposed to fixing the data "along the way", as STExport does.

Suprtool will "clean" or replace all of the characters specified in the Clean command from a byte type field when invoked by the $Clean function. To define what characters that need to be replaced you use the clean command with the character you want to clean in quotes. Since most of the characters that you will need to clean are unprintable, you can enter the decimal equivalent of the character. This is denoted by entering the "^" character in quotes preceding the decimal number of the character you wish to clean.

An example of how easy it would be to clean your database of certain "bad" characters in byte-type fields would be as follows:

     >base mydb,1,;
     >get customer
     >clean "^9","^10","^0","^7"
     >update
     >ext address(1) = $clean(address(1))
     >ext address(2) = $clean(address(2))
     >xeq
 
The SPECIAL keyword automatically defines Clean characters of Decimal 0 thru to Decimal 31.
     >base mydb,1,;
     >get customer 
     >clean special
    >update
     >ext address(1) = $clean(address(1))
     >ext address(2) = $clean(address(2))
     >xeq

The above method cleans the source data in the database and allows you to fix any data in the database prior to exporting. This gives you a little more flexibility.

Now you can also, ONLY fix the data that has clean characters, (which makes much more sense):

     >base mydb,1,;
     >get customer 
     >clean special
     >if $findclean(address(1)) or $findclean(address(2))
    >update
     >ext address(1) = $clean(address(1))
     >ext address(2) = $clean(address(2))
     >xeq 
 

So the findclean function will look for any of the characters specified by the clean command and only those records will be updated.