From:	SMTP%"MACRO32@WKUVX1.BITNET" 11-MAY-1993 20:02:21.04
To:	EVERHART
CC:	
Subj:	Convert monitor files to text

X-ListName: "VMS Internals, MACRO, & BLISS Discussions" <MACRO32@WKUVX1.BITNET>
Warnings-To: <>
Errors-To: MacroMan@WKUVX1.BITNET
Sender: MacroMan@WKUVX1.BITNET
X-Newsgroups: vmsnet.internals
From: "(Carles Blas (UAB))" <g_carles@cc.uab.es>
Reply-To: MACRO32@WKUVX1.BITNET
Subject: Convert monitor files to text
Message-ID: <1993May11.185834.1@cc.uab.es>
Lines: 951
Organization: Universitat Autonoma de Barcelona
Date: 11 May 93 18:58:34 +0200
To: MACRO32@WKUVX1.BITNET
X-Gateway-Source-Info: USENET

I hope this program could be of any help to the people who analyzes
information from MONITOR files.

I'm sorry by the mistakes in English.
-----------------
{+
This program converts data from a monitor file to a multiple comma-delimited
files.

INPUT: A collection of files named NODENAME_XXX.XXX, where NODENAME is the
name of the node owner of the stattistics
OUTPUT: The files DISKS.RES, IOS.RES, LOCKS.RES, MODES.RES, PAGE.RES,
        PROCESS.RES, STATES.RES, SYSTEM.RES containing the statitics
        in comma-delimited format.

Author:       Carles Blas
Organization: Universitat Autonoma de Barcelona
Date:         Oct/92
Revision:     Mai/93
-}
[ INHERIT('SYS$LIBRARY:STARLET.PEN') ]
program ExtractMonitor(input,output);

type
  String = varying [255] of char;            {Generic string type}
  FileBuffer = varying [32000] of char;      {Monitor file buffer type}

  $ubyte = [byte] 0..255;                    {Generic unsigned byte type}
  $word = [word] -32767..32767;              {Generic word type}
  $long = [long] integer;                    {Generic longword type}
  $quad = [quad] record                      {Generic quadword type}
                   ub1,ub2:$ubyte;
                   u: unsigned;
                   v1,v2:$ubyte;
                   end;
  $text4 = packed array [1..4] of char;      {Generic 4 char fixed string type}
  $text8 = packed array [1..8] of char;      {Generic 8 char fixed string type}
  $text12 = packed array [1..12] of char;    {Generic 12 char fixed string type}
  $text16 = packed array [1..16] of char;    {Generic 16 char fixed string type}

  TypeClassMon = (                           {Classes of records in monitor   }
    ClassMonProcess,                         { file. The first is 0 next is 1 }
    ClassMonStates,                          { and so on                      }
    ClassMonModes,                           {See Monitor Utility Manual,     }
    ClassMonPage,                            { appendix A, Table A-1          }
    ClassMonIO,                              {Undefined classes are included  }
    ClassMonFCP,                             { because are reserved by DEC.   }
    ClassMonPool,                            { if they were used it would be  }
    ClassMonLock,                            { printed in the statistics      }
    ClassMonDecnet,
    ClassMonReserved_1,
    ClassMonReserved_2,
    ClassMonFileSystemCache,
    ClassMonDisks,
    ClassMonReserved_3,
    ClassMonDlock,
    ClassMonSCS,
    ClassMonReserved_4,
    ClassMonSystem,
    ClassMonReserved_5,
    ClassMonReserved_6,
    ClassMonReserved_7,
    ClassMonCluster,
    ClassMonRMS,
    ClassMonMscpServer,
    _24,_25,_26,_27,_28,_29,
    _30,_31,_32,_33,_34,_35,_36,_37,_38,_39,
    _40,_41,_42,_43,_44,_45,_46,_47,_48,_49,
    _50,_51,_52,_53,_54,_55,_56,_57,_58,_59,
    _60,_61,_62,_63,_64,_65,_66,_67,_68,_69,
    _70,_71,_72,_73,_74,_75,_76,_77,_78,_79,
    _80,_81,_82,_83,_84,_85,_86,_87,_88,_89,
    _90,_91,_92,_93,_94,_95,_96,_97,_98,_99,
    _100,_101,_102,_103,_104,_105,_106,_107,_108,_109,
    _110,_111,_112,_113,_114,_115,_116,_117,_118,_119,
    _120,_121,_122,_123,_124,_125,_126,_127,_128,_129,
    _130,_131,_132,_133,_134,_135,_136,_137,_138,_139,
    _140,_141,_142,_143,_144,_145,_146,_147,_148,_149,
    _150,_151,_152,_153,_154,_155,_156,_157,_158,_159,
    _160,_161,_162,_163,_164,_165,_166,_167,_168,_169,
    _170,_171,_172,_173,_174,_175,_176,_177,_178,_179,
    _180,_181,_182,_183,_184,_185,_186,_187,_188,_189,
    _190,_191,_192,_193,_194,_195,_196,_197,_198,_199,
    _200,_201,_202,_203,_204,_205,_206,_207,_208,_209,
    _210,_211,_212,_213,_214,_215,_216,_217,_218,_219,
    _220,_221,_222,_223,_224,_225,_226,_227,_228,_229,
    _230,_231,_232,_233,_234,_235,_236,_237,_238,_239,
    _240,_241,_242,_243,_244,_245,_246,_247,_248,_249,
    _250,_251,_252,_253,_254,_255);

{The following definitions are based on Monitor Utility Manual, Appendix A}
  MonNodeCluster = record
    MNR_CLU$L_CPU_BUSY:    $long;
    MNR_CLU$L_FRLIST:      $long;
    MNR_CLU$L_RESERVED:    $long;
    MNR_CLU$L_TOTAL_LOCKS: $long;
    MNR_CLU$L_ENQNEWOLC:   $long;
    MNR_CLU$L_ENQNEWIN:    $long;
    MNR_CLU$L_ENQENWOUT:   $long;
    MNR_CLU$L_ENQCVTLOC:   $long;
    MNR_CLU$L_ENQCVTIN:    $long;
    MNR_CLU$L_ENQCVTOUT:   $long;
    MNR_CLU$L_DEQLOC:      $long;
    MNR_CLU$L_DEQIN:       $long;
    MNR_CLU$L_DEQOUT:      $long;
    end; {MonNodeCluster}

  MonNodeDecnet = record
    MNR_NET$L_ARRLOCPK: $long;
    MNR_NET$L_DEPLOCK:  $long;
    MNR_NET$L_ARRTRAPK: $long;
    MNR_NET$L_TRCNGLOS: $long;
    MNR_NET$L_RCVBUFFL: $long;
    MNR_NET$L_LRPCNT:   $long;
    end; {MonNodeDecnet}

  MonNodeDlock = record
    MNR_DLO$L_ENQNEWLOC: $long;
    MNR_DLO$L_ENQNEWIN:  $long;
    MNR_DLO$L_ENQENWOUT: $long;
    MNR_DLO$L_ENQCVTLOC: $long;
    MNR_DLO$L_ENQCVTIN:  $long;
    MNR_DLO$L_ENQCVTOUT: $long;
    MNR_DLO$L_DEQLOC:    $long;
    MNR_DLO$L_DEQIN:     $long;
    MNR_DLO$L_DEQOUT:    $long;
    MNR_DLO$L_BLKLOC:    $long;
    MNR_DLO$L_BLKIN:     $long;
    MNR_DLO$L_BLKOUT:    $long;
    MNR_DLO$L_DIRIN:     $long;
    MNR_DLO$L_DIROUT:    $long;
    MNR_DLO$L_DLCKMSG:   $long;
    end; {MonNodeDlock}

  MonNodeFCP = record
    MNR_FCP$L_FCPCALLS:  $long;
    MNR_FCP$L_ALLOC:     $long;
    MNR_FCP$L_FCPCREATE: $long;
    MNR_FCP$L_FCPREAD:   $long;
    MNR_FCP$L_FCPWRITE:  $long;
    MNR_FCP$L_VOLWAIT:   $long;
    MNR_FCP$L_FCPCPU:    $long;
    MNR_FCP$L_FCPFAULT:  $long;
    MNR_FCP$L_FCPTURN:   $long;
    MNR_FCP$L_ACCESS:    $long;
    MNR_FCP$L_OPENS:     $long;
    MNR_FCP$L_ERASE:     $long;
    end; {MonNodeFCP}

  MonNodeFileSystemCache = record
    MNR_FIL$L_DIRFCB_HIT:      $long;
    MNR_FIL$L_DIRFCB_TRIES:    $long;
    MNR_FIL$L_DIRDATA_HIT:     $long;
    MNR_FIL$L_DIRDATA_TRIES:   $long;
    MNR_FIL$L_FILHDR_HIT:      $long;
    MNR_FIL$L_FILHDR_TRIES:    $long;
    MNR_FIL$L_FIDHIT:          $long;
    MNR_FIL$L_FID_TRIES:       $long;
    MNR_FIL$L_EXTHIT:          $long;
    MNR_FIL$L_EXT_TRIES:       $long;
    MNR_FIL$L_QUOHIT:          $long;
    MNR_FIL$L_QUO_TRIES:       $long;
    MNR_FIL$L_STORAGMAP_HIT:   $long;
    MNR_FIL$L_STORAGMAP_TRIES: $long;
    end; {MonNodeFileSystemCache}

  MonNodeIO = record
    MNR_IO$L_DIRIO:    $long;
    MNR_IO$L_BUFIO:    $long;
    MNR_IO$L_MBWRITES: $long;
    MNR_IO$L_SPLTTRNS: $long;
    MNR_IO$L_LOGNAM:   $long;
    MNR_IO$L_OPENS:    $long;
    MNR_IO$L_FAULTS:   $long;
    MNR_IO$L_PREADS:   $long;
    MNR_IO$L_PREADIO:  $long;
    MNR_IO$L_PWRITES:  $long;
    MNR_IO$L_PWRITIO:  $long;
    MNR_IO$L_ISWPCNT:  $long;
    MNR_IO$L_FREECNT:  $long;
    MNR_IO$L_MFYCNT:   $long;
    end; {MonNodeIO}

  MonNodeLock = record
    MNR_LCK$L_ENQNEW:   $long;
    MNR_LCK$L_ENQCVT:   $long;
    MNR_LCK$L_DEQ:      $long;
    MNR_LCK$L_BLKAST:   $long;
    MNR_LCK$L_ENQWAIT:  $long;
    MNR_LCK$L_ENQNOTQD: $long;
    MNR_LCK$L_DLCKSRCH: $long;
    MNR_LCK$L_DLCKFND:  $long;
    MNR_LCK$L_NUMLOCKS: $long;
    MNR_LCK$L_NUMRES:   $long;
    end; {MonNodeLock}

  MonNodeMSCPServer = record
    MNR_MSC$L_REQUEST:  $long;
    MNR_MSC$L_READ:     $long;
    MNR_MSC$L_WRITE:    $long;
    MNR_MSC$L_FRAGMENT: $long;
    MNR_MSC$L_SPLIT:    $long;
    MNR_MSC$L_BUFWAIT:  $long;
    MNR_MSC$L_SIZE1:    $long;
    MNR_MSC$L_SIZE2:    $long;
    MNR_MSC$L_SIZE3:    $long;
    MNR_MSC$L_SIZE4:    $long;
    MNR_MSC$L_SIZE5:    $long;
    MNR_MSC$L_SIZE6:    $long;
    MNR_MSC$L_SIZE7:    $long;
    end; {MonNodeMSPCServer}

  MonNodePage = record
    MNR_PAG$L_FAULTS:    $long;
    MNR_PAG$L_PREADS:    $long;
    MNR_PAG$L_PREADIO:   $long;
    MNR_PAG$L_PWRITES:   $long;
    MNR_PAG$L_PWRITIO:   $long;
    MNR_PAG$L_FREFLTS:   $long;
    MNR_PAG$L_MFYFLTS:   $long;
    MNR_PAG$L_DZROFLTS:  $long;
    MNR_PAG$L_GVALID:    $long;
    MNR_PAG$L_WRTINPROG: $long;
    MNR_PAG$L_SYSFAULTS: $long;
    MNR_PAG$L_FREECNT:   $long;
    MNR_PAG$L_MFYCNT:    $long;
    end; {MonNodePage}

  MonNodePool = record
    MNR_POO$L_SRPCNT:    $long;
    MNR_POO$L_SRPINUSE:  $long;
    MNR_POO$L_IRPCNT:    $long;
    MNR_POO$L_IRPINUSE:  $long;
    MNR_POO$L_LRPCNT:    $long;
    MNR_POO$L_LRPINUSE:  $long;
    MNR_POO$L_HOLESUM:   $long;
    MNR_POO$L_DYNINUSE:  $long;
    MNR_POO$L_HOLECNT:   $long;
    MNR_POO$L_BIGHOLE:   $long;
    MNR_POO$L_SMALLHOLE: $long;
    MNR_POO$L_SMALLCNT:  $long;
    end; {MonNodePool}

  MonNodeStates = record
    MNR_STA$L_COLPG: $long;
    MNR_STA$L_MWAIT: $long;
    MNR_STA$L_CEF:   $long;
    MNR_STA$L_PFW:   $long;
    MNR_STA$L_LEF:   $long;
    MNR_STA$L_LEFO:  $long;
    MNR_STA$L_HIB:   $long;
    MNR_STA$L_HIBO:  $long;
    MNR_STA$L_SUSP:  $long;
    MNR_STA$L_SUSPO: $long;
    MNR_STA$L_FPG:   $long;
    MNR_STA$L_COM:   $long;
    MNR_STA$L_COMO:  $long;
    MNR_STA$L_CUR:   $long;
    end; {MonNodeStates}

  MonNodeSystem = record
    MNR_SYS$L_BUSY:    $long;
    MNR_SYS$L_OTHSTAT: $long;
    MNR_SYS$L_PROCS:   $long;
    MNR_SYS$L_FAULTS:  $long;
    MNR_SYS$L_PREADIO: $long;
    MNR_SYS$L_FREECNT: $long;
    MNR_SYS$L_MFYCNT:  $long;
    MNR_SYS$L_DIRIO:   $long;
    MNR_SYS$L_BUFIO:   $long;
    end; {MonNodeSystem}

  MonNodeDisks = record
    MNR_DSK$B_ALLOCLS:  $ubyte;
    MNR_DSK$T_CTRLR:    $text4;
    MNR_DSK$W_UNITNO:   $word;
    MNR_DSK$B_FLAGS:    $ubyte;
    MNR_DSK$T_NODENAME: $text8;
    MNR_DSK$T_VOLNAME:  $text12;
    MNR_DSK$L_OPCNT:    $long;
    MNR_DSK$L_IOQUELN:  $long;
    end; {MonNodeDisks}

  MonNodeModes = record
    MNR_MOD$B_CPUID:  $ubyte;
    MNR_MOD$L_INTER:  $long;
    MNR_MOD$L_MPSYNC: $long;
    MNR_MOD$L_KERNEL: $long;
    MNR_MOD$L_EXEC:   $long;
    MNR_MOD$L_SUPER:  $long;
    MNR_MOD$L_USER:   $long;
    MNR_MOD$L_COMPAT: $long;
    MNR_MOD$L_IDLE:   $long;
    end; {MonNodeModes}

  MonNodeProcess = record
    MNR_PRO$L_IPID:     $long;
    MNR_PRO$L_UIC:      $long;
    MNR_PRO$W_STATE:    $word;
    MNR_PRO$B_PRI:      $ubyte;
    MNR_PRO$T_LNAME:    $text16;
    MNR_PRO$L_GPGCNT:   $long;
    MNR_PRO$L_PPGCNT:   $long;
    MNR_PRO$L_STS:      $long;
    MNR_PRO$L_DIOCNT:   $long;
    MNR_PRO$L_PAGEFLTS: $long;
    MNR_PRO$L_CPUTIM:   $long;
    MNR_PRO$L_BIOCNT:   $long;
    MNR_PRO$L_EPID:     $long;
    MNR_PRO$L_EFWM:     $long;
    end; {MonNodeProcess}

  MonNodeRMS = record
    MNR_RMS$B_FILNUM:      $ubyte;
    MNR_RMS$L_ORG:         $long;
    MNR_RMS$L_RESERVED1:   $long;
    MNR_RMS$L_SEQGETS:     $long;
    MNR_RMS$L_KEYGETS:     $long;
    MNR_RMS$L_RFAGETS:     $long;
    MNR_RMS$Q_GETBYTES:    $quad;
    MNR_RMS$L_SEQPUTS:     $long;
    MNR_RMS$L_KEYPUTS:     $long;
    MNR_RMS$Q_PUTBYTES:    $quad;
    MNR_RMS$L_UPDATES:     $long;
    MNR_RMS$Q_UPDATEBYTES: $quad;
    MNR_RMS$L_DELETES:     $long;
    MNR_RMS$L_TRUNCATES:   $long;
    MNR_RMS$L_TRUNCBLKS:   $long;
    MNR_RMS$L_SEQFINDS:    $long;
    MNR_RMS$L_RFAFINDS:    $long;
    MNR_RMS$L_READS:       $long;
    MNR_RMS$Q_READBYTES:   $quad;
    MNR_RMS$L_CONNECTS:    $long;
    MNR_RMS$L_DISCONNECTS: $long;
    MNR_RMS$L_EXTENDS:     $long;
    MNR_RMS$L_EXBLOCKS:    $long;
    MNR_RMS$L_FLUSHES:     $long;
    MNR_RMS$L_REWINDS:     $long;
    MNR_RMS$L_WRITES:      $long;
    MNR_RMS$Q_WRITEBYTES:  $quad;
    MNR_RMS$L_FLCKENQ:     $long;
    MNR_RMS$L_FLCKDEQ:     $long;
    MNR_RMS$L_FLCKCONVS:   $long;
    MNR_RMS$L_LBLCKENQS:   $long;
    MNR_RMS$L_LBLCKDEQS:   $long;
    MNR_RMS$L_LBLCKCNVS:   $long;
    MNR_RMS$L_GBLCKENQS:   $long;
    MNR_RMS$L_GBLCKDEQS:   $long;
    MNR_RMS$L_GBLCKCNVS:   $long;
    MNR_RMS$L_GSLCKENQS:   $long;
    MNR_RMS$L_GSLCKDEQS:   $long;
    MNR_RMS$L_GSLCKCNVS:   $long;
    MNR_RMS$L_RLCKENQS:    $long;
    MNR_RMS$L_RLCKDEQS:    $long;
    MNR_RMS$L_RLCKCNVS:    $long;
    MNR_RMS$L_APPLCKENQS:  $long;
    MNR_RMS$L_APPLCKDEQS:  $long;
    MNR_RMS$L_APPLCKCNVS:  $long;
    MNR_RMS$L_FLBKASTS:    $long;
    MNR_RMS$L_LBLBLKASTS:  $long;
    MNR_RMS$L_GBLBLKASTS:  $long;
    MNR_RMS$L_APPBLKASTS:  $long;
    MNR_RMS$L_LCACHEHITS:  $long;
    MNR_RMS$L_LCACHEATT:   $long;
    MNR_RMS$L_GCACHECHITS: $long;
    MNR_RMS$L_GCACHEATT:   $long;
    MNR_RMS$L_GBRDIRIOS:   $long;
    MNR_RMS$L_GBWDIRIOS:   $long;
    MNR_RMS$L_LBRDIRIOS:   $long;
    MNR_RMS$L_LBWDIRIOS:   $long;
    MNR_RMS$L_BKTSPLT:     $long;
    MNR_RMS$L_MBKTSPLT:    $long;
    MNR_RMS$L_OPENS:       $long;
    MNR_RMS$L_CLOSES:      $long;
    MNR_RMS$L_RESERVED2:   $long;
    MNR_RMS$L_RESERVED3:   $long;
    end; {MonNodeRMS}

  MonNodeSCS = record
    MNR_SCS$T_NODENAME:  $text8;
    MNR_SCS$L_DGSENT:    $long;
    MNR_SCS$L_DGRCVD:    $long;
    MNR_SCS$L_DGDISCARD: $long;
    MNR_SCS$L_MSGSENT:   $long;
    MNR_SCS$L_MSGRCVD:   $long;
    MNR_SCS$L_SNDATS:    $long;
    MNR_SCS$L_KBYTSENT:  $long;
    MNR_SCS$L_REQDATS:   $long;
    MNR_SCS$L_KBYTREQD:  $long;
    MNR_SCS$L_KBYTMAPD:  $long;
    MNR_SCS$L_QCRCNT:    $long;
    MNR_SCS$L_QBDTCNT:   $long;
    end; {MonNodeSCS}

{+
Generic record of monitor file. There is a fixed header in each record and
a variable part depending on the type of record (MNR_CLS$B_TYPE).
There are two groups of types: the single and the multiple ones.
The single one are made by a fixed number of fields. The multiple classes have
a sub-header containing the number of pieces in the record. I fixed an
arbitrary maximum number of pieces, but it could be other
-}
const
  MaxModes     = 10;
  MaxRMS       = 50;
  MaxSCS       = 30;
  MaxDisks     = 100;
  MaxProcesses = 500;

type
  MonNode = record
    MNR_CLS$B_TYPE:     TypeClassMon;
    MNR_CLS$B_FLAGS:    $ubyte;
    MNR_CLS$B_INDEX:    $ubyte;
    MNR_CLS$Q_STAMP:    $quad;
    MNR_CLS$W_RESERVED: $word;
    case MNR_$B_SELEC:TypeClassMon of
      ClassMonCluster: (MNR_CLS$Z_CLUSTER: MonNodeCluster);
      ClassMonDecnet: (MNR_CLS$Z_DECNET: MonNodeDecnet);
      ClassMonDlock: (MNR_CLS$Z_DLOCK: MonNodeDlock);
      ClassMonFCP: (MNR_CLS$Z_FCP: MonNodeFCP);
      ClassMonFileSystemCache: (MNR_CLS$Z_CACHE: MonNodeFileSystemCache);
      ClassMonIO: (MNR_CLS$Z_IO: MonNodeIO);
      ClassMonLock: (MNR_CLS$Z_LOCK: MonNodeLock);
      ClassMonMscpServer: (MNR_CLS$Z_MSCP: MonNodeMscpServer);
      ClassMonPage: (MNR_CLS$Z_PAGE: MonNodePage);
      ClassMonPool: (MNR_CLS$Z_POOL: MonNodePool);
      ClassMonStates: (MNR_CLS$Z_STATES: MonNodeStates);
      ClassMonSystem: (MNR_CLS$Z_SYSTEM: MonNodeSystem);
      ClassMonProcess,
      ClassMonSCS,
      ClassMonRMS,
      ClassMonDisks,
      ClassMonModes: (
        MNR_CMP$L_ELTCT:           $long;
        MNR_CMP$L_PCTNT:           $long;
        case MNR_$B_SELEC2: TypeClassMon of
          ClassMonDisks: (MNR_DSK$Z_ITEMS: array [1..MaxDisks] of MonNodeDisks);
          ClassMonModes: (MNR_MOD$Z_ITEMS: array [1..MaxModes] of MonNodeModes);
          ClassMonProcess: (MNR_PRO$Z_ITEMS: array [1..MaxProcesses] of MonNodeP
          ClassMonRMS: (MNR_RMS$Z_ITEMS: array [1..MaxRMS] of MonNodeRMS);
          ClassMonSCS: (MNR_SCS$Z_ITEMS: array [1..MaxSCS] of MonNodeSCS);
        );
    end; {record}

{+
External functions required to manipulate data
-}
function lib$sub_times(var a,b,c: $quad): integer; extern;
function lib$cvt_from_internal_time(a:integer; var b: integer; var c: $quad): in
function lib$sub_times(var a,b,c: $quad): integer; extern;
function lib$movc3(w: integer; s,d: [IMMEDIATE] integer): integer; extern;
procedure lib$signal(s: [IMMEDIATE] integer); extern;

{+
Converts the buffer from string to an structured record using LIB$MOVC3
  Moves the header
  If its a single record
     moves the tail with a offset of one byte used in tag field
  else
     moves the sub-header with a offset of one byte used in tag field
     moves the tail with a offset of two bytes used in the second tag field
-}
procedure ConvBuff(var Buff: FileBuffer; var CurrentBuffer: MonNode);
  var st:integer; {Receives the status}
  begin
  st := lib$movc3(13,iaddress(Buff.Body),iaddress(CurrentBuffer));
  if not odd(st) then lib$signal(st);

  CurrentBuffer.MNR_$B_SELEC := CurrentBuffer.MNR_CLS$B_TYPE;
  if not (CurrentBuffer.MNR_$B_SELEC in [ClassMonProcess, ClassMonSCS, ClassMonR
                                  ClassMonDisks, ClassMonModes]) then begin
    st := lib$movc3(Buff.Length-13,iaddress(Buff.Body)+13,iaddress(CurrentBuffer
    if not odd(st) then lib$signal(st);
  end else begin
    st := lib$movc3(8,iaddress(Buff.Body)+13,iaddress(CurrentBuffer)+14);
    if not odd(st) then lib$signal(st);
    CurrentBuffer.MNR_$B_SELEC2 := CurrentBuffer.MNR_$B_SELEC;
    st := lib$movc3(Buff.Length-21,iaddress(Buff.Body)+21,iaddress(CurrentBuffer
    if not odd(st) then lib$signal(st);
  end;
  end; {ConvBuff}

{+
Converts from internal time to hours, with two decimal places, in string format
-}
function CvtTime(var QuadTime:$quad): String;
  var
    StrTime: string; {packed array [1..23] of char;}
    RetStat: integer;
    LenTime: [word] 0..32000;
    ResSecs, ResDays, ResDOW: integer;
  begin
  RetStat := lib$cvt_from_internal_time(lib$k_day_of_year, ResDays, QuadTime);
  if not odd(RetStat) then lib$signal(RetStat);
  RetStat := lib$cvt_from_internal_time(lib$k_second_of_day, ResSecs, QuadTime);
  if not odd(RetStat) then lib$signal(RetStat);
  RetStat := lib$cvt_from_internal_time(lib$k_day_of_week, ResDOW, QuadTime);
  if not odd(RetStat) then lib$signal(RetStat);
  writev(StrTime, ResDays:3, ',', ResSecs/3600:5:2, ',', ResDow:1);
  CvtTime := StrTime;
  end;

{+
Return the difference in seconds of two times
-}
function SubTime(var NewTime, OldTime:$quad): integer;
  var
    z: real;

  begin
  if (NewTime.v1 <> OldTime.v1) or (NewTime.v2 <> OldTime.v2) then
    begin SubTime := -100000000; writeln('Abnormal condition. What happens?'); e
  else
    z := (NewTime.u - OldTime.u) / 10000000 * 256 * 256;
    if z < 0 then
      writeln('Abnormal condition. What happens?');
    SubTime := trunc(z);
  end; {SubTime}

{+
The following procedures do more or less the same. For each field, they
calculate the difference between the current record and the previous one.
In the case of the array type records we must match each individual current
record with the previous one
-}
procedure ProcDisks(Node: string; var CurrentBuffer, DisksBuffer: MonNode;
 var IsFirst: boolean; Var OutFile: text);

  procedure SwapDisk(i,j:integer);
    begin
    with DisksBuffer do begin
      MNR_DSK$Z_ITEMS[MNR_CMP$L_ELTCT] := MNR_DSK$Z_ITEMS[i];
      MNR_DSK$Z_ITEMS[i] := MNR_DSK$Z_ITEMS[j];
      MNR_DSK$Z_ITEMS[j] := MNR_DSK$Z_ITEMS[MNR_CMP$L_ELTCT];
      end;
    end;

  procedure HeadDisk(i:integer);
    begin
    with CurrentBuffer.MNR_DSK$Z_ITEMS[i] do
      writeln(OutFile,
        '>>>', Node, ',"',
        substr(MNR_DSK$T_CTRLR, 2, ord(MNR_DSK$T_CTRLR[1])), '",',
        MNR_DSK$W_UNITNO:3, ',"',
        substr(MNR_DSK$T_NODENAME, 2, ord(MNR_DSK$T_NODENAME[1])), '","',
        MNR_DSK$T_VOLNAME, '",',
        MNR_DSK$B_ALLOCLS:1, ',',
        MNR_DSK$B_FLAGS:1);
    end; {HeadDisk}

  procedure WriteDisk(i,j:integer);
    begin
    with CurrentBuffer, MNR_DSK$Z_ITEMS[i] do
      writeln(OutFile,
        Node, ',"',
        substr(MNR_DSK$T_CTRLR, 2, ord(MNR_DSK$T_CTRLR[1])), '",',
        MNR_DSK$W_UNITNO:3, ',',
        CvtTime(MNR_CLS$Q_STAMP), ',',
        SubTime(MNR_CLS$Q_STAMP, DisksBuffer.MNR_CLS$Q_STAMP):4, ',',
        MNR_DSK$L_OPCNT - DisksBuffer.MNR_DSK$Z_ITEMS[j].MNR_DSK$L_OPCNT:6, ',',
        MNR_DSK$L_IOQUELN - DisksBuffer.MNR_DSK$Z_ITEMS[j].MNR_DSK$L_IOQUELN:6);
    end;

  var
    i,j,n: integer; {cursors for the array of individual sub-recdors}
    Found: boolean; {Flag to signal if current sub-record was found in previous
  {+
   If first then
     change flag and write an output line with the header information
   else
     match each current sub-record, previous sub-record not matched are ignored
     if found then
       write statistics
       move the sub-record found to the beggining of the search-range to narrow
     else
       write header
   Assign current buffer to previous buffer
  -}
  begin
  if IsFirst then
    begin IsFirst := false; for i:=1 to CurrentBuffer.MNR_CMP$L_ELTCT do HeadDis
  else begin
    n := 1;
    for i:=1 to CurrentBuffer.MNR_CMP$L_ELTCT do begin
       Found := false;
       for j:=n to DisksBuffer.MNR_CMP$L_ELTCT do
         with CurrentBuffer.MNR_DSK$Z_ITEMS[i] do
           if (MNR_DSK$T_CTRLR = DisksBuffer.MNR_DSK$Z_ITEMS[j].MNR_DSK$T_CTRLR)
              (MNR_DSK$W_UNITNO = DisksBuffer.MNR_DSK$Z_ITEMS[j].MNR_DSK$W_UNITN
             Found := true;
             WriteDisk(i,j);
             if n <> j then SwapDisk(n,j);
             n := n + 1;
             end;
       if not Found then HeadDisk(i);
       end;
     end;
  DisksBuffer := CurrentBuffer;
  end; {ProcDisks}

{+
If first then
  change flag
else
  write statistics
Assign current buffer to previous buffer
-}
procedure ProcIOs(Node: string; var CurrentBuffer, IOsBuffer: MonNode;
 var IsFirst: boolean; Var OutFile: text);
  var i:integer;
  begin
  if IsFirst then
     IsFirst := false
  else
    with CurrentBuffer, MNR_CLS$Z_IO do
      writeln(OutFile,
              Node, ',',
              CvtTime(MNR_CLS$Q_STAMP), ',',
              SubTime(MNR_CLS$Q_STAMP, IOsBuffer.MNR_CLS$Q_STAMP):4, ',',
              MNR_IO$L_DIRIO - IOsBuffer.MNR_CLS$Z_IO.MNR_IO$L_DIRIO:6,  ',',
              MNR_IO$L_BUFIO - IOsBuffer.MNR_CLS$Z_IO.MNR_IO$L_BUFIO:6,  ',',
              MNR_IO$L_LOGNAM - IOsBuffer.MNR_CLS$Z_IO.MNR_IO$L_LOGNAM:6,  ',',
              MNR_IO$L_OPENS - IOsBuffer.MNR_CLS$Z_IO.MNR_IO$L_OPENS:6);
  IOsBuffer := CurrentBuffer;
  end; {ProcIOs}

procedure ProcLocks(Node: string; var CurrentBuffer, LocksBuffer: MonNode;
 var IsFirst: boolean; Var OutFile: text);
  var i:integer;
  begin
  if IsFirst then
     IsFirst := false
  else
    with CurrentBuffer, MNR_CLS$Z_LOCK do
      writeln(OutFile,
              Node, ',',
              CvtTime(MNR_CLS$Q_STAMP), ',',
              SubTime(MNR_CLS$Q_STAMP, LocksBuffer.MNR_CLS$Q_STAMP):4, ',',
              MNR_LCK$L_ENQNEW - LocksBuffer.MNR_CLS$Z_LOCK.MNR_LCK$L_ENQNEW:6,
              MNR_LCK$L_ENQCVT - LocksBuffer.MNR_CLS$Z_LOCK.MNR_LCK$L_ENQCVT:6,
              MNR_LCK$L_DEQ - LocksBuffer.MNR_CLS$Z_LOCK.MNR_LCK$L_DEQ:6,  ',',
              MNR_LCK$L_NUMLOCKS - LocksBuffer.MNR_CLS$Z_LOCK.MNR_LCK$L_NUMLOCKS
              MNR_LCK$L_NUMRES - LocksBuffer.MNR_CLS$Z_LOCK.MNR_LCK$L_NUMRES:6);
  LocksBuffer := CurrentBuffer;
  end; {ProcLocks}

procedure ProcModes(Node: string; var CurrentBuffer, ModesBuffer: MonNode;
 var IsFirst: boolean; Var OutFile: text);
  var i:integer;
  begin
  if IsFirst then
     IsFirst := false
  else
    with CurrentBuffer do
      for i:=1 to MNR_CMP$L_ELTCT do
        with MNR_MOD$Z_ITEMS[i] do
          writeln(OutFile,
              Node, ',',
              MNR_MOD$B_CPUID:1, ',',
              CvtTime(MNR_CLS$Q_STAMP), ',',
              SubTime(MNR_CLS$Q_STAMP, ModesBuffer.MNR_CLS$Q_STAMP):4, ',',
              MNR_MOD$L_INTER - ModesBuffer.MNR_MOD$Z_ITEMS[i].MNR_MOD$L_INTER:4
              MNR_MOD$L_MPSYNC - ModesBuffer.MNR_MOD$Z_ITEMS[i].MNR_MOD$L_MPSYNC
              MNR_MOD$L_KERNEL - ModesBuffer.MNR_MOD$Z_ITEMS[i].MNR_MOD$L_KERNEL
              MNR_MOD$L_EXEC - ModesBuffer.MNR_MOD$Z_ITEMS[i].MNR_MOD$L_EXEC:4,
              MNR_MOD$L_SUPER - ModesBuffer.MNR_MOD$Z_ITEMS[i].MNR_MOD$L_SUPER:4
              MNR_MOD$L_USER - ModesBuffer.MNR_MOD$Z_ITEMS[i].MNR_MOD$L_USER:6,
              MNR_MOD$L_COMPAT - ModesBuffer.MNR_MOD$Z_ITEMS[i].MNR_MOD$L_COMPAT
              MNR_MOD$L_IDLE - ModesBuffer.MNR_MOD$Z_ITEMS[i].MNR_MOD$L_IDLE:6);
  ModesBuffer := CurrentBuffer;
  end; {ProcModes}

procedure ProcPage(Node: string; var CurrentBuffer, PageBuffer: MonNode;
 var IsFirst: boolean; Var OutFile: text);
  var i:integer;
  begin
  if IsFirst then
     IsFirst := false
  else
    with CurrentBuffer, MNR_CLS$Z_PAGE do
      writeln(OutFile,
              Node, ',',
              CvtTime(MNR_CLS$Q_STAMP), ',',
              SubTime(MNR_CLS$Q_STAMP, PageBuffer.MNR_CLS$Q_STAMP):4, ',',
              MNR_PAG$L_FAULTS - PageBuffer.MNR_CLS$Z_PAGE.MNR_PAG$L_FAULTS:6,
              MNR_PAG$L_PREADS - PageBuffer.MNR_CLS$Z_PAGE.MNR_PAG$L_PREADS:6,
              MNR_PAG$L_PWRITES - PageBuffer.MNR_CLS$Z_PAGE.MNR_PAG$L_PWRITES:6,
              MNR_PAG$L_DZROFLTS - PageBuffer.MNR_CLS$Z_PAGE.MNR_PAG$L_DZROFLTS:
              MNR_PAG$L_FREECNT - PageBuffer.MNR_CLS$Z_PAGE.MNR_PAG$L_FREECNT:6,
              MNR_PAG$L_MFYCNT - PageBuffer.MNR_CLS$Z_PAGE.MNR_PAG$L_MFYCNT:6);
  PageBuffer := CurrentBuffer;
  end; {ProcPage}

procedure ProcProcess(Node: string; var CurrentBuffer, ProcessBuffer: MonNode;
 var IsFirst: boolean; Var OutFile: text);

  procedure SwapProc(i,j:integer);
    begin
    with ProcessBuffer do begin
      MNR_PRO$Z_ITEMS[MNR_CMP$L_ELTCT] := MNR_PRO$Z_ITEMS[i];
      MNR_PRO$Z_ITEMS[i] := MNR_PRO$Z_ITEMS[j];
      MNR_PRO$Z_ITEMS[j] := MNR_PRO$Z_ITEMS[MNR_CMP$L_ELTCT];
      end;
    end;

  procedure HeadProc(i:integer);
    begin
    with CurrentBuffer.MNR_PRO$Z_ITEMS[i] do
      writeln(OutFile,
        '>>>', Node, ',',
        hex(MNR_PRO$L_IPID,8,8), ',',
        hex(MNR_PRO$L_EPID,8,8), ',',
        '"', substr(MNR_PRO$T_LNAME, 2, ord(MNR_PRO$T_LNAME[1])), '"');
    end; {HeadProc}

  procedure WriteProc(i,j:integer);
    begin
    with CurrentBuffer, MNR_PRO$Z_ITEMS[i] do
      writeln(OutFile,
        Node, ',',
        hex(MNR_PRO$L_IPID,8,8), ',',
        CvtTime(MNR_CLS$Q_STAMP), ',',
        SubTime(MNR_CLS$Q_STAMP, ProcessBuffer.MNR_CLS$Q_STAMP):4, ',',
        MNR_PRO$W_STATE:4, ',',
        hex(MNR_PRO$L_EFWM,8,8), ',',
        hex(MNR_PRO$L_STS,8,8), ',',
        MNR_PRO$B_PRI:2, ',',
        MNR_PRO$L_GPGCNT - ProcessBuffer.MNR_PRO$Z_ITEMS[j].MNR_PRO$L_GPGCNT:5,
        MNR_PRO$L_PPGCNT - ProcessBuffer.MNR_PRO$Z_ITEMS[j].MNR_PRO$L_PPGCNT:5,
        MNR_PRO$L_DIOCNT - ProcessBuffer.MNR_PRO$Z_ITEMS[j].MNR_PRO$L_DIOCNT:5,
        MNR_PRO$L_PAGEFLTS - ProcessBuffer.MNR_PRO$Z_ITEMS[j].MNR_PRO$L_PAGEFLTS
        MNR_PRO$L_CPUTIM - ProcessBuffer.MNR_PRO$Z_ITEMS[j].MNR_PRO$L_CPUTIM:5,
        MNR_PRO$L_BIOCNT - ProcessBuffer.MNR_PRO$Z_ITEMS[j].MNR_PRO$L_BIOCNT:5);
    end; {WriteProc}

  var i,j,n: integer; Found: boolean;

  begin
  if IsFirst then
    begin IsFirst := false; for i:=1 to CurrentBuffer.MNR_CMP$L_ELTCT do HeadPro
  else begin
    n := 1;
    for i:=1 to CurrentBuffer.MNR_CMP$L_ELTCT do begin
       Found := false;
       for j:=n to ProcessBuffer.MNR_CMP$L_ELTCT do
         if CurrentBuffer.MNR_PRO$Z_ITEMS[i].MNR_PRO$L_IPID = ProcessBuffer.MNR_
           Found := true;
           WriteProc(i,j);
           if n <> j then SwapProc(n,j);
           n := n + 1;
           end;
       if not Found then HeadProc(i);
       end;
     end;
  ProcessBuffer := CurrentBuffer;
  end; {ProcProcess}

procedure ProcStates(Node: string; var CurrentBuffer, StatesBuffer: MonNode;
 var IsFirst: boolean; Var OutFile: text);
  var i:integer;
  begin
  if IsFirst then
     IsFirst := false
  else
    with CurrentBuffer, MNR_CLS$Z_STATES do
      writeln(OutFile,
              Node, ',',
              CvtTime(MNR_CLS$Q_STAMP), ',',
              SubTime(MNR_CLS$Q_STAMP, StatesBuffer.MNR_CLS$Q_STAMP):4, ',',
              MNR_STA$L_COLPG - StatesBuffer.MNR_CLS$Z_STATES.MNR_STA$L_COLPG:3,
              MNR_STA$L_MWAIT - StatesBuffer.MNR_CLS$Z_STATES.MNR_STA$L_MWAIT:3,
              MNR_STA$L_CEF - StatesBuffer.MNR_CLS$Z_STATES.MNR_STA$L_CEF:3,  ',
              MNR_STA$L_PFW - StatesBuffer.MNR_CLS$Z_STATES.MNR_STA$L_PFW:3,  ',
              MNR_STA$L_LEF - StatesBuffer.MNR_CLS$Z_STATES.MNR_STA$L_LEF:3,  ',
              MNR_STA$L_HIB - StatesBuffer.MNR_CLS$Z_STATES.MNR_STA$L_HIB:3,  ',
              MNR_STA$L_SUSP - StatesBuffer.MNR_CLS$Z_STATES.MNR_STA$L_SUSP:3,
              MNR_STA$L_FPG - StatesBuffer.MNR_CLS$Z_STATES.MNR_STA$L_FPG:3,  ',
              MNR_STA$L_COM - StatesBuffer.MNR_CLS$Z_STATES.MNR_STA$L_COM:3,  ',
              MNR_STA$L_CUR - StatesBuffer.MNR_CLS$Z_STATES.MNR_STA$L_CUR:3);
  StatesBuffer := CurrentBuffer;
  end; {ProcStates}

procedure ProcSystem(Node: string; var CurrentBuffer, SystemBuffer: MonNode;
 var IsFirst: boolean; Var OutFile: text);
  var i:integer;
  begin
  if IsFirst then
     IsFirst := false
  else
    with CurrentBuffer, MNR_CLS$Z_SYSTEM do
      writeln(OutFile,
              Node, ',',
              CvtTime(MNR_CLS$Q_STAMP), ',',
              SubTime(MNR_CLS$Q_STAMP, SystemBuffer.MNR_CLS$Q_STAMP):4, ',',
              MNR_SYS$L_BUSY - SystemBuffer.MNR_CLS$Z_SYSTEM.MNR_SYS$L_BUSY:3,
              MNR_SYS$L_OTHSTAT - SystemBuffer.MNR_CLS$Z_SYSTEM.MNR_SYS$L_OTHSTA
              MNR_SYS$L_PROCS - SystemBuffer.MNR_CLS$Z_SYSTEM.MNR_SYS$L_PROCS:6,
              MNR_SYS$L_FAULTS - SystemBuffer.MNR_CLS$Z_SYSTEM.MNR_SYS$L_FAULTS:
              MNR_SYS$L_PREADIO - SystemBuffer.MNR_CLS$Z_SYSTEM.MNR_SYS$L_PREADI
              MNR_SYS$L_FREECNT - SystemBuffer.MNR_CLS$Z_SYSTEM.MNR_SYS$L_FREECN
              MNR_SYS$L_MFYCNT - SystemBuffer.MNR_CLS$Z_SYSTEM.MNR_SYS$L_MFYCNT:
              MNR_SYS$L_DIRIO - SystemBuffer.MNR_CLS$Z_SYSTEM.MNR_SYS$L_DIRIO:6,
              MNR_SYS$L_BUFIO - SystemBuffer.MNR_CLS$Z_SYSTEM.MNR_SYS$L_BUFIO:6)
  SystemBuffer := CurrentBuffer;
  end; {ProcSystem}

{Global output text files}
var
  DisksFile, IOsFile, LocksFile, ModesFile,
    PageFile, ProcessFile, StatesFile, SystemFile: text;
{+
Filters a single input file
-}
procedure FilterFile(FileName: string);
var
  InputBuffer: FileBuffer;              {Input file buffer (string)}
  CurrentBuffer, MonDisks, MonIOs, MonLocks,
  MonModes, MonPage, MonProcess, MonStates,
  MonSystem: MonNode;                   {Structured buffers for each kind of rec
  FirstDisks, FirstIOs, FirstLocks,
  FirstModes, FirstPage, FirstProcess,
  FirstStates, FirstSystem: boolean;    {Flags indicating if it is the first
                                        { occurrence of that kind of record}
  MonFile: text;                        {Input file}
  StatMultCount, StatLength,
  StatCount: array [TypeClassMon] of integer; {Arrays to strore statistics}
  i: TypeClassMon;                      {Cursor for statistics arrays}
  NodeName: string;                     {Variable used to store which is the}
                                        { node of the cluster in process}
  lpos: integer;                        {Auxiliar variable}

  begin
  for i:=ClassMonProcess to _255 do
    begin StatMultCount[i] := 0; StatLength[i] := 0; StatCount[i] := 0; end;

  FirstDisks := true;
  FirstIOs := true;
  FirstLocks := true;
  FirstModes := true;
  FirstPage := true;
  FirstProcess := true;
  FirstStates := true;
  FirstSystem := true;

  {Open input file}
  lpos := index(FileName,']');
  NodeName := substr(FileName, lpos+1, length(FileName) - lpos);
  NodeName := '"'+ substr(NodeName, 1, index(NodeName,'_')-1) +'"';
  open(MonFile, FileName, old); reset(MonFile);

  {+
  Loop for each record in file:
    Read the record
    Convert the record from string to structure
    Select the proper procedure to proces the record. Each procedure receives:
      the node name
      the current buffer
      the last record processed
      a flag signaling if is the first call to the procedure
      the corresponding output file
  -}
  while not eof(MonFile) do begin
    readln(MonFile,InputBuffer);
    ConvBuff(InputBuffer, CurrentBuffer);

    case CurrentBuffer.MNR_CLS$B_TYPE of
      ClassMonDisks:   ProcDisks(NodeName, CurrentBuffer, MonDisks, FirstDisks,
      ClassMonIO:      ProcIOs(NodeName, CurrentBuffer, MonIOs, FirstIOs, IOsFil
      ClassMonLock:    ProcLocks(NodeName, CurrentBuffer, MonLocks, FirstLocks,
      ClassMonModes:   ProcModes(NodeName, CurrentBuffer, MonModes, FirstModes,
      ClassMonPage:    ProcPage(NodeName, CurrentBuffer, MonPage, FirstPage, Pag
      ClassMonProcess: ProcProcess(NodeName, CurrentBuffer, MonProcess, FirstPro
      ClassMonStates:  ProcStates(NodeName, CurrentBuffer, MonStates, FirstState
      ClassMonSystem:  ProcSystem(NodeName, CurrentBuffer, MonSystem, FirstSyste
    end; {case}

    {Collect statistics}
    with CurrentBuffer do begin
      StatCount[MNR_CLS$B_TYPE] := StatCount[MNR_CLS$B_TYPE] + 1;
      StatLength[MNR_CLS$B_TYPE] := StatLength[MNR_CLS$B_TYPE] + InputBuffer.Len
      if MNR_CLS$B_TYPE in [ClassMonProcess, ClassMonSCS, ClassMonRMS,
                                   ClassMonDisks, ClassMonModes] then
        StatMultCount[MNR_CLS$B_TYPE] := StatMultCount[MNR_CLS$B_TYPE] + MNR_CMP
      end;
    end; {while}

  {Print statistics}
  for i:=ClassMonProcess to _255 do
    if StatCount[i] <> 0 then
      writeln(i, StatCount[i]:8, StatLength[i]:8, StatMultCOunt[i]:8);
  end; {FilterFile}

FUNCTION lib$find_file_end (context: UNSIGNED) : INTEGER; EXTERNAL;

FUNCTION lib$find_file (
  filespec : [CLASS_S] PACKED ARRAY [$l1..$u1:INTEGER] OF CHAR;
  VAR resultant_filespec : [CLASS_S,VOLATILE] PACKED ARRAY [$l2..$u2:INTEGER] OF
  VAR context : [VOLATILE] UNSIGNED;
  default_filespec : [CLASS_S] PACKED ARRAY [$l4..$u4:INTEGER] OF CHAR := %IMMED
  related_filespec : [CLASS_S] PACKED ARRAY [$l5..$u5:INTEGER] OF CHAR := %IMMED
  VAR status_value : [VOLATILE] UNSIGNED := %IMMED 0;
  flags : UNSIGNED := %IMMED 0) : INTEGER; EXTERNAL;

var
  PatternName: string;               {User pattern for input file name}
  FileName: string;                  {Current input file name}
  Context: unsigned;                 {Context for file finding}
  WildAllowed: unsigned;             {Specifies if wildcars are used in the patt
  RetStatus: integer;                {Function return status}

begin {main}
{Open output files}
open(DisksFile,  'DISKS.RES', new); rewrite(DisksFile);
open(IOsFile,    'IOS.RES', new); rewrite(IOsFile);
open(LocksFile,  'LOCKS.RES', new); rewrite(LocksFile);
open(ModesFile,  'MODES.RES', new); rewrite(ModesFile);
open(PageFile,   'PAGE.RES', new); rewrite(PageFile);
open(ProcessFile,'PROCESS.RES', new); rewrite(ProcessFile);
open(StatesFile, 'STATES.RES', new); rewrite(StatesFile);
open(SystemFile, 'SYSTEM.RES', new); rewrite(SystemFile);

{Get input file pattern}
write('Input file name (NODENAME_*.*: '); readln(PatternName);
Context := 0;
WildAllowed := 0;
RetStatus := LIB$FIND_FILE(PatternName, %DESCR FileName, Context,,,, WildAllowed
if RetStatus = LIB$_NOWILD then begin
  WildAllowed := 1;
  Context := 0;
  RetStatus := LIB$FIND_FILE(PatternName, %DESCR FileName, Context,,,, WildAllow
end; {if}

{Loop for every file matching file name pattern}
while (RetStatus <> RMS$_NMF) and (RetStatus <> RMS$_FNF) do begin
  FilterFile(FileName);
  RetStatus := LIB$FIND_FILE(PatternName, %DESCR FileName, Context,,,, WildAllow
  end;

RetStatus := LIB$FIND_FILE_END(Context := Context);
if not odd(RetStatus) then lib$signal(RetStatus);

end.
---------------------------
You could send any comment or suggestion to:

Carles Blas
System Analyst
Centre de Processament de Dades
Universitat Autonoma de Barcelona
Internet: g_carles@cc.uab.es
